Co-authored-by: Jorge Chavez-Saab <jorgechavezsaab@gmail.com> Co-authored-by: Maria Corte-Real Santos <36373796+mariascrs@users.noreply.github.com> Co-authored-by: Luca De Feo <github@defeo.lu> Co-authored-by: Jonathan Komada Eriksen <jonathan.eriksen97@gmail.com> Co-authored-by: Basil Hess <bhe@zurich.ibm.com> Co-authored-by: Antonin Leroux <18654258+tonioecto@users.noreply.github.com> Co-authored-by: Patrick Longa <plonga@microsoft.com> Co-authored-by: Lorenz Panny <lorenz@yx7.cc> Co-authored-by: Francisco Rodríguez-Henríquez <francisco.rodriguez@tii.ae> Co-authored-by: Sina Schaeffler <108983332+syndrakon@users.noreply.github.com> Co-authored-by: Benjamin Wesolowski <19474926+Calodeon@users.noreply.github.com>
204 lines
6.2 KiB
Python
Executable File
204 lines
6.2 KiB
Python
Executable File
#!/usr/bin/env sage
|
|
proof.all(False) # faster
|
|
|
|
from sage.misc.banner import require_version
|
|
if not require_version(10, 0, print_message=True):
|
|
exit('')
|
|
|
|
################################################################
|
|
|
|
from parameters import p, B, f, Tpls, Tmin, Dcom, Dchall
|
|
T = Tpls * Tmin
|
|
|
|
################################################################
|
|
|
|
if p % 4 != 3:
|
|
raise NotImplementedError('requires p ≡ 3 (mod 4)')
|
|
|
|
Fp2.<i> = GF((p,2), modulus=[1,0,1])
|
|
Fp4 = Fp2.extension(2,'u')
|
|
E = EllipticCurve(Fp4, [1,0])
|
|
assert E.j_invariant() == 1728
|
|
assert E.is_supersingular()
|
|
assert E.change_ring(Fp2).frobenius() == -p
|
|
assert E.order() == (p^2-1)^2
|
|
|
|
endo_1 = E.scalar_multiplication(1)
|
|
endo_i = E.automorphisms()[-1]
|
|
endo_j = E.frobenius_isogeny()
|
|
endo_k = endo_i * endo_j
|
|
|
|
if 0: # skipped for speed, for now
|
|
assert endo_i^2 == E.scalar_multiplication(-1)
|
|
assert endo_j^2 == E.scalar_multiplication(-p)
|
|
assert endo_j * endo_i == - endo_i * endo_j
|
|
else:
|
|
R = E.random_point()
|
|
assert (endo_i^2)(R) == -1*R
|
|
assert (endo_j^2)(R) == -p*R
|
|
assert (endo_j*endo_i)(R) == -(endo_i*endo_j)(R)
|
|
|
|
def half_endo(summands):
|
|
def _eval(P):
|
|
E = P.curve()
|
|
assert P in E
|
|
F = E.base_field()
|
|
if (halves := P.division_points(2)):
|
|
Q = halves[0]
|
|
else:
|
|
Q = E.change_ring(F.extension(2,'v'))(P)
|
|
R = sum(endo._eval(Q) for endo in summands)
|
|
return E(R)
|
|
return _eval
|
|
|
|
gen1 = endo_1._eval
|
|
gen2 = endo_i._eval
|
|
gen3 = half_endo([endo_i, endo_j])
|
|
gen4 = half_endo([endo_1, endo_k])
|
|
|
|
################################################################
|
|
|
|
from sage.groups.generic import order_from_multiple
|
|
|
|
x = Fp4.gen()
|
|
while True:
|
|
x += 1
|
|
try:
|
|
P = E.lift_x(x)
|
|
except ValueError:
|
|
continue
|
|
o = order_from_multiple(P, p^2-1)
|
|
if (T<<f).divides(o):
|
|
P *= o // (T<<f)
|
|
P.set_order(T<<f)
|
|
break
|
|
|
|
x = Fp4.gen()
|
|
while True:
|
|
x += 1
|
|
try:
|
|
Q = E.lift_x(x)
|
|
except ValueError:
|
|
continue
|
|
o = order_from_multiple(Q, p^2-1)
|
|
if not (T<<f).divides(o):
|
|
continue
|
|
Q *= o // (T<<f)
|
|
Q.set_order(T<<f)
|
|
if order_from_multiple(P.weil_pairing(Q, T<<f), T<<f, operation='*') == T<<f:
|
|
break
|
|
|
|
def dlp(P, Q, R):
|
|
n = P.order()
|
|
assert P.order() == Q.order()
|
|
assert R.order().divides(P.order())
|
|
e = Fp2(P.weil_pairing(Q, n))
|
|
a = Fp2(R.weil_pairing(Q, n)).log(e)
|
|
b = Fp2(P.weil_pairing(R, n)).log(e)
|
|
assert a*P + b*Q == R
|
|
return a, b
|
|
|
|
def matrix_of_isogeny(phi):
|
|
imP, imQ = map(phi, (P,Q))
|
|
vecP = dlp(P, Q, imP)
|
|
vecQ = dlp(P, Q, imQ)
|
|
mat = matrix(Zmod(T<<f), [vecP, vecQ]).transpose()
|
|
assert imP == ZZ(mat[0][0])*P + ZZ(mat[1][0])*Q
|
|
assert imQ == ZZ(mat[0][1])*P + ZZ(mat[1][1])*Q
|
|
return mat
|
|
|
|
#mat1 = matrix_of_isogeny(endo_1)
|
|
mati = matrix_of_isogeny(endo_i)
|
|
matj = matrix_of_isogeny(endo_j)
|
|
matk = matrix_of_isogeny(endo_k)
|
|
#assert mat1 == 1 # identity; omit
|
|
|
|
#mat1 = matrix_of_isogeny(gen1)
|
|
mat2 = matrix_of_isogeny(gen2)
|
|
mat3 = matrix_of_isogeny(gen3)
|
|
mat4 = matrix_of_isogeny(gen4)
|
|
#assert mat1 == 1 # identity; omit
|
|
|
|
################################################################
|
|
|
|
Quat.<i,j,k> = QuaternionAlgebra(-1, -p)
|
|
O0 = Quat.quaternion_order([1, i, (i+j)/2, (1+k)/2])
|
|
|
|
assert Dcom % 2 == 1 # odd
|
|
mat = block_matrix(Zmod(Dcom), [[identity_matrix(2), mati, matj, matk]])[:,::2]
|
|
ker = list(map(Quat, mat.right_kernel_matrix()))
|
|
idealP = sum((O0*g for g in ker), O0*Dcom)
|
|
assert idealP.norm() == Dcom
|
|
for b in idealP.basis():
|
|
assert sum(Mod(c,Dcom)*g for c,g in zip(b,(1,mati,matj,matk)))[:,0] == 0 # kills P
|
|
for v in (ZZ^4):
|
|
idealPgen = sum(c*g for c,g in zip(v, idealP.basis()))
|
|
if vector(list(idealPgen)).denominator() == 2:
|
|
idealPgen *= 2
|
|
if gcd(idealPgen.reduced_norm(), Dcom^2) == Dcom:
|
|
break
|
|
assert idealP == O0*Dcom + O0*idealPgen
|
|
|
|
mat = mat # still
|
|
rhs = vector(Zmod(Dcom), [0,1])
|
|
cs = mat.solve_right(rhs)
|
|
distorter = Quat(cs)
|
|
assert sum(Mod(c,Dcom)*g for c,g in zip(distorter,(1,mati,matj,matk))).columns()[0] == vector((0,1)) # maps P->Q
|
|
|
|
################################################################
|
|
|
|
from cformat import Ibz, Object, ObjectFormatter
|
|
|
|
def field2limbs(el):
|
|
l = 1 + floor(log(p, 2**64))
|
|
el = Fp2(el)
|
|
vs = [[(int(c) >> 64*i) % 2**64 for i in range(l)] for c in el]
|
|
return vs
|
|
|
|
def fmt_basis(name, P, Q):
|
|
vs = [
|
|
[field2limbs(T[0]), field2limbs(T[2])]
|
|
for T in (P,Q,P-Q)
|
|
]
|
|
return Object('ec_basis_t', name, vs)
|
|
|
|
bases = {
|
|
'EVEN': 1<<f,
|
|
'ODD_PLUS': Tpls,
|
|
'ODD_MINUS': Tmin,
|
|
'COMMITMENT_PLUS': gcd(Tpls, Dcom),
|
|
'COMMITMENT_MINUS': gcd(Tmin, Dcom),
|
|
'CHALLENGE': Dchall,
|
|
}
|
|
|
|
assert P.order() == Q.order()
|
|
|
|
objs = ObjectFormatter([
|
|
fmt_basis(f'BASIS_{k}', ZZ(P.order()/v)*P, ZZ(Q.order()/v)*Q)
|
|
for k,v in bases.items()
|
|
] + [
|
|
Object('ec_curve_t', 'CURVE_E0', [[[int(0)]], [[int(1)]]]),
|
|
Object('ec_point_t', 'CURVE_E0_A24', [[[int(0)]], [[int(1)]]]),
|
|
Object('ibz_mat_2x2_t', 'ACTION_I', [[Ibz(v) for v in vs] for vs in mati]),
|
|
Object('ibz_mat_2x2_t', 'ACTION_J', [[Ibz(v) for v in vs] for vs in matj]),
|
|
Object('ibz_mat_2x2_t', 'ACTION_K', [[Ibz(v) for v in vs] for vs in matk]),
|
|
Object('ibz_mat_2x2_t', 'ACTION_GEN2', [[Ibz(v) for v in vs] for vs in mat2]),
|
|
Object('ibz_mat_2x2_t', 'ACTION_GEN3', [[Ibz(v) for v in vs] for vs in mat3]),
|
|
Object('ibz_mat_2x2_t', 'ACTION_GEN4', [[Ibz(v) for v in vs] for vs in mat4]),
|
|
Object('quat_alg_elem_t', 'COMMITMENT_IDEAL_UNDISTORTED_GEN', [Ibz(1), [Ibz(ZZ(v)) for v in idealPgen]]),
|
|
Object('quat_alg_elem_t', 'COMMITMENT_IDEAL_DISTORTION_ENDO', [Ibz(1), [Ibz(ZZ(v)) for v in distorter]]),
|
|
])
|
|
|
|
with open('include/endomorphism_action.h','w') as hfile:
|
|
with open('endomorphism_action.c','w') as cfile:
|
|
print(f'#include <intbig.h>', file=hfile)
|
|
print(f'#include <ec.h>', file=hfile)
|
|
print(f'#include <quaternion.h>', file=hfile)
|
|
print(f'#include <stddef.h>', file=cfile)
|
|
print(f'#include <stdint.h>', file=cfile)
|
|
print(f'#include <endomorphism_action.h>', file=cfile)
|
|
|
|
objs.header(file=hfile)
|
|
objs.implementation(file=cfile)
|
|
|