1
1
# The following Sage script check the consistency of the following curves parameters:
2
2
#
3
- # 1) P=(GENERATOR_X,GENERATOR_Y) must belongs to the curve of equation E: y^2 = x^3 + Ax + B
3
+ # 1) P=(GENERATOR_X,GENERATOR_Y) must belongs to the curve of equation E: y^2 = x^3 + Ax + B
4
4
# 2) P must have order equal to the MODULUS of the scalar field
5
5
# 3) COFACTOR must be equal to Order(E)/Order(P)
6
6
# 4) COFACTOR_INV must be the inverse of COFACTOR in the scalar Field
7
+ # 5) ENDO_COEFF must be a cube root in the base field.
8
+ # 6) ENDO_SCALAR must be a cube root in the scalar field and satisfy ENDO_SCALAR * (X, Y) == (ENDO_COEFF * X, Y)
9
+ # 7) The intersection of the plane lattice spanned by {(1, ENDO_SCALAR), (0, SCALAR_FIELD_MODULUS)} with the square [-A,A]^2 must be empty,
10
+ # where A = 2^(LAMBDA/2 + 1) + 2^(LAMBDA/2) + 1.
7
11
# Open Sage Shell in the corresponding folder and run the command
8
12
# "sage check_curve_paramaters sage [file_path_curve] [file_path_basefield] [file_path_scalarfield]".
9
13
@@ -65,10 +69,10 @@ scalar_field_name = re.findall(pattern, readfile)[0]
65
69
fn = "(?:" + base_field_name + "|" + scalar_field_name + ")" #fn = field name = "(:?Fr|Fq)". Useful declaration for the pattern
66
70
67
71
#### Reading the big integers list and extracting names and values
68
- pattern = "const\s+(\w+):\s*" + fn + "\s *=\s*field_new!\(\s*" + fn + "\s*,\s*BigInteger\d*\s *\(\s*\[" + "([0-9a-fA-Fxu\s,]+)\s*" + "\]\s*\)"
72
+ pattern = "const\s+(\w+)[:\w\s] *=\s*field_new!\([\s\w,] *\(\s*\[" + "([0-9a-fA-Fxu\s,]+)\s*" + "\]\s*\)"
69
73
big_int_ls = re .findall (pattern ,readfile ) #####list of couples of the form ('[VARIABLE_NAME]',"[u64],..,[u64]")
70
74
71
- big_int_names = [b [0 ] for b in big_int_ls ]
75
+ big_int_names = [b [0 ] for b in big_int_ls ]
72
76
big_int_values = [BigInteger_to_number (b [1 ]) for b in big_int_ls ]
73
77
74
78
BigIntegerLen = BigInteger_len (big_int_ls [0 ][1 ])
@@ -87,6 +91,10 @@ for s in big_int_names:
87
91
pattern = "const\s+COFACTOR:\s*&'static\s*\[u64\]\s*=\s*&\[([0-9a-fA-Fxu\s,]+)\]\s*;"
88
92
COFACTOR = BigInteger_to_number (re .findall (pattern ,readfile )[0 ])
89
93
94
+ ####Reading the value of LAMBDA
95
+ pattern = "const\s+LAMBDA[:\w\s]*=\s*([\d]+)\s*;"
96
+ LAMBDA = int (re .findall (pattern ,readfile )[0 ])
97
+
90
98
#######################################Reading the values from the file containing the Base Field parameters########################
91
99
filename = sys .argv [2 ]
92
100
@@ -163,4 +171,60 @@ else:
163
171
if Fr (COFACTOR ) * Fr (COFACTOR_INV ) == Fr (SCALAR_FIELD_R ):
164
172
print ("Correct. COFACTOR_INV is the inverse of COFACTOR in the the scalar field." )
165
173
else :
166
- print ("WARNING! COFACTOR_INV IS NOT THE INVERSE OF COFACTOR IN THE SCALAR FIELD!" )
174
+ print ("WARNING! COFACTOR_INV IS NOT THE INVERSE OF COFACTOR IN THE SCALAR FIELD!" )
175
+ ####### Checking the correctness of ENDO_COEFF and ENDO_FACTOR ############
176
+ endo_mul_is_used = False
177
+ if 'ENDO_COEFF' in locals () and 'ENDO_SCALAR' in locals ():
178
+ zeta_q = Fq (ENDO_COEFF ) * Fq (BASE_FIELD_R )** (- 1 )
179
+ if zeta_q ** 2 + zeta_q == Fq (- 1 ):
180
+ endo_mul_is_used = True
181
+ print ("Correct. ENDO_COEFF is a primitive cube root of unity." )
182
+ else :
183
+ print ("WARNING! ENDO_COEFF IS NOT A PRIMITIVE CUBE ROOT OF UNITY." )
184
+ zeta_r = Fr (ENDO_SCALAR ) * Fr (SCALAR_FIELD_R )** (- 1 )
185
+ if zeta_r ** 2 + zeta_r == Fr (- 1 ):
186
+ print ("Correct. ENDO_SCALAR is a primitive cube root of unity." )
187
+ else :
188
+ print ("WARNING! ENDO_SCALAR IS NOT A PRIMITIVE CUBE ROOT OF UNITY." )
189
+
190
+
191
+ ####### Checking the consistency of ENDO_COEFF and ENDO_SCALAR #############
192
+ if endo_mul_is_used :
193
+ Q = int (zeta_r ) * P
194
+ if Q == E ([zeta_q * X , Y ]):
195
+ print ("Correct. ENDO_COEFF and ENDO_SCALAR are consistent." )
196
+ else :
197
+ print ("WARNING! ENDO_COEFF AND ENDO_SCALAR ARE NOT CONSISTENT!" )
198
+
199
+
200
+ ########## Checking that shortest vector in the lattice ([1,zeta_r),[0,r]) is long enough #########
201
+ ## The Halo paper (https://eprint.iacr.org/2019/1021.pdf) proves the injectivity of the endo_mul map.
202
+ ## The injectivity of the map (a,b) |-> a\zeta + b for a,b in [0,A] (essential for using add_unsafe)
203
+ ## is equivalent the lattice condition below.
204
+ ## a*zeta + b = a'*zeta_r + b' mod r for a,a',b,b' in [0,A]
205
+ ## is equivalent to the fact that there are non-zero solutions to
206
+ ## a * zeta_r = b mod r for a,b in [-A,A].
207
+ ## Then it would exists c such that
208
+ ## b = a * zeta_r + c * r.
209
+ ## Any such solution correspond to a point of the lattice spanned by (1, zeta_r) and (0, r).
210
+ ## (a, b) = (a, c) * (1 zeta_r)
211
+ ## (0 r )
212
+ ## The injectivity is equivalent to the fact that the intersection between this lattice and [-A, A]^2
213
+ ## is trivial. To verify this we first compute a LLL reduced basis {v,w} and
214
+ ## then check if at least one of v, w, v + w, v - w is belongs to such a square.
215
+ ## If not, there can't be other lattice points in the square.
216
+ if endo_mul_is_used :
217
+ A = 2 ** (LAMBDA // 2 + 1 ) + 2 ** (LAMBDA // 2 ) + 1
218
+ L = Matrix ([[1 ,Integer (zeta_r )],[0 ,SCALAR_FIELD_MODULUS ]])
219
+ Lred = L .LLL ()
220
+ set = [Lred .row (0 ), Lred .row (1 ), Lred .row (0 ) - Lred .row (1 ), Lred .row (0 ) + Lred .row (1 )]
221
+ add_unsafe = True
222
+ for v in set :
223
+ if abs (v [0 ]) <= A and abs (v [1 ]) <= A :
224
+ add_unsafe = False
225
+ if add_unsafe :
226
+ print ("We can use add_unsafe for endo_mul." )
227
+ else :
228
+ print ("WARNING! WE CAN'T USE add_unsafe FOR endo_mul!" )
229
+ else :
230
+ print ("endo_mul is not used for this curve." )
0 commit comments