initial version of SQIsign

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>
This commit is contained in:
SQIsign team
2023-06-01 00:00:00 +00:00
committed by Lorenz Panny
commit 28ff420dd0
285 changed files with 70301 additions and 0 deletions

View File

@@ -0,0 +1,203 @@
#!/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)