File: optimized_curve.py

package info (click to toggle)
python-py-ecc 8.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 796 kB
  • sloc: python: 4,896; makefile: 237
file content (186 lines) | stat: -rw-r--r-- 5,620 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
from py_ecc.fields import (
    optimized_bls12_381_FQ as FQ,
    optimized_bls12_381_FQ2 as FQ2,
    optimized_bls12_381_FQ12 as FQ12,
    optimized_bls12_381_FQP as FQP,
)
from py_ecc.fields.field_properties import (
    field_properties,
)
from py_ecc.typing import (
    Optimized_Field,
    Optimized_Point2D,
    Optimized_Point3D,
)

field_modulus = field_properties["bls12_381"]["field_modulus"]
curve_order = (
    52435875175126190479447740508185965837690552500527637822603658699938581184513
)

# Curve order should be prime
if not pow(2, curve_order, curve_order) == 2:
    raise ValueError("Curve order is not prime")
# Curve order should be a factor of field_modulus**12 - 1
if not (field_modulus**12 - 1) % curve_order == 0:
    raise ValueError("Curve order is not a factor of field_modulus**12 - 1")

# Curve is y**2 = x**3 + 4
b = FQ(4)
# Twisted curve over FQ**2
b2 = FQ2((4, 4))
# Extension curve over FQ**12; same b value as over FQ
b12 = FQ12((4,) + (0,) * 11)

# Generator for curve over FQ
G1 = (
    FQ(
        3685416753713387016781088315183077757961620795782546409894578378688607592378376318836054947676345821548104185464507  # noqa: E501
    ),
    FQ(
        1339506544944476473020471379941921221584933875938349620426543736416511423956333506472724655353366534992391756441569  # noqa: E501
    ),
    FQ(1),
)
# Generator for twisted curve over FQ2
G2 = (
    FQ2(
        (
            352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160,  # noqa: E501
            3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758,  # noqa: E501
        )
    ),
    FQ2(
        (
            1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905,  # noqa: E501
            927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582,  # noqa: E501
        )
    ),
    FQ2.one(),
)
# Point at infinity over FQ
Z1 = (FQ.one(), FQ.one(), FQ.zero())
# Point at infinity for twisted curve over FQ2
Z2 = (FQ2.one(), FQ2.one(), FQ2.zero())


# Check if a point is the point at infinity
def is_inf(pt: Optimized_Point3D[Optimized_Field]) -> bool:
    return pt[-1] == pt[-1].__class__.zero()


# Check that a point is on the curve defined by y**2 == x**3 + b
def is_on_curve(pt: Optimized_Point3D[Optimized_Field], b: Optimized_Field) -> bool:
    if is_inf(pt):
        return True
    x, y, z = pt
    return y**2 * z - x**3 == b * z**3


if not is_on_curve(G1, b):
    raise ValueError("Generator is not on curve")
if not is_on_curve(G2, b2):
    raise ValueError("Generator is not on twisted curve")


# Elliptic curve doubling
def double(
    pt: Optimized_Point3D[Optimized_Field],
) -> Optimized_Point3D[Optimized_Field]:
    x, y, z = pt
    W = 3 * x * x
    S = y * z
    B = x * y * S
    H = W * W - 8 * B
    S_squared = S * S
    newx = 2 * H * S
    newy = W * (4 * B - H) - 8 * y * y * S_squared
    newz = 8 * S * S_squared
    return (newx, newy, newz)


# Elliptic curve addition
def add(
    p1: Optimized_Point3D[Optimized_Field], p2: Optimized_Point3D[Optimized_Field]
) -> Optimized_Point3D[Optimized_Field]:
    one, zero = p1[0].one(), p1[0].zero()
    if p1[2] == zero or p2[2] == zero:
        return p1 if p2[2] == zero else p2
    x1, y1, z1 = p1
    x2, y2, z2 = p2
    U1 = y2 * z1
    U2 = y1 * z2
    V1 = x2 * z1
    V2 = x1 * z2
    if V1 == V2 and U1 == U2:
        return double(p1)
    elif V1 == V2:
        return (one, one, zero)
    U = U1 - U2
    V = V1 - V2
    V_squared = V * V
    V_squared_times_V2 = V_squared * V2
    V_cubed = V * V_squared
    W = z1 * z2
    A = U * U * W - V_cubed - 2 * V_squared_times_V2
    newx = V * A
    newy = U * (V_squared_times_V2 - A) - V_cubed * U2
    newz = V_cubed * W
    return (newx, newy, newz)


# Elliptic curve point multiplication
def multiply(
    pt: Optimized_Point3D[Optimized_Field], n: int
) -> Optimized_Point3D[Optimized_Field]:
    if n == 0:
        return (pt[0].one(), pt[0].one(), pt[0].zero())
    elif n == 1:
        return pt
    elif not n % 2:
        return multiply(double(pt), n // 2)
    else:
        return add(multiply(double(pt), int(n // 2)), pt)


def eq(
    p1: Optimized_Point3D[Optimized_Field], p2: Optimized_Point3D[Optimized_Field]
) -> bool:
    x1, y1, z1 = p1
    x2, y2, z2 = p2
    return x1 * z2 == x2 * z1 and y1 * z2 == y2 * z1


def normalize(
    pt: Optimized_Point3D[Optimized_Field],
) -> Optimized_Point2D[Optimized_Field]:
    x, y, z = pt
    return (x / z, y / z)


# "Twist" a point in E(FQ2) into a point in E(FQ12)
w = FQ12([0, 1] + [0] * 10)


# Convert P => -P
def neg(pt: Optimized_Point3D[Optimized_Field]) -> Optimized_Point3D[Optimized_Field]:
    x, y, z = pt
    return (x, -y, z)


def twist(pt: Optimized_Point3D[FQP]) -> Optimized_Point3D[FQ12]:
    _x, _y, _z = pt
    # Field isomorphism from Z[p] / x**2 to Z[p] / x**2 - 2*x + 2
    xcoeffs = [_x.coeffs[0] - _x.coeffs[1], _x.coeffs[1]]
    ycoeffs = [_y.coeffs[0] - _y.coeffs[1], _y.coeffs[1]]
    zcoeffs = [_z.coeffs[0] - _z.coeffs[1], _z.coeffs[1]]
    nx = FQ12([0] + [xcoeffs[0]] + [0] * 5 + [xcoeffs[1]] + [0] * 4)
    ny = FQ12([ycoeffs[0]] + [0] * 5 + [ycoeffs[1]] + [0] * 5)
    nz = FQ12([0] * 3 + [zcoeffs[0]] + [0] * 5 + [zcoeffs[1]] + [0] * 2)
    return (nx, ny, nz)


# Check that the twist creates a point that is on the curve
G12 = twist(G2)
if not is_on_curve(G12, b12):
    raise ValueError("Twist creates a point not on curve")