Let us walk on the 3-isogeny graph
Loading...
Searching...
No Matches
setup.py
Go to the documentation of this file.
1import sys
2import argparse
3
4# SageMath imports
5from sage.all import (
6 log,
7 ZZ,
8 GF,
9 PolynomialRing,
10 previous_prime,
11)
12
13
14
15def arguments(args=sys.argv[1:]):
16 parser = argparse.ArgumentParser(description="Parses command.")
17 parser.add_argument('-b', '--bits', type=int, help='Bitlength of the field characteristic', required=True)
18 parser.add_argument('-v', '--verbose', action='store_true', help='verbose help')
19
20 if len(sys.argv) == 1:
21 parser.print_help(sys.stderr)
22 sys.exit(1)
23
24 options = parser.parse_args(args)
25 return options
26
27
28
29def ProgressBar(index, total, label):
30 n_bar = 50 # Progress bar width
31 progress = index / total
32 sys.stdout.write('\r')
33 sys.stdout.write(f"[{'=' * int(n_bar * progress):{n_bar}s}] {int(100 * progress)}% {label}")
34 sys.stdout.flush()
35
36
37
38def l2r(a, exponent):
39 # Left-to-right algorithm: Exponentiation over finite fields
40 temporal = 1 * exponent
41 power = a * 1
42 result = 1
43 while temporal > 0:
44 if (temporal % 2) == 1:
45 result = result * power;
46 power = power**2
47 # Dividing m by 2 in every iteration
48 temporal = temporal // 2
49 return result
50
51
52
54 p = a.parent().characteristic()
55 q = a.parent().cardinality()
56 m = int(log(q, p))
57 b = 1 * a
58 c = 1
59 for index in range(0, m, 1):
60 c *= b
61 b = l2r(b, p)
62 return not (l2r(c, (p - 1) // 2) - 1)
63
64
65
66def sqrt_fp(a, check=True):
67 # Square root over Fp
68 p = a.parent().characteristic()
69 assert(p % 4 == 3)
70 if check:
71 if not is_quadratic_residue(a):
72 return None
73 return l2r(a, (p + 1) // 4)
74
75
76
77def sqrt_fp2(a, root2_squared, check=True):
78 # Square root over Fq with q = p²: Kong et al. algorithm. We assume p² = 9 mod 16 and p = 3 mod 4
79 p = a.parent().characteristic()
80 q = p**2
81 assert(q % 16 == 9)
82 if check:
83 if not is_quadratic_residue(a):
84 return None
85
86 exponent1 = (q - 9) // 16
87 exponent2 = (q - 9) // 8
88 b = l2r(2 * a, exponent1)
89 c = 2 * a * b**2
90 r = c**2
91
92 s0 = a * b * (c - 1)
93 constant3 = l2r(root2_squared, exponent2)
94 u = b * constant3
95 c = 2 * u**2 * root2_squared**2 * a
96 s1 = u * root2_squared * a * (c - 1)
97 return (ZZ(1 - r) >> 1) * s0 + (ZZ(1 + r) >> 1) * s1
98
99
100
101def setup_fp(bits):
102 p = previous_prime(2**bits)
103 while (p % 4 != 3) or (p**2 % 16 != 9) or( (p**2 - 1) % 9 == 0) or (p % 3 == 1):
104 p = previous_prime(p)
105
106 assert(p % 4 == 3) # p = 3 mod 4
107 assert(p**2 % 16 == 9) # p^2 = 9 mod 16
108 assert((p**2 - 1) % 9) # 9 does NOT divide (p^2 - 1)
109
110 print('\n+++++++ Setup')
111 print(f'p: {hex(p)}')
112 print(f'p % 4 = {p % 4}')
113 print(f'p % 3 = {p % 3}\n')
114 f = {2: '(p + 1)', 1: '(p - 1)'}[p % 3]
115 g = {1: '(p + 1)', 2: '(p - 1)'}[p % 3]
116 print(f'In particular, 3 divides {f} but not {g}\n')
117
118 # Prime Field
119 Fq = GF(p)
120 def sqrt_fq(input, check=True):
121 return sqrt_fp(input, check=check)
122
123 r3 = (2*p - 1) // 3
124 def curt_fq(a):
125 return l2r(a, r3)
126
127 setup = {
128 'Fp': Fq,
129 'sqrt': sqrt_fq,
130 'curt': curt_fq,
131 }
132
133 return setup
134
135
136
137def setup_fq(bits):
138 p = previous_prime(2**bits)
139 while (p % 4 != 3) or (p**2 % 16 != 9) or( (p**2 - 1) % 9 == 0):
140 p = previous_prime(p)
141
142 assert(p % 4 == 3) # p = 3 mod 4
143 assert(p**2 % 16 == 9) # p^2 = 9 mod 16
144 assert((p**2 - 1) % 9) # 9 does NOT divide (p^2 - 1)
145
146 print('\n+++++++ Setup')
147 print(f'p: {hex(p)}')
148 print(f'p % 4 = {p % 4}')
149 print(f'p % 3 = {p % 3}\n')
150 f = {2: '(p + 1)', 1: '(p - 1)'}[p % 3]
151 g = {1: '(p + 1)', 2: '(p - 1)'}[p % 3]
152 print(f'In particular, 3 divides {f} but not {g}\n')
153
154 # Prime Field
155 Fp = GF(p)
156 Rx = PolynomialRing(Fp, name="x")
157 X = Rx.gens()[0]
158
159 # Quadratic Field
160 Fq = Fp.extension(X**2 + 1, 'i')
161 rootq = Fq.gen()
162 assert(rootq**2 + 1 == 0)
163 Rx = PolynomialRing(Fq, name="x")
164
165 # Non quadratic residue
166 rootq2_squared = rootq
167 while is_quadratic_residue(-rootq2_squared):
168 rootq2_squared += 1
169
170 def sqrt_fq(input, check=True):
171 return sqrt_fp2(input, rootq2_squared, check=check)
172
173 # Concerning 3rd roots of unity
174 N3 = (p**2 - 1) // 3
175 r3 = ZZ(3).inverse_mod(N3) # assume three does not divide p - 1, but p + 1 does
176 def curt_fq(a):
177 return l2r(a, r3)
178
179 zeta3 = (-1 + sqrt_fq(Fq(-3))) / Fq(2)
180 assert(zeta3**3 == 1)
181
182 setup = {
183 'Fq': Fq,
184 'Rx':Rx,
185 'ζ₃':zeta3,
186 'sqrt': sqrt_fq,
187 'curt': curt_fq,
188 }
189
190 return setup
assert(var1 eq var2)
l2r(a, exponent)
Definition setup.py:38
sqrt_fp2(a, root2_squared, check=True)
Definition setup.py:77
ProgressBar(index, total, label)
Definition setup.py:29
arguments(args=sys.argv[1:])
Definition setup.py:15
setup_fq(bits)
Definition setup.py:137
setup_fp(bits)
Definition setup.py:101
sqrt_fp(a, check=True)
Definition setup.py:66
is_quadratic_residue(a)
Definition setup.py:53