Try to use hash-to-curve for BN254_Snarks but no low-degree isogeny [skip ci]
This commit is contained in:
parent
65eedd1cf7
commit
062ae56867
|
@ -132,9 +132,9 @@ proc sqrtBench*(T: typedesc, iters: int) =
|
||||||
let x = rng.random_unsafe(T)
|
let x = rng.random_unsafe(T)
|
||||||
|
|
||||||
const algoType = block:
|
const algoType = block:
|
||||||
when T.C.hasP3mod4_primeModulus():
|
when T.C.has_P_3mod4_primeModulus():
|
||||||
"p ≡ 3 (mod 4)"
|
"p ≡ 3 (mod 4)"
|
||||||
elif T.C.hasP5mod8_primeModulus():
|
elif T.C.has_P_5mod8_primeModulus():
|
||||||
"p ≡ 5 (mod 8)"
|
"p ≡ 5 (mod 8)"
|
||||||
else:
|
else:
|
||||||
"Tonelli-Shanks"
|
"Tonelli-Shanks"
|
||||||
|
|
|
@ -84,13 +84,13 @@ func mapToCurve[F; G: static Subgroup](
|
||||||
# Simplified Shallue-van de Woestijne-Ulas method for AB == 0
|
# Simplified Shallue-van de Woestijne-Ulas method for AB == 0
|
||||||
|
|
||||||
# 1. Map to E' isogenous to E
|
# 1. Map to E' isogenous to E
|
||||||
when F is Fp and F.C.hasP3mod4_primeModulus():
|
when F is Fp and F.C.has_P_3mod4_primeModulus():
|
||||||
mapToIsoCurve_sswuG1_opt3mod4(
|
mapToIsoCurve_sswuG1_opt3mod4(
|
||||||
xn, xd,
|
xn, xd,
|
||||||
yn,
|
yn,
|
||||||
u, xd3
|
u, xd3
|
||||||
)
|
)
|
||||||
elif F is Fp2 and F.C.hasP3mod4_primeModulus():
|
elif F is Fp2 and F.C.has_Psquare_9mod16_primePower():
|
||||||
# p ≡ 3 (mod 4) => p² ≡ 9 (mod 16)
|
# p ≡ 3 (mod 4) => p² ≡ 9 (mod 16)
|
||||||
mapToIsoCurve_sswuG2_opt9mod16(
|
mapToIsoCurve_sswuG2_opt9mod16(
|
||||||
xn, xd,
|
xn, xd,
|
||||||
|
@ -131,12 +131,12 @@ func mapToCurve_fusedAdd[F; G: static Subgroup](
|
||||||
# Simplified Shallue-van de Woestijne-Ulas method for AB == 0
|
# Simplified Shallue-van de Woestijne-Ulas method for AB == 0
|
||||||
|
|
||||||
# 1. Map to E' isogenous to E
|
# 1. Map to E' isogenous to E
|
||||||
when F is Fp and F.C.hasP3mod4_primeModulus():
|
when F is Fp and F.C.has_P_3mod4_primeModulus():
|
||||||
# 1. Map to E'1 isogenous to E1
|
# 1. Map to E'1 isogenous to E1
|
||||||
P0.mapToIsoCurve_sswuG1_opt3mod4(u0)
|
P0.mapToIsoCurve_sswuG1_opt3mod4(u0)
|
||||||
P1.mapToIsoCurve_sswuG1_opt3mod4(u1)
|
P1.mapToIsoCurve_sswuG1_opt3mod4(u1)
|
||||||
P0.sum(P0, P1, h2CConst(F.C, G1, Aprime_E1))
|
P0.sum(P0, P1, h2CConst(F.C, G1, Aprime_E1))
|
||||||
elif F is Fp2 and F.C.hasP3mod4_primeModulus():
|
elif F is Fp2 and F.C.has_Psquare_9mod16_primePower():
|
||||||
# p ≡ 3 (mod 4) => p² ≡ 9 (mod 16)
|
# p ≡ 3 (mod 4) => p² ≡ 9 (mod 16)
|
||||||
# 1. Map to E'2 isogenous to E2
|
# 1. Map to E'2 isogenous to E2
|
||||||
P0.mapToIsoCurve_sswuG2_opt9mod16(u0)
|
P0.mapToIsoCurve_sswuG2_opt9mod16(u0)
|
||||||
|
|
|
@ -44,7 +44,7 @@ func invsqrt_p3mod4(r: var Fp, a: Fp) =
|
||||||
# a^((p-1)/2)) * a^-1 ≡ 1/a (mod p)
|
# a^((p-1)/2)) * a^-1 ≡ 1/a (mod p)
|
||||||
# a^((p-3)/2)) ≡ 1/a (mod p)
|
# a^((p-3)/2)) ≡ 1/a (mod p)
|
||||||
# a^((p-3)/4)) ≡ 1/√a (mod p) # Requires p ≡ 3 (mod 4)
|
# a^((p-3)/4)) ≡ 1/√a (mod p) # Requires p ≡ 3 (mod 4)
|
||||||
static: doAssert Fp.C.hasP3mod4_primeModulus()
|
static: doAssert Fp.C.has_P_3mod4_primeModulus()
|
||||||
when FP.C.hasSqrtAddchain():
|
when FP.C.hasSqrtAddchain():
|
||||||
r.invsqrt_addchain(a)
|
r.invsqrt_addchain(a)
|
||||||
else:
|
else:
|
||||||
|
@ -104,7 +104,7 @@ func invsqrt_p5mod8(r: var Fp, a: Fp) =
|
||||||
#
|
#
|
||||||
# Hence we set β = (2a)^((p-1)/4)
|
# Hence we set β = (2a)^((p-1)/4)
|
||||||
# and α = (β/2a)⁽¹⸍²⁾= (2a)^(((p-1)/4 - 1)/2) = (2a)^((p-5)/8)
|
# and α = (β/2a)⁽¹⸍²⁾= (2a)^(((p-1)/4 - 1)/2) = (2a)^((p-5)/8)
|
||||||
static: doAssert Fp.C.hasP5mod8_primeModulus()
|
static: doAssert Fp.C.has_P_5mod8_primeModulus()
|
||||||
var alpha{.noInit.}, beta{.noInit.}: Fp
|
var alpha{.noInit.}, beta{.noInit.}: Fp
|
||||||
|
|
||||||
# α = (2a)^((p-5)/8)
|
# α = (2a)^((p-5)/8)
|
||||||
|
@ -234,9 +234,9 @@ func invsqrt*[C](r: var Fp[C], a: Fp[C]) =
|
||||||
## i.e. both x² == (-x)²
|
## i.e. both x² == (-x)²
|
||||||
## This procedure returns a deterministic result
|
## This procedure returns a deterministic result
|
||||||
## This procedure is constant-time
|
## This procedure is constant-time
|
||||||
when C.hasP3mod4_primeModulus():
|
when C.has_P_3mod4_primeModulus():
|
||||||
r.invsqrt_p3mod4(a)
|
r.invsqrt_p3mod4(a)
|
||||||
elif C.hasP5mod8_primeModulus():
|
elif C.has_P_5mod8_primeModulus():
|
||||||
r.invsqrt_p5mod8(a)
|
r.invsqrt_p5mod8(a)
|
||||||
else:
|
else:
|
||||||
r.invsqrt_tonelli_shanks(a)
|
r.invsqrt_tonelli_shanks(a)
|
||||||
|
@ -334,7 +334,7 @@ func isSquare*(a: Fp): SecretBool =
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# We reuse the optimized addition chains instead of exponentiation by (p-1)/2
|
# We reuse the optimized addition chains instead of exponentiation by (p-1)/2
|
||||||
when Fp.C.hasP3mod4_primeModulus() or Fp.C.hasP5mod8_primeModulus():
|
when Fp.C.has_P_3mod4_primeModulus() or Fp.C.has_P_5mod8_primeModulus():
|
||||||
var sqrt{.noInit.}, invsqrt{.noInit.}: Fp
|
var sqrt{.noInit.}, invsqrt{.noInit.}: Fp
|
||||||
return sqrt_invsqrt_if_square(sqrt, invsqrt, a)
|
return sqrt_invsqrt_if_square(sqrt, invsqrt, a)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -39,14 +39,18 @@ template matchingLimbs2x*(C: Curve): untyped =
|
||||||
const N2 = wordsRequired(getCurveBitwidth(C)) * 2 # TODO upstream, not precomputing N2 breaks semcheck
|
const N2 = wordsRequired(getCurveBitwidth(C)) * 2 # TODO upstream, not precomputing N2 breaks semcheck
|
||||||
array[N2, SecretWord] # TODO upstream, using Limbs[N2] breaks semcheck
|
array[N2, SecretWord] # TODO upstream, using Limbs[N2] breaks semcheck
|
||||||
|
|
||||||
func hasP3mod4_primeModulus*(C: static Curve): static bool =
|
func has_P_3mod4_primeModulus*(C: static Curve): static bool =
|
||||||
## Returns true iff p ≡ 3 (mod 4)
|
## Returns true iff p ≡ 3 (mod 4)
|
||||||
(BaseType(C.Mod.limbs[0]) and 3) == 3
|
(BaseType(C.Mod.limbs[0]) and 3) == 3
|
||||||
|
|
||||||
func hasP5mod8_primeModulus*(C: static Curve): static bool =
|
func has_P_5mod8_primeModulus*(C: static Curve): static bool =
|
||||||
## Returns true iff p ≡ 5 (mod 8)
|
## Returns true iff p ≡ 5 (mod 8)
|
||||||
(BaseType(C.Mod.limbs[0]) and 7) == 5
|
(BaseType(C.Mod.limbs[0]) and 7) == 5
|
||||||
|
|
||||||
func hasP9mod16_primeModulus*(C: static Curve): static bool =
|
func has_P_9mod16_primeModulus*(C: static Curve): static bool =
|
||||||
## Returns true iff p ≡ 9 (mod 16)
|
## Returns true iff p ≡ 9 (mod 16)
|
||||||
(BaseType(C.Mod.limbs[0]) and 15) == 9
|
(BaseType(C.Mod.limbs[0]) and 15) == 9
|
||||||
|
|
||||||
|
func has_Psquare_9mod16_primePower*(C: static Curve): static bool =
|
||||||
|
## Returns true iff p² ≡ 9 (mod 16)
|
||||||
|
((BaseType(C.Mod.limbs[0]) * BaseType(C.Mod.limbs[0])) and 15) == 9
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import inspect, textwrap
|
import inspect, textwrap
|
||||||
|
import sage.schemes.elliptic_curves.isogeny_small_degree as isd
|
||||||
|
|
||||||
# Working directory
|
# Working directory
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
@ -86,9 +87,24 @@ def dump_poly(name, poly, field, curve):
|
||||||
result += ']'
|
result += ']'
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Unused
|
# Isogenies
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
|
|
||||||
|
def find_iso(E):
|
||||||
|
"""
|
||||||
|
Find an isogenous curve with j-invariant not in {0, 1728} so that
|
||||||
|
Simplified Shallue-van de Woestijne method is directly applicable
|
||||||
|
(i.e the Elliptic Curve coefficient y² = x³ + A*x + B have AB != 0)
|
||||||
|
"""
|
||||||
|
for p_test in primes(30):
|
||||||
|
isos = [i for i in isd.isogenies_prime_degree(E, p_test)
|
||||||
|
if i.codomain().j_invariant() not in (0, 1728) ]
|
||||||
|
if len(isos) > 0:
|
||||||
|
print(f'Found {len(isos)} isogenous curves of degree {p_test}')
|
||||||
|
return isos[0].dual()
|
||||||
|
print(f'Found no isogenies')
|
||||||
|
return None
|
||||||
|
|
||||||
def find_z_sswu(F, A, B):
|
def find_z_sswu(F, A, B):
|
||||||
"""
|
"""
|
||||||
https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#ref-SAGE
|
https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#ref-SAGE
|
||||||
|
@ -115,6 +131,86 @@ def find_z_sswu(F, A, B):
|
||||||
return Z_cand
|
return Z_cand
|
||||||
ctr += 1
|
ctr += 1
|
||||||
|
|
||||||
|
def search_isogeny(curve_name, curve_config):
|
||||||
|
p = curve_config[curve_name]['field']['modulus']
|
||||||
|
Fp = GF(p)
|
||||||
|
|
||||||
|
# Base constants - E1
|
||||||
|
A = curve_config[curve_name]['curve']['a']
|
||||||
|
B = curve_config[curve_name]['curve']['b']
|
||||||
|
E1 = EllipticCurve(Fp, [A, B])
|
||||||
|
|
||||||
|
# Base constants - E2
|
||||||
|
embedding_degree = curve_config[curve_name]['tower']['embedding_degree']
|
||||||
|
twist_degree = curve_config[curve_name]['tower']['twist_degree']
|
||||||
|
twist = curve_config[curve_name]['tower']['twist']
|
||||||
|
|
||||||
|
G2_field_degree = embedding_degree // twist_degree
|
||||||
|
G2_field = f'Fp{G2_field_degree}' if G2_field_degree > 1 else 'Fp'
|
||||||
|
|
||||||
|
if G2_field_degree == 2:
|
||||||
|
non_residue_fp = curve_config[curve_name]['tower']['QNR_Fp']
|
||||||
|
elif G2_field_degree == 1:
|
||||||
|
if twist_degree == 6:
|
||||||
|
# Only for complete serialization
|
||||||
|
non_residue_fp = curve_config[curve_name]['tower']['SNR_Fp']
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
Fp = GF(p)
|
||||||
|
K.<u> = PolynomialRing(Fp)
|
||||||
|
|
||||||
|
if G2_field == 'Fp2':
|
||||||
|
Fp2.<beta> = Fp.extension(u^2 - non_residue_fp)
|
||||||
|
G2F = Fp2
|
||||||
|
if twist_degree == 6:
|
||||||
|
non_residue_twist = curve_config[curve_name]['tower']['SNR_Fp2']
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
elif G2_field == 'Fp':
|
||||||
|
G2F = Fp
|
||||||
|
if twist_degree == 6:
|
||||||
|
non_residue_twist = curve_config[curve_name]['tower']['SNR_Fp']
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
else:
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
if twist == 'D_Twist':
|
||||||
|
G2B = B/G2F(non_residue_twist)
|
||||||
|
E2 = EllipticCurve(G2F, [0, G2B])
|
||||||
|
elif twist == 'M_Twist':
|
||||||
|
G2B = B*G2F(non_residue_twist)
|
||||||
|
E2 = EllipticCurve(G2F, [0, G2B])
|
||||||
|
else:
|
||||||
|
raise ValueError('E2 must be a D_Twist or M_Twist but found ' + twist)
|
||||||
|
|
||||||
|
|
||||||
|
# Isogenies:
|
||||||
|
iso_G1 = find_iso(E1)
|
||||||
|
a_G1 = iso_G1.domain().a4()
|
||||||
|
b_G1 = iso_G1.domain().a6()
|
||||||
|
|
||||||
|
iso_G2 = find_iso(E2)
|
||||||
|
a_G2 = iso_G2.domain().a4()
|
||||||
|
b_G2 = iso_G2.domain().a6()
|
||||||
|
|
||||||
|
# Z
|
||||||
|
Z_G1 = find_z_sswu(Fp, a_G1, b_G1)
|
||||||
|
Z_G2 = find_z_sswu(Fp2, a_G2, b_G2)
|
||||||
|
|
||||||
|
print(f"{curve_name} G1 - isogeny of degree {iso_G1.degree()} with eq y² = x³ + A'x + B':")
|
||||||
|
print(f" A': 0x{Integer(a_G1).hex()}")
|
||||||
|
print(f" B': 0x{Integer(b_G1).hex()}")
|
||||||
|
print(f" Z: {Z_G1}")
|
||||||
|
|
||||||
|
print(f"{curve_name} G2 - isogeny of degree {iso_G2.degree()} with eq y² = x³ + A'x + B':")
|
||||||
|
print(f" A': {fp2_to_hex(a_G2)}")
|
||||||
|
print(f" B': {fp2_to_hex(b_G2)}")
|
||||||
|
print(f" Z: {fp2_to_hex(Z_G2)}")
|
||||||
|
|
||||||
# BLS12-381 G1
|
# BLS12-381 G1
|
||||||
# ---------------------------------------------------------
|
# ---------------------------------------------------------
|
||||||
# Hardcoding from spec:
|
# Hardcoding from spec:
|
||||||
|
@ -192,8 +288,8 @@ def genBLS12381G1_H2C_isogeny_map(curve_config):
|
||||||
# Hash-to-Curve 11-isogeny map BLS12-381 E'1 constants
|
# Hash-to-Curve 11-isogeny map BLS12-381 E'1 constants
|
||||||
# -----------------------------------------------------------------
|
# -----------------------------------------------------------------
|
||||||
#
|
#
|
||||||
# The polynomials map a point (x', y') on the isogenous curve E'2
|
# The polynomials map a point (x', y') on the isogenous curve E'1
|
||||||
# to (x, y) on E2, represented as (xnum/xden, y' * ynum/yden)
|
# to (x, y) on E1, represented as (xnum/xden, y' * ynum/yden)
|
||||||
|
|
||||||
""")
|
""")
|
||||||
buf += '\n\n'
|
buf += '\n\n'
|
||||||
|
@ -374,7 +470,7 @@ def genBLS12381G2_H2C_isogeny_map(curve_config):
|
||||||
else:
|
else:
|
||||||
Btwist = B / Fp2(SNR_Fp2)
|
Btwist = B / Fp2(SNR_Fp2)
|
||||||
|
|
||||||
E2 = EllipticCurve(Fp2, [A, B * Fp2(SNR_Fp2)])
|
E2 = EllipticCurve(Fp2, [A, Btwist])
|
||||||
|
|
||||||
# Base constants - Isogenous curve E'2, degree 3
|
# Base constants - Isogenous curve E'2, degree 3
|
||||||
Aprime_E2 = Fp2([0, 240])
|
Aprime_E2 = Fp2([0, 240])
|
||||||
|
@ -414,6 +510,10 @@ if __name__ == "__main__":
|
||||||
# Usage
|
# Usage
|
||||||
# BLS12-381
|
# BLS12-381
|
||||||
# sage sage/derive_hash_to_curve.sage BLS12_381 G2
|
# sage sage/derive_hash_to_curve.sage BLS12_381 G2
|
||||||
|
# for Hash-to-Curve
|
||||||
|
# or
|
||||||
|
# sage sage/derive_hash_to_curve.sage BLS12_381 iso
|
||||||
|
# to search for a suitable isogeny
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
@ -422,9 +522,12 @@ if __name__ == "__main__":
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
curve = args.curve[0]
|
curve = args.curve[0]
|
||||||
group = args.curve[1]
|
group_or_iso = args.curve[1]
|
||||||
|
|
||||||
if curve == 'BLS12_381' and group == 'G1':
|
if group_or_iso == 'iso':
|
||||||
|
search_isogeny(curve, Curves)
|
||||||
|
|
||||||
|
elif curve == 'BLS12_381' and group_or_iso == 'G1':
|
||||||
h2c = genBLS12381G1_H2C_constants(Curves)
|
h2c = genBLS12381G1_H2C_constants(Curves)
|
||||||
h2c += '\n\n'
|
h2c += '\n\n'
|
||||||
h2c += genBLS12381G1_H2C_isogeny_map(Curves)
|
h2c += genBLS12381G1_H2C_isogeny_map(Curves)
|
||||||
|
@ -444,7 +547,7 @@ if __name__ == "__main__":
|
||||||
|
|
||||||
print(f'Successfully created {curve.lower()}_hash_to_curve_g1.nim')
|
print(f'Successfully created {curve.lower()}_hash_to_curve_g1.nim')
|
||||||
|
|
||||||
elif curve == 'BLS12_381' and group == 'G2':
|
elif curve == 'BLS12_381' and group_or_iso == 'G2':
|
||||||
h2c = genBLS12381G2_H2C_constants(Curves)
|
h2c = genBLS12381G2_H2C_constants(Curves)
|
||||||
h2c += '\n\n'
|
h2c += '\n\n'
|
||||||
h2c += genBLS12381G2_H2C_isogeny_map(Curves)
|
h2c += genBLS12381G2_H2C_isogeny_map(Curves)
|
||||||
|
@ -465,6 +568,6 @@ if __name__ == "__main__":
|
||||||
print(f'Successfully created {curve.lower()}_hash_to_curve_g2.nim')
|
print(f'Successfully created {curve.lower()}_hash_to_curve_g2.nim')
|
||||||
else:
|
else:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
curve + group +
|
curve + group_or_iso +
|
||||||
' is not configured '
|
' is not configured '
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue