Let us walk on the 3-isogeny graph
Loading...
Searching...
No Matches
hdr_code.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2import argparse
3import sys
4from sage.all import ceil, log, GF, ZZ, PolynomialRing
5
6# sage -python hdr_code.py -a 246 -c 201 -l 128 > ../src/parameters/p254.h
7
8# sage -python hdr_code.py -a 372 -c 437 -l 128 > ../src/parameters/p381.h
9# sage -python hdr_code.py -a 567 -c 139 -l 192 > ../src/parameters/p575.h
10# sage -python hdr_code.py -a 756 -c 257 -l 256 > ../src/parameters/p765.h
11
12# sage -python hdr_code.py -a 390 -c 165 -l 128 > ../src/parameters/p398.h
13# sage -python hdr_code.py -a 582 -c 921 -l 192 > ../src/parameters/p592.h
14# sage -python hdr_code.py -a 774 -c 411 -l 256 > ../src/parameters/p783.h
15
16# sage -python hdr_code.py -a 2 -c 10980266050796090380028661398194450349184449178169757955514086995044995524265 -l 128 > ../src/parameters/p255.h
17# sage -python hdr_code.py -a 2 -c 4265069153285891173087371089085058777333948346280563290592617735285026033366853728148093776366671044752906631128723 -l 192 > ../src/parameters/p383.h
18# sage -python hdr_code.py -a 2 -c 1331684699081905773686966904488651388517342873708180584403111660513502390006644134406723028256595313406156735410987361198165720310405343322235720072016415 -l 256 > ../src/parameters/p511.h
19
20# +++++++++++++++++++++++++++++++
21def arguments(args=sys.argv[1:]):
22 parser = argparse.ArgumentParser(description="Parses command.")
23 parser.add_argument('-a', '--exponent_of_two', type=int, help='exponent of two', required=True)
24 parser.add_argument('-c', '--cofactor', type=int, help='cofactor', required=True)
25 parser.add_argument('-l', '--security_level', type=int, help='security level', required=True)
26
27 if len(sys.argv) == 1:
28 parser.print_help(sys.stderr)
29 sys.exit(1)
30
31 options = parser.parse_args(args)
32 return options
33
34
35# ++++++++++++++++++++++++++++++++++
36def word_extractor(p: int, p_words: int, length: int, var: str):
37 k = 64
38 p_word = []
39 content_str = "static const uint64_t " + var + f"[{length}] = {{\n"
40 pp = p
41 for i in range(1, p_words + 1):
42 if ((i - 1) % 4) == 0:
43 content_str = content_str + "\t"
44 p_word.append(pp % 2 ** k)
45 if (i % 4) != 0 and (i != p_words):
46 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + ", "
47 else:
48 if (i != p_words):
49 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + ",\n"
50 else:
51 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + "\n"
52 pp = pp // (2 ** k)
53
54 content_str = content_str + "};\n"
55 print(f'{content_str}')
56
57
58# ++++++++++++++++++++++++++++++++++
59def word_extractor_twice(p: list, p_words: int, length: int, var: str):
60 k = 64
61 p_word = []
62 content_str = "static const uint64_t " + var + f"[2 * {length}] = {{\n"
63 pp = ZZ(p[0])
64 for i in range(1, p_words + 1):
65 if ((i - 1) % 4) == 0:
66 content_str = content_str + "\t"
67 p_word.append(pp % 2 ** k)
68 if (i % 4) != 0 and (i != p_words):
69 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + ", "
70 else:
71 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + ",\n"
72 pp = pp // (2 ** k)
73 p_word = []
74 pp = ZZ(p[1])
75 for i in range(1, p_words + 1):
76 if ((i - 1) % 4) == 0:
77 content_str = content_str + "\t"
78 p_word.append(pp % 2 ** k)
79 if (i % 4) != 0 and (i != p_words):
80 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + ", "
81 else:
82 if (i != p_words):
83 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + ",\n"
84 else:
85 content_str = content_str + "0x{:X}".format(p_word[i - 1]) + "\n"
86 pp = pp // (2 ** k)
87
88 content_str = content_str + "};\n"
89 print(f'{content_str}')
90
91
92def cube_root(p):
93 pbits = p.bit_length()
94 pwords = (pbits + 63) // 64
95 montgomery_one = 2 ** (64 * pwords) % p
96
97 p_minus_one_halves = (p - 1) // 2
98 p_minus_3_quarters = (p - 3) // 4
99
100 # Fp
101 fp = GF(p)
102 Rx = PolynomialRing(fp, name="x")
103 x = Rx.gens()[0]
104 fp2 = fp.extension(x**2 + 1, 'i')
105 i = fp2.gen()
106 assert(i**2 + 1 == 0)
107
108 def fp2_issquare(a):
109 a1 = a ** p_minus_3_quarters
110 alpha = a1 ** 2
111 alpha = alpha * a
112
113 alpha_conjugated = alpha.conjugate()
114
115 a0 = alpha * alpha_conjugated
116 if a0 == fp2(-1):
117 # a doesn't have sqrt in fp2
118 return False, None
119
120 x0 = a1 * a
121 if alpha == fp2(-1):
122 return True, x0 * i
123
124 else:
125
126 alpha = alpha + 1
127 b = alpha ** p_minus_one_halves
128 b = b * x0
129 return True, b
130
131 N3 = (p**2 - 1) // 3
132 r3 = ZZ(3).inverse_mod(N3) # assume three does not divide p - 1, but p + 1 does
133 assert(r3 * 3 % N3 == 1)
134
135 correct, square_root_of_three = fp2_issquare(fp2(-3))
136 assert(correct)
137 assert(square_root_of_three**2 == -3)
138 zeta3 = (-1 + square_root_of_three) / fp2(2)
139 assert(zeta3**3 == 1)
140 return r3, (zeta3 * montgomery_one).list()
141
142
143def print_parameters(a: int, c: int, l: int):
144 # assert(c % 3 != 0)
145 p = (2**a) * c - 1
146 assert p % 4 == 3
147
148 # // size of p in bits, bytes ,words
149 pbits = p.bit_length()
150 pbytes = (pbits + 7) // 8
151 pwords = (pbits + 63) // 64
152 pmask = pbits % 64
153 if pmask == 0:
154 pmask = hex((1 << 64) - 1);
155 else:
156 pmask = hex((1 << pmask) - 1)
157
158 print(f'// Parameters concerning P{pbits}\n')
159 print(f'#ifndef SSEC_PARAMETERS_P{pbits}_H')
160 print(f'#define SSEC_PARAMETERS_P{pbits}_H\n')
161
162 print(f'#define FIELD_NAME\t\t\t"p{pbits}"')
163 print(f'#define FIELD_BITS\t\t\t{pbits}')
164 print(f'#define FIELD_BYTES\t\t\t{pbytes}')
165 print(f'#define FIELD_64BITS_WORDS\t{pwords}')
166 print(f'#define QFIELD_BYTES\t\t{2 * pbytes}')
167 print(f'#define MASK_FIELD_ELEMENT\t{pmask}')
168 print(f'#define SECURITY_BITS\t\t{l}\n')
169
170 trits = int(ceil((2.0 * l) / log(3.0, 2)))
171 print(f'#define BIT_LENGTH_PATH\t\t{2 * l}')
172 print(f'#define TRITLENGTH_PATH\t\t{trits}\n')
173
174 print("// Field characteristic p")
175 word_extractor(p, pwords, "FIELD_64BITS_WORDS", "FIELD_CHARACTERISTIC")
176
177 montgomery_one = 2 ** (64 * pwords) % p
178 print("// Neutral multiplicative in Montgomery domain: R = 2ᵉ mod p")
179 word_extractor(montgomery_one, pwords, "FIELD_64BITS_WORDS", "MONTGOMERY_CONSTANT_ONE")
180 print("// Montgomery constant R² = (2ᵉ)² mod p where e = 0 mod 64 s.t. 2ᵉ⁻⁶⁴ < p < 2ᵉ")
181 word_extractor((montgomery_one ** 2) % p, pwords, "FIELD_64BITS_WORDS", "MONTGOMERY_CONSTANT_R_SQUARED")
182
183 print("// Exponent constant required for field inversion: p - 2")
184 word_extractor(p - 2, pwords, "FIELD_64BITS_WORDS", "FIELD_INVERSION_EXPONENT")
185
186 print("// Exponent constant required for computing square-roots in GF(p): (p - 1) / 2")
187 word_extractor((p - 1) // 2, pwords, "FIELD_64BITS_WORDS", "SQUARE_ROOT_EXPONENT_12")
188 q = p**2
189
190 print("// Exponent constant required for computing square-roots in GF(p²): (p - 3) / 4")
191 word_extractor((p - 3) // 4, pwords, "FIELD_64BITS_WORDS", "SQUARE_ROOT_EXPONENT_34")
192
193 print("// Exponent constant required for computing square-roots in GF(p²): (p + 1) / 4")
194 word_extractor((p + 1) // 4, pwords, "FIELD_64BITS_WORDS", "SQUARE_ROOT_EXPONENT_14")
195
196 if (p % 3 == 2):
197 print("#define SSEC_CUBE_ROOT_OVER_FP")
198 print("// Exponent constant required for computing square-roots in GF(p): (2p - 1) / 3")
199 word_extractor((2*p - 1) // 3, pwords, "FIELD_64BITS_WORDS", "CUBE_ROOT_EXPONENT_213")
200
201 if (q % 16 == 9):
202 def l2r(a, exponent):
203 # Left-to-right algorithm: Exponentiation over finite fields
204 temporal = 1 * exponent
205 power = a * 1
206 result = 1
207 while temporal > 0:
208 if (temporal % 2) == 1:
209 result = result * power;
210 power = power**2
211 # Dividing m by 2 in every iteration
212 temporal = temporal // 2
213 return result
214
215 def is_quadratic_residue(a):
216 p = a.parent().characteristic()
217 q = a.parent().cardinality()
218 m = int(log(q, p))
219 b = 1 * a
220 c = 1
221 for index in range(0, m, 1):
222 c *= b
223 b = l2r(b, p)
224 return not (l2r(c, (p - 1) // 2) - 1)
225
226 # Prime Field
227 Fp = GF(p)
228 Rx = PolynomialRing(Fp, name="x")
229 X = Rx.gens()[0]
230
231 # Quadratic Field
232 Fq = Fp.extension(X**2 + 1, 'i')
233 rootq = Fq.gen()
234 assert(rootq**2 + 1 == 0)
235 Rx = PolynomialRing(Fq, name="x")
236
237 # Non quadratic residue
238 rootq2_squared = rootq
239 while is_quadratic_residue(-rootq2_squared):
240 rootq2_squared += 1
241
242 exponent1 = (q - 9) // 16
243 exponent2 = (q - 9) // 8
244
245 constant3 = l2r(rootq2_squared, exponent2)
246 print("#define SSEC_KONG_ET_AL_S_ALGORITHM")
247 print("// Constant required in Kong et al.'s algorithm, d: quadratic non-residue")
248 word_extractor_twice((rootq2_squared * montgomery_one).list(), pwords, "FIELD_64BITS_WORDS", "SQUARE_ROOT_CONSTANT_D")
249 print("// Constant required in Kong et al.'s algorithm, t: d raised at the power (p² - 9) / 8")
250 word_extractor_twice((constant3 * montgomery_one).list(), pwords, "FIELD_64BITS_WORDS", "SQUARE_ROOT_CONSTANT_T")
251 print("// Exponent constant required for computing square-roots in GF(p²): (p² - 9) / 16")
252 e1words = (exponent1.bit_length() + 63) // 64
253 print(f'#define SQUARE_ROOT_EXPONENT_BITS\t\t\t{exponent1.bit_length()}')
254 word_extractor(exponent1, e1words, "2 * FIELD_64BITS_WORDS", "SQUARE_ROOT_EXPONENT_916")
255
256
257 n3, zeta3 = cube_root(p)
258 n3words = (n3.bit_length() + 63) // 64
259 print("// Exponent constant required for computing cube-roots")
260 print(f'#define CUBE_ROOT_EXPONENT_BITS\t\t\t{n3.bit_length()}')
261 word_extractor(n3, n3words, "2 * FIELD_64BITS_WORDS", "CUBE_ROOT_EXPONENT")
262 print("// Cube root of unity in Montgomery domain")
263 word_extractor_twice(zeta3, pwords, "FIELD_64BITS_WORDS", "CUBE_ROOT_OF_UNITY")
264
265 montgomery_one = 2 ** (64 * pwords) % p
266 one_half = ZZ(2).inverse_mod(p)
267 word_extractor((one_half * montgomery_one) % p, pwords, "FIELD_64BITS_WORDS", "ONE_HALF")
268 one_third = ZZ(3).inverse_mod(p)
269 word_extractor((one_third * montgomery_one) % p, pwords, "FIELD_64BITS_WORDS", "ONE_THIRD")
270 one_ninth = (one_third**2) % p
271 word_extractor((one_ninth * montgomery_one) % p, pwords, "FIELD_64BITS_WORDS", "ONE_NINTH")
272 one_by_27 = (one_third * one_ninth) % p
273 word_extractor((one_by_27 * montgomery_one) % p, pwords, "FIELD_64BITS_WORDS", "ONE_BY_27")
274
275 print(f'#endif // SSEC_PARAMETERS_P{pbits}_H')
276
277
278def main():
279 a = arguments(sys.argv[1:]).exponent_of_two
280 c = arguments(sys.argv[1:]).cofactor
281 l = arguments(sys.argv[1:]).security_level
282 print_parameters(a, c, l)
283
284
285# ++++++++++++++++++++++++
286if __name__ == "__main__":
287 main()
assert(var1 eq var2)
word_extractor(int p, int p_words, int length, str var)
Definition hdr_code.py:36
word_extractor_twice(list p, int p_words, int length, str var)
Definition hdr_code.py:59
arguments(args=sys.argv[1:])
Definition hdr_code.py:21
cube_root(p)
Definition hdr_code.py:92
print_parameters(int a, int c, int l)
Definition hdr_code.py:143
Definition fp2.h:17