mirror of
https://github.com/codex-storage/constantine.git
synced 2025-02-03 06:24:51 +00:00
BN254 - Hash-to-Curve (SVDW method) (#190)
* Hash to BN254-Snarks * Test SVDW code path with old v7 vectors for BLS12-381 * add benches
This commit is contained in:
parent
062ae56867
commit
e9e7a1809c
@ -12,9 +12,7 @@ import
|
||||
../constantine/math/config/curves,
|
||||
../constantine/math/extension_fields,
|
||||
../constantine/math/io/[io_bigints, io_ec],
|
||||
../constantine/math/elliptic/[
|
||||
ec_shortweierstrass_affine,
|
||||
ec_shortweierstrass_projective],
|
||||
../constantine/math/ec_shortweierstrass,
|
||||
../constantine/hash_to_curve/hash_to_curve,
|
||||
../constantine/hashes,
|
||||
# Helpers
|
||||
@ -39,9 +37,9 @@ proc bench_BLS12_381_hash_to_G1(iters: int) =
|
||||
const dst = "BLS_SIG_BLS12381G1-SHA256-SSWU-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Prj[Fp[BLS12_381], G1]
|
||||
var P: ECP_ShortW_Jac[Fp[BLS12_381], G1]
|
||||
|
||||
bench("Hash to G1 (Draft #11)", BLS12_381, iters):
|
||||
bench("Hash to G1 (SSWU method - Draft #14)", BLS12_381, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
@ -54,9 +52,9 @@ proc bench_BLS12_381_hash_to_G2(iters: int) =
|
||||
const dst = "BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Prj[Fp2[BLS12_381], G2]
|
||||
var P: ECP_ShortW_Jac[Fp2[BLS12_381], G2]
|
||||
|
||||
bench("Hash to G2 (Draft #11)", BLS12_381, iters):
|
||||
bench("Hash to G2 (SSWU method - Draft #14)", BLS12_381, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
@ -65,11 +63,72 @@ proc bench_BLS12_381_hash_to_G2(iters: int) =
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
proc bench_BLS12_381_G1_proj_aff_conversion(iters: int) =
|
||||
proc bench_BLS12_381_hash_to_G1_SVDW(iters: int) =
|
||||
const dst = "BLS_SIG_BLS12381G1-SHA256-SVDW-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Jac[Fp[BLS12_381], G1]
|
||||
|
||||
bench("Hash to G1 (SVDW method)", BLS12_381, iters):
|
||||
sha256.hashToCurve_svdw(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
proc bench_BLS12_381_hash_to_G2_SVDW(iters: int) =
|
||||
const dst = "BLS_SIG_BLS12381G2-SHA256-SVDW-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Jac[Fp2[BLS12_381], G2]
|
||||
|
||||
bench("Hash to G2 (SVDW method)", BLS12_381, iters):
|
||||
sha256.hashToCurve_svdw(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
proc bench_BN254_Snarks_hash_to_G1(iters: int) =
|
||||
const dst = "BLS_SIG_BN254SNARKSG1-SHA256-SVDW-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Jac[Fp[BN254_Snarks], G1]
|
||||
|
||||
bench("Hash to G1 (SVDW method)", BN254_Snarks, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
proc bench_BN254_Snarks_hash_to_G2(iters: int) =
|
||||
const dst = "BLS_SIG_BN254SNARKSG2-SHA256-SVDW-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Jac[Fp2[BN254_Snarks], G2]
|
||||
|
||||
bench("Hash to G2 (SVDW method)", BN254_Snarks, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
|
||||
proc bench_BLS12_381_G1_jac_aff_conversion(iters: int) =
|
||||
const dst = "BLS_SIG_BLS12381G1-SHA256-SSWU-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Prj[Fp[BLS12_381], G1]
|
||||
var P: ECP_ShortW_Jac[Fp[BLS12_381], G1]
|
||||
var Paff: ECP_ShortW_Aff[Fp[BLS12_381], G1]
|
||||
|
||||
sha256.hashToCurve(
|
||||
@ -80,14 +139,14 @@ proc bench_BLS12_381_G1_proj_aff_conversion(iters: int) =
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
bench("G1 Proj->Affine conversion (for pairing)", BLS12_381, iters):
|
||||
bench("G1 Jac->Affine conversion (for pairing)", BLS12_381, iters):
|
||||
Paff.affine(P)
|
||||
|
||||
proc bench_BLS12_381_G2_proj_aff_conversion(iters: int) =
|
||||
proc bench_BLS12_381_G2_jac_aff_conversion(iters: int) =
|
||||
const dst = "BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
|
||||
var P: ECP_ShortW_Prj[Fp2[BLS12_381], G2]
|
||||
var P: ECP_ShortW_Jac[Fp2[BLS12_381], G2]
|
||||
var Paff: ECP_ShortW_Aff[Fp2[BLS12_381], G2]
|
||||
|
||||
sha256.hashToCurve(
|
||||
@ -98,7 +157,7 @@ proc bench_BLS12_381_G2_proj_aff_conversion(iters: int) =
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
bench("G2 Proj->Affine conversion (for pairing)", BLS12_381, iters):
|
||||
bench("G2 Jac->Affine conversion (for pairing)", BLS12_381, iters):
|
||||
Paff.affine(P)
|
||||
|
||||
const Iters = 1000
|
||||
@ -107,8 +166,12 @@ proc main() =
|
||||
separator()
|
||||
bench_BLS12_381_hash_to_G1(Iters)
|
||||
bench_BLS12_381_hash_to_G2(Iters)
|
||||
bench_BLS12_381_G1_proj_aff_conversion(Iters)
|
||||
bench_BLS12_381_G2_proj_aff_conversion(Iters)
|
||||
bench_BLS12_381_hash_to_G1_SVDW(Iters)
|
||||
bench_BLS12_381_hash_to_G2_SVDW(Iters)
|
||||
bench_BN254_Snarks_hash_to_G1(Iters)
|
||||
bench_BN254_Snarks_hash_to_G2(Iters)
|
||||
bench_BLS12_381_G1_jac_aff_conversion(Iters)
|
||||
bench_BLS12_381_G2_jac_aff_conversion(Iters)
|
||||
separator()
|
||||
|
||||
main()
|
||||
|
@ -79,6 +79,7 @@ proc main() =
|
||||
finalExpBLS12Bench(curve, Iters)
|
||||
pairingBLS12Bench(curve, Iters)
|
||||
separator()
|
||||
hashToCurveBLS12381G1Bench(Iters)
|
||||
hashToCurveBLS12381G2Bench(Iters)
|
||||
separator()
|
||||
|
||||
|
@ -78,6 +78,9 @@ proc main() =
|
||||
finalExpBNBench(curve, Iters)
|
||||
pairingBNBench(curve, Iters)
|
||||
separator()
|
||||
hashToCurveBN254SnarksG1Bench(Iters)
|
||||
hashToCurveBN254SnarksG2Bench(Iters)
|
||||
separator()
|
||||
|
||||
main()
|
||||
notes()
|
||||
|
@ -212,15 +212,67 @@ proc pairingBNBench*(C: static Curve, iters: int) =
|
||||
bench("Pairing BN", C, iters):
|
||||
f.pairing_bn(P, Q)
|
||||
|
||||
proc hashToCurveBLS12_381G2Bench*(iters: int) =
|
||||
proc hashToCurveBLS12381G1Bench*(iters: int) =
|
||||
# Hardcode BLS12_381
|
||||
# otherwise concept symbol
|
||||
# 'CryptoHash' resolution issue
|
||||
const dst = "BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_"
|
||||
const dst = "BLS_SIG_BLS12381G1-SHA256-SSWU-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
var P: ECP_ShortW_Prj[Fp2[BLS12_381], G2]
|
||||
var P: ECP_ShortW_Prj[Fp[BLS12_381], G1]
|
||||
|
||||
bench("Hash to G2 (Draft #11)", BLS12_381, iters):
|
||||
bench("Hash to G1 (SSWU - Draft #14)", BLS12_381, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
proc hashToCurveBLS12381G2Bench*(iters: int) =
|
||||
# Hardcode BLS12_381
|
||||
# otherwise concept symbol
|
||||
# 'CryptoHash' resolution issue
|
||||
const dst = "BLS_SIG_BLS12381G2-SHA256-SSWU-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
var P: ECP_ShortW_Prj[Fp2[BLS12_381], G2]
|
||||
|
||||
bench("Hash to G2 (SSWU - Draft #14)", BLS12_381, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
|
||||
proc hashToCurveBN254SnarksG1Bench*(iters: int) =
|
||||
# Hardcode BN254_Snarks
|
||||
# otherwise concept symbol
|
||||
# 'CryptoHash' resolution issue
|
||||
const dst = "BLS_SIG_BN254SNARKSG1-SHA256-SVDW-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
var P: ECP_ShortW_Prj[Fp[BN254_Snarks], G1]
|
||||
|
||||
bench("Hash to G1 (SVDW - Draft #14)", BN254_Snarks, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = dst
|
||||
)
|
||||
|
||||
proc hashToCurveBN254SnarksG2Bench*(iters: int) =
|
||||
# Hardcode BN254_Snarks
|
||||
# otherwise concept symbol
|
||||
# 'CryptoHash' resolution issue
|
||||
const dst = "BLS_SIG_BN254SNARKSG2-SHA256-SVDW-RO_POP_"
|
||||
let msg = "Mr F was here"
|
||||
var P: ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]
|
||||
|
||||
bench("Hash to G2 (SVDW - Draft #14)", BN254_Snarks, iters):
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
|
@ -175,11 +175,6 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
||||
("tests/math/t_pairing_bls12_381_optate.nim", false),
|
||||
("tests/math/t_pairing_bls12_381_multi.nim", false),
|
||||
|
||||
# Hashing to elliptic curves
|
||||
# ----------------------------------------------------------
|
||||
("tests/math/t_hash_to_field.nim", false),
|
||||
("tests/math/t_hash_to_curve.nim", false),
|
||||
|
||||
# Prime order fields
|
||||
# ----------------------------------------------------------
|
||||
("tests/math/t_fr.nim", false),
|
||||
@ -188,6 +183,12 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
||||
# ----------------------------------------------------------
|
||||
("tests/t_hash_sha256_vs_openssl.nim", true), # skip OpenSSL tests on Windows
|
||||
|
||||
# Hashing to elliptic curves
|
||||
# ----------------------------------------------------------
|
||||
("tests/t_hash_to_field.nim", false),
|
||||
("tests/t_hash_to_curve_random.nim", false),
|
||||
("tests/t_hash_to_curve.nim", false),
|
||||
|
||||
# Ciphers
|
||||
# ----------------------------------------------------------
|
||||
("tests/t_cipher_chacha20.nim", false),
|
||||
@ -216,8 +217,9 @@ const skipSanitizers = [
|
||||
"tests/math/t_ec_sage_bn254_snarks.nim",
|
||||
"tests/math/t_ec_sage_bls12_377.nim",
|
||||
"tests/math/t_ec_sage_bls12_381.nim",
|
||||
"tests/math/t_hash_to_field.nim",
|
||||
"tests/math/t_hash_to_curve.nim"
|
||||
"tests/t_hash_to_field.nim",
|
||||
"tests/t_hash_to_curve.nim",
|
||||
"tests/t_hash_to_curve_random.nim"
|
||||
]
|
||||
|
||||
when defined(windows):
|
||||
|
@ -92,10 +92,10 @@ func h2c_isogeny_map[F](
|
||||
|
||||
# xd^e with e in [1, N], for example [xd, xd², xd³]
|
||||
const maxdegree = max([
|
||||
h2cIsomapPoly(F.C, G, xnum).len,
|
||||
h2cIsomapPoly(F.C, G, xden).len,
|
||||
h2cIsomapPoly(F.C, G, ynum).len,
|
||||
h2cIsomapPoly(F.C, G, yden).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, xnum).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, xden).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, ynum).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, yden).len,
|
||||
])
|
||||
var xd_pow{.noInit.}: array[maxdegree, F]
|
||||
xd_pow[0] = xd
|
||||
@ -103,28 +103,28 @@ func h2c_isogeny_map[F](
|
||||
for i in 2 ..< xd_pow.len:
|
||||
xd_pow[i].prod(xd_pow[i-1], xd_pow[0])
|
||||
|
||||
const xnLen = h2cIsomapPoly(F.C, G, xnum).len
|
||||
const ynLen = h2cIsomapPoly(F.C, G, ynum).len
|
||||
const xnLen = h2cIsomapPoly(F.C, sswu, G, xnum).len
|
||||
const ynLen = h2cIsomapPoly(F.C, sswu, G, ynum).len
|
||||
|
||||
rxn.poly_eval_horner_scaled(
|
||||
xn, xd_pow,
|
||||
h2cIsomapPoly(F.C, G, xnum),
|
||||
h2cIsomapPoly(F.C, sswu, G, xnum),
|
||||
xnLen
|
||||
)
|
||||
rxd.poly_eval_horner_scaled(
|
||||
xn, xd_pow,
|
||||
h2cIsomapPoly(F.C, G, xden),
|
||||
h2cIsomapPoly(F.C, sswu, G, xden),
|
||||
xnLen
|
||||
)
|
||||
|
||||
ryn.poly_eval_horner_scaled(
|
||||
xn, xd_pow,
|
||||
h2cIsomapPoly(F.C, G, ynum),
|
||||
h2cIsomapPoly(F.C, sswu, G, ynum),
|
||||
ynLen
|
||||
)
|
||||
ryd.poly_eval_horner_scaled(
|
||||
xn, xd_pow,
|
||||
h2cIsomapPoly(F.C, G, yden),
|
||||
h2cIsomapPoly(F.C, sswu, G, yden),
|
||||
ynLen
|
||||
)
|
||||
|
||||
@ -224,10 +224,10 @@ func h2c_isogeny_map*[F; G: static Subgroup](
|
||||
|
||||
# Z²^e with e in [1, N], for example [Z², Z⁴, Z⁶]
|
||||
const maxdegree = max([
|
||||
h2cIsomapPoly(F.C, G, xnum).len,
|
||||
h2cIsomapPoly(F.C, G, xden).len,
|
||||
h2cIsomapPoly(F.C, G, ynum).len,
|
||||
h2cIsomapPoly(F.C, G, yden).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, xnum).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, xden).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, ynum).len,
|
||||
h2cIsomapPoly(F.C, sswu, G, yden).len,
|
||||
])
|
||||
var ZZpow{.noInit.}: array[maxdegree, F]
|
||||
ZZpow[0].square(P.z)
|
||||
@ -241,28 +241,28 @@ func h2c_isogeny_map*[F; G: static Subgroup](
|
||||
else:
|
||||
ZZpow[i].prod(ZZpow[(i-1) shr 1], ZZpow[((i-1) shr 1) + 1])
|
||||
|
||||
const xnLen = h2cIsomapPoly(F.C, G, xnum).len
|
||||
const ynLen = h2cIsomapPoly(F.C, G, ynum).len
|
||||
const xnLen = h2cIsomapPoly(F.C, sswu, G, xnum).len
|
||||
const ynLen = h2cIsomapPoly(F.C, sswu, G, ynum).len
|
||||
|
||||
xn.poly_eval_horner_scaled(
|
||||
P.x, ZZpow,
|
||||
h2cIsomapPoly(F.C, G, xnum),
|
||||
h2cIsomapPoly(F.C, sswu, G, xnum),
|
||||
xnLen
|
||||
)
|
||||
xd.poly_eval_horner_scaled(
|
||||
P.x, ZZpow,
|
||||
h2cIsomapPoly(F.C, G, xden),
|
||||
h2cIsomapPoly(F.C, sswu, G, xden),
|
||||
xnLen
|
||||
)
|
||||
|
||||
yn.poly_eval_horner_scaled(
|
||||
P.x, ZZpow,
|
||||
h2cIsomapPoly(F.C, G, ynum),
|
||||
h2cIsomapPoly(F.C, sswu, G, ynum),
|
||||
ynLen
|
||||
)
|
||||
yd.poly_eval_horner_scaled(
|
||||
P.x, ZZpow,
|
||||
h2cIsomapPoly(F.C, G, yden),
|
||||
h2cIsomapPoly(F.C, sswu, G, yden),
|
||||
ynLen
|
||||
)
|
||||
|
||||
|
@ -11,7 +11,8 @@ import
|
||||
../platforms/abstractions,
|
||||
../math/config/curves,
|
||||
../math/[arithmetic, extension_fields],
|
||||
../math/curves/zoo_hash_to_curve
|
||||
../math/curves/zoo_hash_to_curve,
|
||||
./h2c_utilities
|
||||
|
||||
# ############################################################
|
||||
#
|
||||
@ -39,43 +40,6 @@ import
|
||||
# Test vector generator
|
||||
# - https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/f7dd3761/poc/sswu_generic.sage
|
||||
|
||||
func sgn0(x: Fp): SecretBool =
|
||||
## Returns a conventional "sign" for a field element.
|
||||
## Even numbers are considered positive by convention
|
||||
## and odd negative.
|
||||
##
|
||||
## https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-4.1
|
||||
#
|
||||
# In Montgomery representation
|
||||
# each number a is represented as aR (mod M)
|
||||
# with R a Montgomery constant
|
||||
# hence the LSB of the Montgomery representation
|
||||
# cannot be used for this use-case.
|
||||
#
|
||||
# Another angle is that if M is odd,
|
||||
# a+M and a have different parity even though they are
|
||||
# the same modulo M.
|
||||
let canonical {.noInit.} = x.toBig()
|
||||
result = canonical.isOdd()
|
||||
|
||||
func sgn0(x: Fp2): SecretBool =
|
||||
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-4.1
|
||||
# sgn0_m_eq_2(x)
|
||||
#
|
||||
# Input: x, an element of GF(p^2).
|
||||
# Output: 0 or 1.
|
||||
#
|
||||
# Steps:
|
||||
# 1. sign_0 = x_0 mod 2
|
||||
# 2. zero_0 = x_0 == 0
|
||||
# 3. sign_1 = x_1 mod 2
|
||||
# 4. return sign_0 OR (zero_0 AND sign_1) # Avoid short-circuit logic ops
|
||||
|
||||
result = x.c0.sgn0()
|
||||
let z0 = x.c0.isZero()
|
||||
let s1 = x.c1.sgn0()
|
||||
result = result or (z0 and s1)
|
||||
|
||||
func invsqrt_if_square[C: static Curve](
|
||||
r: var Fp2[C], a: Fp2[C]): SecretBool =
|
||||
## If ``a`` is a square, compute the inverse square root of ``a``
|
||||
@ -113,13 +77,13 @@ func invsqrt_if_square[C: static Curve](
|
||||
result = t3.invsqrt_if_square(t1) # 1/sqrt(a0² - β a1²)
|
||||
|
||||
# If input is not a square in Fp2, multiply by 1/Z³
|
||||
inp.prod(a, h2cConst(C, G2, inv_Z3)) # inp = a / Z³
|
||||
inp.prod(a, h2cConst(C, sswu, G2, inv_Z3)) # inp = a / Z³
|
||||
block: # Adjust t1 and t3 accordingly
|
||||
var t0{.noInit.}: Fp[C]
|
||||
t0.prod(t1, h2cConst(C, G2, squared_norm_inv_Z3)) # (a0² - β a1²) * ||1/Z³||²
|
||||
t0.prod(t1, h2cConst(C, sswu, G2, squared_norm_inv_Z3)) # (a0² - β a1²) * ||1/Z³||²
|
||||
t1.ccopy(t0, not result)
|
||||
|
||||
t0.prod(t3, h2cConst(C, G2, inv_norm_inv_Z3)) # 1/sqrt(a0² - β a1²) * 1/||1/Z³||
|
||||
t0.prod(t3, h2cConst(C, sswu, G2, inv_norm_inv_Z3)) # 1/sqrt(a0² - β a1²) * 1/||1/Z³||
|
||||
t3.ccopy(t0, not result)
|
||||
|
||||
inp.ccopy(a, result)
|
||||
@ -188,42 +152,42 @@ func mapToIsoCurve_sswuG2_opt9mod16*[C: static Curve](
|
||||
template gxd: untyped = xd3
|
||||
|
||||
# x numerators
|
||||
uu.square(u) # uu = u²
|
||||
Zuu.prod(uu, h2cConst(C, G2, Z)) # Zuu = Z * uu
|
||||
tv2.square(Zuu) # tv2 = Zuu²
|
||||
tv2 += Zuu # tv2 = tv2 + Zuu
|
||||
uu.square(u) # uu = u²
|
||||
Zuu.prod(uu, h2cConst(C, sswu, G2, Z)) # Zuu = Z * uu
|
||||
tv2.square(Zuu) # tv2 = Zuu²
|
||||
tv2 += Zuu # tv2 = tv2 + Zuu
|
||||
x1n.setOne()
|
||||
x1n += tv2 # x1n = tv2 + 1
|
||||
x1n *= h2cConst(C, G2, Bprime_E2) # x1n = x1n * B'
|
||||
x2n.prod(Zuu, x1n) # x2n = Zuu * x1n
|
||||
x1n += tv2 # x1n = tv2 + 1
|
||||
x1n *= h2cConst(C, sswu, G2, Bprime_E2) # x1n = x1n * B'
|
||||
x2n.prod(Zuu, x1n) # x2n = Zuu * x1n
|
||||
|
||||
# x denumerator
|
||||
xd.prod(tv2, h2cConst(C, G2, minus_A)) # xd = -A * tv2
|
||||
e1 = xd.isZero() # e1 = xd == 0
|
||||
xd.ccopy(h2cConst(C, G2, ZmulA), e1) # If xd == 0, set xd = Z*A
|
||||
xd.prod(tv2, h2cConst(C, sswu, G2, minus_A)) # xd = -A * tv2
|
||||
e1 = xd.isZero() # e1 = xd == 0
|
||||
xd.ccopy(h2cConst(C, sswu, G2, ZmulA), e1) # If xd == 0, set xd = Z*A
|
||||
|
||||
# y numerators
|
||||
tv2.square(xd)
|
||||
gxd.prod(xd, tv2) # gxd = xd³
|
||||
tv2.mulCheckSparse(h2CConst(C, G2, Aprime_E2))
|
||||
gxd.prod(xd, tv2) # gxd = xd³
|
||||
tv2.mulCheckSparse(h2CConst(C, sswu, G2, Aprime_E2))
|
||||
gx1.square(x1n)
|
||||
gx1 += tv2 # x1n² + A * xd²
|
||||
gx1 *= x1n # x1n³ + A * x1n * xd²
|
||||
tv2.prod(gxd, h2cConst(C, G2, Bprime_E2))
|
||||
gx1 += tv2 # gx1 = x1n³ + A * x1n * xd² + B * xd³
|
||||
tv4.square(gxd) # tv4 = gxd²
|
||||
tv2.prod(gx1, gxd) # tv2 = gx1 * gxd
|
||||
tv4 *= tv2 # tv4 = gx1 * gxd³
|
||||
gx1 += tv2 # x1n² + A * xd²
|
||||
gx1 *= x1n # x1n³ + A * x1n * xd²
|
||||
tv2.prod(gxd, h2cConst(C, sswu, G2, Bprime_E2))
|
||||
gx1 += tv2 # gx1 = x1n³ + A * x1n * xd² + B * xd³
|
||||
tv4.square(gxd) # tv4 = gxd²
|
||||
tv2.prod(gx1, gxd) # tv2 = gx1 * gxd
|
||||
tv4 *= tv2 # tv4 = gx1 * gxd³
|
||||
|
||||
# Start searching for sqrt(gx1)
|
||||
e2 = y1.invsqrt_if_square(tv4) # y1 = tv4^c1 = (gx1 * gxd³)^((p²-9)/16)
|
||||
y1 *= tv2 # y1 *= gx1*gxd
|
||||
e2 = y1.invsqrt_if_square(tv4) # y1 = tv4^c1 = (gx1 * gxd³)^((p²-9)/16)
|
||||
y1 *= tv2 # y1 *= gx1*gxd
|
||||
y2.prod(y1, uu)
|
||||
y2 *= u
|
||||
|
||||
# Choose numerators
|
||||
xn.ccopy(x2n, not e2) # xn = e2 ? x1n : x2n
|
||||
yn.ccopy(y2, not e2) # yn = e2 ? y1 : y2
|
||||
xn.ccopy(x2n, not e2) # xn = e2 ? x1n : x2n
|
||||
yn.ccopy(y2, not e2) # yn = e2 ? y1 : y2
|
||||
|
||||
e1 = sgn0(u)
|
||||
e2 = sgn0(y)
|
||||
@ -270,28 +234,28 @@ func mapToIsoCurve_sswuG1_opt3mod4*[C: static Curve](
|
||||
template gxd: untyped = xd3
|
||||
|
||||
# x numerators
|
||||
uu.square(u) # uu = u²
|
||||
Zuu.prod(uu, h2cConst(C, G1, Z)) # Zuu = Z * uu
|
||||
tv2.square(Zuu) # tv2 = Zuu²
|
||||
tv2 += Zuu # tv2 = tv2 + Zuu
|
||||
uu.square(u) # uu = u²
|
||||
Zuu.prod(uu, h2cConst(C, sswu, G1, Z)) # Zuu = Z * uu
|
||||
tv2.square(Zuu) # tv2 = Zuu²
|
||||
tv2 += Zuu # tv2 = tv2 + Zuu
|
||||
x1n.setOne()
|
||||
x1n += tv2 # x1n = tv2 + 1
|
||||
x1n *= h2cConst(C, G1, Bprime_E1) # x1n = x1n * B'
|
||||
x2n.prod(Zuu, x1n) # x2n = Zuu * x1n
|
||||
x1n += tv2 # x1n = tv2 + 1
|
||||
x1n *= h2cConst(C, sswu, G1, Bprime_E1) # x1n = x1n * B'
|
||||
x2n.prod(Zuu, x1n) # x2n = Zuu * x1n
|
||||
|
||||
# x denumerator
|
||||
xd.prod(tv2, h2cConst(C, G1, minus_A)) # xd = -A * tv2
|
||||
e1 = xd.isZero() # e1 = xd == 0
|
||||
xd.ccopy(h2cConst(C, G1, ZmulA), e1) # If xd == 0, set xd = Z*A
|
||||
xd.prod(tv2, h2cConst(C, sswu, G1, minus_A)) # xd = -A * tv2
|
||||
e1 = xd.isZero() # e1 = xd == 0
|
||||
xd.ccopy(h2cConst(C, sswu, G1, ZmulA), e1) # If xd == 0, set xd = Z*A
|
||||
|
||||
# y numerators
|
||||
tv2.square(xd)
|
||||
gxd.prod(xd, tv2) # gxd = xd³
|
||||
tv2 *= h2CConst(C, G1, Aprime_E1)
|
||||
tv2 *= h2cConst(C, sswu, G1, Aprime_E1)
|
||||
gx1.square(x1n)
|
||||
gx1 += tv2 # x1n² + A * xd²
|
||||
gx1 *= x1n # x1n³ + A * x1n * xd²
|
||||
tv2.prod(gxd, h2cConst(C, G1, Bprime_E1))
|
||||
tv2.prod(gxd, h2cConst(C, sswu, G1, Bprime_E1))
|
||||
gx1 += tv2 # gx1 = x1n³ + A * x1n * xd² + B * xd³
|
||||
tv4.square(gxd) # tv4 = gxd²
|
||||
tv2.prod(gx1, gxd) # tv2 = gx1 * gxd
|
||||
@ -300,7 +264,7 @@ func mapToIsoCurve_sswuG1_opt3mod4*[C: static Curve](
|
||||
# Start searching for sqrt(gx1)
|
||||
e2 = y1.invsqrt_if_square(tv4) # y1 = tv4^c1 = (gx1 * gxd³)^((p²-9)/16)
|
||||
y1 *= tv2 # y1 *= gx1*gxd
|
||||
y2.prod(y1, h2cConst(C, G1, sqrt_minus_Z3))
|
||||
y2.prod(y1, h2cConst(C, sswu, G1, sqrt_minus_Z3))
|
||||
y2 *= uu
|
||||
y2 *= u
|
||||
|
||||
|
51
constantine/hash_to_curve/h2c_utilities.nim
Normal file
51
constantine/hash_to_curve/h2c_utilities.nim
Normal file
@ -0,0 +1,51 @@
|
||||
# Constantine
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
# Internals
|
||||
../platforms/abstractions,
|
||||
../math/[arithmetic, extension_fields]
|
||||
|
||||
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#section-4.1
|
||||
|
||||
func sgn0*(x: Fp): SecretBool =
|
||||
## Returns a conventional "sign" for a field element.
|
||||
## Even numbers are considered positive by convention
|
||||
## and odd negative.
|
||||
##
|
||||
## https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-4.1
|
||||
#
|
||||
# In Montgomery representation
|
||||
# each number a is represented as aR (mod M)
|
||||
# with R a Montgomery constant
|
||||
# hence the LSB of the Montgomery representation
|
||||
# cannot be used for this use-case.
|
||||
#
|
||||
# Another angle is that if M is odd,
|
||||
# a+M and a have different parity even though they are
|
||||
# the same modulo M.
|
||||
let canonical {.noInit.} = x.toBig()
|
||||
result = canonical.isOdd()
|
||||
|
||||
func sgn0*(x: Fp2): SecretBool =
|
||||
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-4.1
|
||||
# sgn0_m_eq_2(x)
|
||||
#
|
||||
# Input: x, an element of GF(p^2).
|
||||
# Output: 0 or 1.
|
||||
#
|
||||
# Steps:
|
||||
# 1. sign_0 = x_0 mod 2
|
||||
# 2. zero_0 = x_0 == 0
|
||||
# 3. sign_1 = x_1 mod 2
|
||||
# 4. return sign_0 OR (zero_0 AND sign_1) # Avoid short-circuit logic ops
|
||||
|
||||
result = x.c0.sgn0()
|
||||
let z0 = x.c0.isZero()
|
||||
let s1 = x.c1.sgn0()
|
||||
result = result or (z0 and s1)
|
@ -16,6 +16,7 @@ import
|
||||
./h2c_hash_to_field,
|
||||
./h2c_map_to_isocurve_swu,
|
||||
./h2c_isogeny_maps,
|
||||
./h2c_utilities,
|
||||
../hashes
|
||||
|
||||
# ############################################################
|
||||
@ -34,6 +35,63 @@ import
|
||||
# Map to curve
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
func mapToCurve_svdw[F, G](
|
||||
r: var ECP_ShortW_Aff[F, G],
|
||||
u: F) =
|
||||
## Deterministically map a field element u
|
||||
## to an elliptic curve point `r`
|
||||
## https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#section-6.6.1
|
||||
|
||||
var
|
||||
tv1 {.noInit.}, tv2{.noInit.}, tv3{.noInit.}: F
|
||||
tv4{.noInit.}: F
|
||||
x1{.noInit.}, x2{.noInit.}: F
|
||||
gx1{.noInit.}, gx2{.noInit.}: F
|
||||
|
||||
tv1.square(u)
|
||||
tv1 *= h2cConst(F.C, svdw, G, curve_eq_rhs_Z)
|
||||
tv2 = tv1
|
||||
when F is Fp:
|
||||
tv2 += F(mres: F.getMontyOne())
|
||||
tv1.diff(F(mres: F.getMontyOne()), tv1)
|
||||
else:
|
||||
tv2.c0 += Fp[F.F.C](mres: Fp[F.F.C].getMontyOne())
|
||||
tv1.c0.diff(Fp[F.F.C](mres: Fp[F.F.C].getMontyOne()), tv1.c0)
|
||||
tv1.c1.neg()
|
||||
tv3.prod(tv1, tv2)
|
||||
tv3.inv()
|
||||
|
||||
tv4.prod(u, tv1)
|
||||
tv4 *= tv3
|
||||
tv4.mulCheckSparse(h2cConst(F.C, svdw, G, z3))
|
||||
|
||||
x1.diff(h2cConst(F.C, svdw, G, minus_Z_div_2), tv4)
|
||||
x2.sum(h2cConst(F.C, svdw, G, minus_Z_div_2), tv4)
|
||||
r.x.square(tv2)
|
||||
r.x *= tv3
|
||||
r.x.square()
|
||||
r.x *= h2cConst(F.C, svdw, G, z4)
|
||||
r.x += h2cConst(F.C, svdw, G, Z)
|
||||
|
||||
# x³+ax+b
|
||||
gx1.curve_eq_rhs(x1, G)
|
||||
gx2.curve_eq_rhs(x2, G)
|
||||
|
||||
# TODO: faster Legendre symbol.
|
||||
# We can optimize the 2 legendre symbols + 3 sqrt to
|
||||
# - either 2 legendre and 1 sqrt
|
||||
# - or 3 fused legendre+sqrt
|
||||
let e1 = gx1.isSquare()
|
||||
let e2 = gx2.isSquare() and not e1
|
||||
|
||||
r.x.ccopy(x1, e1)
|
||||
r.x.ccopy(x2, e2)
|
||||
|
||||
r.y.curve_eq_rhs(r.x, G)
|
||||
r.y.sqrt()
|
||||
|
||||
r.y.cneg(sgn0(u) xor sgn0(r.y))
|
||||
|
||||
func mapToIsoCurve_sswuG1_opt3mod4[F](
|
||||
r: var ECP_ShortW_Jac[F, G1],
|
||||
u: F) =
|
||||
@ -72,40 +130,21 @@ func mapToIsoCurve_sswuG2_opt9mod16[F](
|
||||
r.x.prod(xn, xd) # X = xZ² = xn/xd * xd² = xn*xd
|
||||
r.y.prod(yn, xd3) # Y = yZ³ = yn * xd³
|
||||
|
||||
func mapToCurve[F; G: static Subgroup](
|
||||
r: var (ECP_ShortW_Prj[F, G] or ECP_ShortW_Jac[F, G]),
|
||||
u: F) =
|
||||
## Map an element of the
|
||||
func mapToCurve_svdw_fusedAdd[F; G: static Subgroup](
|
||||
r: var ECP_ShortW_Jac[F, G],
|
||||
u0, u1: F) =
|
||||
## Map 2 elements of the
|
||||
## finite or extension field F
|
||||
## to an elliptic curve E
|
||||
|
||||
when F.C.getCoefA() * F.C.getCoefB() == 0:
|
||||
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-6.6.3
|
||||
# Simplified Shallue-van de Woestijne-Ulas method for AB == 0
|
||||
|
||||
# 1. Map to E' isogenous to E
|
||||
when F is Fp and F.C.has_P_3mod4_primeModulus():
|
||||
mapToIsoCurve_sswuG1_opt3mod4(
|
||||
xn, xd,
|
||||
yn,
|
||||
u, xd3
|
||||
)
|
||||
elif F is Fp2 and F.C.has_Psquare_9mod16_primePower():
|
||||
# p ≡ 3 (mod 4) => p² ≡ 9 (mod 16)
|
||||
mapToIsoCurve_sswuG2_opt9mod16(
|
||||
xn, xd,
|
||||
yn,
|
||||
u, xd3
|
||||
)
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
## and add them
|
||||
var P0{.noInit.}, P1{.noInit.}: ECP_ShortW_Aff[F, G]
|
||||
P0.mapToCurve_svdw(u0)
|
||||
P1.mapToCurve_svdw(u1)
|
||||
|
||||
# 2. Map from E'1 to E1
|
||||
r.h2c_isogeny_map(xn, xd, yn)
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
r.fromAffine(P0)
|
||||
r += P1
|
||||
|
||||
func mapToCurve_fusedAdd[F; G: static Subgroup](
|
||||
func mapToCurve_sswu_fusedAdd[F; G: static Subgroup](
|
||||
r: var ECP_ShortW_Jac[F, G],
|
||||
u0, u1: F) =
|
||||
## Map 2 elements of the
|
||||
@ -125,23 +164,24 @@ func mapToCurve_fusedAdd[F; G: static Subgroup](
|
||||
# unlike the complete projective formulae which heavily depends on it
|
||||
# So we use jacobian coordinates for computation on isogenies.
|
||||
|
||||
var P0{.noInit.}, P1{.noInit.}: ECP_ShortW_Jac[F, G]
|
||||
when F.C.getCoefA() * F.C.getCoefB() == 0:
|
||||
# https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-6.6.3
|
||||
# Simplified Shallue-van de Woestijne-Ulas method for AB == 0
|
||||
|
||||
var P0{.noInit.}, P1{.noInit.}: ECP_ShortW_Jac[F, G]
|
||||
|
||||
# 1. Map to E' isogenous to E
|
||||
when F is Fp and F.C.has_P_3mod4_primeModulus():
|
||||
# 1. Map to E'1 isogenous to E1
|
||||
P0.mapToIsoCurve_sswuG1_opt3mod4(u0)
|
||||
P1.mapToIsoCurve_sswuG1_opt3mod4(u1)
|
||||
P0.sum(P0, P1, h2CConst(F.C, G1, Aprime_E1))
|
||||
P0.sum(P0, P1, h2CConst(F.C, sswu, G1, Aprime_E1))
|
||||
elif F is Fp2 and F.C.has_Psquare_9mod16_primePower():
|
||||
# p ≡ 3 (mod 4) => p² ≡ 9 (mod 16)
|
||||
# 1. Map to E'2 isogenous to E2
|
||||
P0.mapToIsoCurve_sswuG2_opt9mod16(u0)
|
||||
P1.mapToIsoCurve_sswuG2_opt9mod16(u1)
|
||||
P0.sum(P0, P1, h2CConst(F.C, G2, Aprime_E2))
|
||||
P0.sum(P0, P1, h2CConst(F.C, sswu, G2, Aprime_E2))
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
|
||||
@ -153,7 +193,7 @@ func mapToCurve_fusedAdd[F; G: static Subgroup](
|
||||
# Hash to curve
|
||||
# ----------------------------------------------------------------
|
||||
|
||||
func hashToCurve*[
|
||||
func hashToCurve_svdw*[
|
||||
F; G: static Subgroup;
|
||||
B1, B2, B3: byte|char](
|
||||
H: type CryptoHash,
|
||||
@ -192,9 +232,89 @@ func hashToCurve*[
|
||||
H.shortDomainSepTag(dst, domainSepTag)
|
||||
H.hashToField(k, u, augmentation, message, dst)
|
||||
|
||||
output.mapToCurve_fusedAdd(u[0], u[1])
|
||||
output.mapToCurve_svdw_fusedAdd(u[0], u[1])
|
||||
output.clearCofactor()
|
||||
|
||||
func hashToCurve_sswu*[
|
||||
F; G: static Subgroup;
|
||||
B1, B2, B3: byte|char](
|
||||
H: type CryptoHash,
|
||||
k: static int,
|
||||
output: var ECP_ShortW_Jac[F, G],
|
||||
augmentation: openarray[B1],
|
||||
message: openarray[B2],
|
||||
domainSepTag: openarray[B3]
|
||||
) =
|
||||
## Hash a message to an elliptic curve
|
||||
##
|
||||
## Arguments:
|
||||
## - `Hash` a cryptographic hash function.
|
||||
## - `Hash` MAY be a Merkle-Damgaard hash function like SHA-2
|
||||
## - `Hash` MAY be a sponge-based hash function like SHA-3 or BLAKE2
|
||||
## - Otherwise, H MUST be a hash function that has been proved
|
||||
## indifferentiable from a random oracle [MRH04] under a reasonable
|
||||
## cryptographic assumption.
|
||||
## - k the security parameter of the suite in bits (for example 128)
|
||||
## - `output`, an elliptic curve point that will be overwritten.
|
||||
## - `augmentation`, an optional augmentation to the message. This will be prepended,
|
||||
## prior to hashing.
|
||||
## This is used for building the "message augmentation" variant of BLS signatures
|
||||
## https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04#section-3.2
|
||||
## which requires `CoreSign(SK, PK || message)`
|
||||
## and `CoreVerify(PK, PK || message, signature)`
|
||||
## - `message` is the message to hash
|
||||
## - `domainSepTag` is the protocol domain separation tag (DST).
|
||||
|
||||
var u{.noInit.}: array[2, F]
|
||||
if domainSepTag.len <= 255:
|
||||
H.hashToField(k, u, augmentation, message, domainSepTag)
|
||||
else:
|
||||
const N = H.type.digestSize()
|
||||
var dst {.noInit.}: array[N, byte]
|
||||
H.shortDomainSepTag(dst, domainSepTag)
|
||||
H.hashToField(k, u, augmentation, message, dst)
|
||||
|
||||
output.mapToCurve_sswu_fusedAdd(u[0], u[1])
|
||||
output.clearCofactor()
|
||||
|
||||
func hashToCurve*[
|
||||
F; G: static Subgroup;
|
||||
B1, B2, B3: byte|char](
|
||||
H: type CryptoHash,
|
||||
k: static int,
|
||||
output: var ECP_ShortW_Jac[F, G],
|
||||
augmentation: openarray[B1],
|
||||
message: openarray[B2],
|
||||
domainSepTag: openarray[B3]
|
||||
) {.inline.} =
|
||||
## Hash a message to an elliptic curve
|
||||
##
|
||||
## Arguments:
|
||||
## - `Hash` a cryptographic hash function.
|
||||
## - `Hash` MAY be a Merkle-Damgaard hash function like SHA-2
|
||||
## - `Hash` MAY be a sponge-based hash function like SHA-3 or BLAKE2
|
||||
## - Otherwise, H MUST be a hash function that has been proved
|
||||
## indifferentiable from a random oracle [MRH04] under a reasonable
|
||||
## cryptographic assumption.
|
||||
## - k the security parameter of the suite in bits (for example 128)
|
||||
## - `output`, an elliptic curve point that will be overwritten.
|
||||
## - `augmentation`, an optional augmentation to the message. This will be prepended,
|
||||
## prior to hashing.
|
||||
## This is used for building the "message augmentation" variant of BLS signatures
|
||||
## https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-04#section-3.2
|
||||
## which requires `CoreSign(SK, PK || message)`
|
||||
## and `CoreVerify(PK, PK || message, signature)`
|
||||
## - `message` is the message to hash
|
||||
## - `domainSepTag` is the protocol domain separation tag (DST).
|
||||
when F.C == BLS12_381:
|
||||
hashToCurve_sswu(H, k, output,
|
||||
augmentation, message, domainSepTag)
|
||||
elif F.C == BN254_Snarks:
|
||||
hashToCurve_svdw(H, k, output,
|
||||
augmentation, message, domainSepTag)
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
|
||||
func hashToCurve*[
|
||||
F; G: static Subgroup;
|
||||
B1, B2, B3: byte|char](
|
||||
@ -204,7 +324,7 @@ func hashToCurve*[
|
||||
augmentation: openarray[B1],
|
||||
message: openarray[B2],
|
||||
domainSepTag: openarray[B3]
|
||||
) =
|
||||
) {.inline.} =
|
||||
## Hash a message to an elliptic curve
|
||||
##
|
||||
## Arguments:
|
||||
|
@ -524,11 +524,11 @@ func prod*(r: var FF, a: FF, b: static int) =
|
||||
|
||||
template mulCheckSparse*(a: var Fp, b: Fp) =
|
||||
## Multiplication with optimization for sparse inputs
|
||||
when b.isOne().bool:
|
||||
when isOne(b).bool:
|
||||
discard
|
||||
elif b.isZero().bool:
|
||||
elif isZero(b).bool:
|
||||
a.setZero()
|
||||
elif b.isMinusOne().bool:
|
||||
elif isMinusOne(b).bool:
|
||||
a.neg()
|
||||
else:
|
||||
a *= b
|
||||
|
@ -10,6 +10,26 @@ import
|
||||
../config/curves,
|
||||
../io/io_fields
|
||||
|
||||
# Hash-to-Curve Shallue-van de Woestijne (SVDW) BLS12_381 G1 map
|
||||
# -----------------------------------------------------------------
|
||||
# Spec:
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-F.1
|
||||
# This map is slower than SSWU
|
||||
|
||||
const BLS12_381_h2c_svdw_G1_Z* = Fp[BLS12_381].fromHex(
|
||||
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa8")
|
||||
const BLS12_381_h2c_svdw_G1_curve_eq_rhs_Z* = Fp[BLS12_381].fromHex(
|
||||
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa94")
|
||||
const BLS12_381_h2c_svdw_G1_minus_Z_div_2* = Fp[BLS12_381].fromHex(
|
||||
"0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd557")
|
||||
const BLS12_381_h2c_svdw_G1_z3* = Fp[BLS12_381].fromHex(
|
||||
"0xc855b97020fc106fa9c2de78c9f5d835bbc17c0487afe401c9cd0dcff9fd40bdf8033cd3095a4cd124d794808f153aa")
|
||||
const BLS12_381_h2c_svdw_G1_z4* = Fp[BLS12_381].fromHex(
|
||||
"0x6bde8333e50911e85400f0953d13fc61090b4c3a76e5a319f7e6f7f108cb197962c97b3cf28bda11d421c71c71c5bab")
|
||||
|
||||
# Hash-to-Curve Simplified Shallue-van de Woestijne-Ulas (SSWU) map
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# Hash-to-Curve map to isogenous BLS12-381 E'1 constants
|
||||
# -----------------------------------------------------------------
|
||||
#
|
||||
@ -19,17 +39,17 @@ import
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#section-8.8.2
|
||||
# - https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/f7dd3761/poc/sswu_opt_3mod4.sage#L126-L132
|
||||
|
||||
const BLS12_381_h2c_G1_Aprime_E1* = Fp[BLS12_381].fromHex(
|
||||
const BLS12_381_h2c_sswu_G1_Aprime_E1* = Fp[BLS12_381].fromHex(
|
||||
"0x144698a3b8e9433d693a02c96d4982b0ea985383ee66a8d8e8981aefd881ac98936f8da0e0f97f5cf428082d584c1d")
|
||||
const BLS12_381_h2c_G1_Bprime_E1* = Fp[BLS12_381].fromHex(
|
||||
const BLS12_381_h2c_sswu_G1_Bprime_E1* = Fp[BLS12_381].fromHex(
|
||||
"0x12e2908d11688030018b12e8753eee3b2016c1f0f24f4070a0b9c14fcef35ef55a23215a316ceaa5d1cc48e98e172be0")
|
||||
const BLS12_381_h2c_G1_Z* = Fp[BLS12_381].fromHex(
|
||||
const BLS12_381_h2c_sswu_G1_Z* = Fp[BLS12_381].fromHex(
|
||||
"0xb")
|
||||
const BLS12_381_h2c_G1_minus_A* = Fp[BLS12_381].fromHex(
|
||||
const BLS12_381_h2c_sswu_G1_minus_A* = Fp[BLS12_381].fromHex(
|
||||
"0x19eccb5195c6fd570db26db379de6354b38cb3316f96ac168e483a8606d8747786189071107306805d0ad7f7d2a75e8e")
|
||||
const BLS12_381_h2c_G1_ZmulA* = Fp[BLS12_381].fromHex(
|
||||
const BLS12_381_h2c_sswu_G1_ZmulA* = Fp[BLS12_381].fromHex(
|
||||
"0xdf088f08f205e3a3857e1ea7b2289d9a148b96ab3e694151fe89284e4d926a8e55cb15e9aab878fe7db859f2cb453f")
|
||||
const BLS12_381_h2c_G1_sqrt_minus_Z3* = Fp[BLS12_381].fromHex(
|
||||
const BLS12_381_h2c_sswu_G1_sqrt_minus_Z3* = Fp[BLS12_381].fromHex(
|
||||
"0x3d689d1e0e762cef9f2bec6130316806b4c80eda6fc10ce77ae83eab1ea8b8b8a407c9c6db195e06f2dbeabc2baeff5")
|
||||
|
||||
# Hash-to-Curve 11-isogeny map BLS12-381 E'1 constants
|
||||
@ -38,7 +58,7 @@ const BLS12_381_h2c_G1_sqrt_minus_Z3* = Fp[BLS12_381].fromHex(
|
||||
# The polynomials map a point (x', y') on the isogenous curve E'1
|
||||
# to (x, y) on E1, represented as (xnum/xden, y' * ynum/yden)
|
||||
|
||||
const BLS12_381_h2c_G1_isogeny_map_xnum* = [
|
||||
const BLS12_381_h2c_sswu_G1_isogeny_map_xnum* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
@ -91,7 +111,7 @@ const BLS12_381_h2c_G1_isogeny_map_xnum* = [
|
||||
"0x6e08c248e260e70bd1e962381edee3d31d79d7e22c837bc23c0bf1bc24c6b68c24b1b80b64d391fa9c8ba2e8ba2d229"
|
||||
)
|
||||
]
|
||||
const BLS12_381_h2c_G1_isogeny_map_xden* = [
|
||||
const BLS12_381_h2c_sswu_G1_isogeny_map_xden* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
@ -140,7 +160,7 @@ const BLS12_381_h2c_G1_isogeny_map_xden* = [
|
||||
"0x1"
|
||||
)
|
||||
]
|
||||
const BLS12_381_h2c_G1_isogeny_map_ynum* = [
|
||||
const BLS12_381_h2c_sswu_G1_isogeny_map_ynum* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
@ -209,7 +229,7 @@ const BLS12_381_h2c_G1_isogeny_map_ynum* = [
|
||||
"0x15e6be4e990f03ce4ea50b3b42df2eb5cb181d8f84965a3957add4fa95af01b2b665027efec01c7704b456be69c8b604"
|
||||
),
|
||||
]
|
||||
const BLS12_381_h2c_G1_isogeny_map_yden* = [
|
||||
const BLS12_381_h2c_sswu_G1_isogeny_map_yden* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
|
@ -10,6 +10,37 @@ import
|
||||
../config/curves,
|
||||
../io/[io_fields, io_extfields]
|
||||
|
||||
# Hash-to-Curve Shallue-van de Woestijne (SVDW) BLS12_381 G2 map
|
||||
# -----------------------------------------------------------------
|
||||
# Spec:
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-F.1
|
||||
# This map is slower than SSWU
|
||||
|
||||
const BLS12_381_h2c_svdw_G2_Z* = Fp2[BLS12_381].fromHex(
|
||||
"0x0",
|
||||
"0x1"
|
||||
)
|
||||
const BLS12_381_h2c_svdw_G2_curve_eq_rhs_Z* = Fp2[BLS12_381].fromHex(
|
||||
"0x4",
|
||||
"0x3"
|
||||
)
|
||||
const BLS12_381_h2c_svdw_G2_minus_Z_div_2* = Fp2[BLS12_381].fromHex(
|
||||
"0x0",
|
||||
"0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd555"
|
||||
)
|
||||
const BLS12_381_h2c_svdw_G2_z3* = Fp2[BLS12_381].fromHex(
|
||||
"0xbdd5ce0da1f67a74801737ad294eb2e8792dfaff3b97d438795e114a0bf9b0d448554f8291ae6ae6f9aad7ac97e0842",
|
||||
"0x154a803c6f0a66f3f4bd964d1db96c49c5807ce89e413640c752821cda0b2d1c809f1c51d940f78f4bdd8f28edd47488"
|
||||
)
|
||||
const BLS12_381_h2c_svdw_G2_z4* = Fp2[BLS12_381].fromHex(
|
||||
"0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc722",
|
||||
"0x4"
|
||||
)
|
||||
|
||||
|
||||
# Hash-to-Curve Simplified Shallue-van de Woestijne-Ulas (SSWU) map
|
||||
# -----------------------------------------------------------------
|
||||
|
||||
# Hash-to-Curve map to isogenous BLS12-381 E'2 constants
|
||||
# -----------------------------------------------------------------
|
||||
#
|
||||
@ -19,33 +50,33 @@ import
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.8.2
|
||||
# - https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/blob/f7dd3761/poc/sswu_opt_9mod16.sage#L142-L148
|
||||
|
||||
const BLS12_381_h2c_G2_Aprime_E2* = Fp2[BLS12_381].fromHex( # 240𝑖
|
||||
const BLS12_381_h2c_sswu_G2_Aprime_E2* = Fp2[BLS12_381].fromHex( # 240𝑖
|
||||
"0x0",
|
||||
"0xf0"
|
||||
)
|
||||
const BLS12_381_h2c_G2_Bprime_E2* = Fp2[BLS12_381].fromHex( # 1012 * (1 + 𝑖)
|
||||
const BLS12_381_h2c_sswu_G2_Bprime_E2* = Fp2[BLS12_381].fromHex( # 1012 * (1 + 𝑖)
|
||||
"0x3f4",
|
||||
"0x3f4"
|
||||
)
|
||||
const BLS12_381_h2c_G2_Z* = Fp2[BLS12_381].fromHex( # -(2 + 𝑖)
|
||||
const BLS12_381_h2c_sswu_G2_Z* = Fp2[BLS12_381].fromHex( # -(2 + 𝑖)
|
||||
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa9",
|
||||
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa"
|
||||
)
|
||||
const BLS12_381_h2c_G2_minus_A* = Fp2[BLS12_381].fromHex( # -240𝑖
|
||||
const BLS12_381_h2c_sswu_G2_minus_A* = Fp2[BLS12_381].fromHex( # -240𝑖
|
||||
"0x0",
|
||||
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9bb"
|
||||
)
|
||||
const BLS12_381_h2c_G2_ZmulA* = Fp2[BLS12_381].fromHex( # Z*A = 240-480𝑖
|
||||
const BLS12_381_h2c_sswu_G2_ZmulA* = Fp2[BLS12_381].fromHex( # Z*A = 240-480𝑖
|
||||
"0xf0",
|
||||
"0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8cb"
|
||||
)
|
||||
const BLS12_381_h2c_G2_inv_Z3* = Fp2[BLS12_381].fromHex( # 1/Z³
|
||||
const BLS12_381_h2c_sswu_G2_inv_Z3* = Fp2[BLS12_381].fromHex( # 1/Z³
|
||||
"0xec5373b4fc387140dfd46af348f55e2ca7901ef5b371b085d6da6bdbb39819171ad78d43fdbbe76a0f1189374bc3a07",
|
||||
"0x9c70eed928c402db9efc63a4a7484928607fdacdea2acefe74fcc1fd9af14de7a1fe76c0d6d687295ce78d4fdf39630"
|
||||
)
|
||||
const BLS12_381_h2c_G2_squared_norm_inv_Z3* = Fp[BLS12_381].fromHex( # ||1/Z³||²
|
||||
const BLS12_381_h2c_sswu_G2_squared_norm_inv_Z3* = Fp[BLS12_381].fromHex( # ||1/Z³||²
|
||||
"0x59ded5774de2fc31e8f3083875e2b7a4cff24cacc26fbdb84e195f19dbbba49567f439538bc20c48c86f3b645a1b852")
|
||||
const BLS12_381_h2c_G2_inv_norm_inv_Z3* = Fp[BLS12_381].fromHex( # 1/||1/Z³||
|
||||
const BLS12_381_h2c_sswu_G2_inv_norm_inv_Z3* = Fp[BLS12_381].fromHex( # 1/||1/Z³||
|
||||
"0x810e5a23cbb86fd12ded1af502287a397ed25c1d6fe0444e38c48e9c7ddb3c27cfebdd464e90f201fda0eb6983f2533")
|
||||
|
||||
|
||||
@ -55,7 +86,7 @@ const BLS12_381_h2c_G2_inv_norm_inv_Z3* = Fp[BLS12_381].fromHex( # 1/||1/Z³||
|
||||
# The polynomials map a point (x', y') on the isogenous curve E'2
|
||||
# to (x, y) on E2, represented as (xnum/xden, y' * ynum/yden)
|
||||
|
||||
const BLS12_381_h2c_G2_isogeny_map_xnum* = [
|
||||
const BLS12_381_h2c_sswu_G2_isogeny_map_xnum* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
@ -80,7 +111,7 @@ const BLS12_381_h2c_G2_isogeny_map_xnum* = [
|
||||
"0x0"
|
||||
)
|
||||
]
|
||||
const BLS12_381_h2c_G2_isogeny_map_xden* = [
|
||||
const BLS12_381_h2c_sswu_G2_isogeny_map_xden* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
@ -100,7 +131,7 @@ const BLS12_381_h2c_G2_isogeny_map_xden* = [
|
||||
"0x0"
|
||||
)
|
||||
]
|
||||
const BLS12_381_h2c_G2_isogeny_map_ynum* = [
|
||||
const BLS12_381_h2c_sswu_G2_isogeny_map_ynum* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
@ -125,7 +156,7 @@ const BLS12_381_h2c_G2_isogeny_map_ynum* = [
|
||||
"0x0"
|
||||
)
|
||||
]
|
||||
const BLS12_381_h2c_G2_isogeny_map_yden* = [
|
||||
const BLS12_381_h2c_sswu_G2_isogeny_map_yden* = [
|
||||
# Polynomial k₀ + k₁ x + k₂ x² + k₃ x³ + ... + kₙ xⁿ
|
||||
# The polynomial is stored as an array of coefficients ordered from k₀ to kₙ
|
||||
|
||||
|
@ -81,7 +81,7 @@ func clearCofactorReference*(P: var ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]) {.inl
|
||||
# BN G1
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BN254_Nogami], G1]) {.inline.} =
|
||||
func clearCofactorFast*(P: var ECP_ShortW[Fp[BN254_Nogami], G1]) {.inline.} =
|
||||
## Clear the cofactor of BN254_Nogami G1
|
||||
## BN curves have a prime order r hence all points on curve are in G1
|
||||
## Hence this is a no-op
|
||||
@ -93,7 +93,7 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BN254_Nogami], G1]) {.inline.}
|
||||
# Implementation
|
||||
# Fuentes-Castaneda et al, "Fast Hashing to G2 on Pairing-Friendly Curves", https://doi.org/10.1007/978-3-642-28496-0_25*
|
||||
|
||||
func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]) {.inline.} =
|
||||
func clearCofactorFast*(P: var ECP_ShortW[Fp2[BN254_Nogami], G2]) {.inline.} =
|
||||
## Clear the cofactor of BN254_Nogami G2
|
||||
## Optimized using endomorphisms
|
||||
## P' → [x]P + [3x]ψ(P) + [x]ψ²(P) + ψ³(P)
|
||||
@ -115,7 +115,7 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]) {.inline.}
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func isInSubgroup*(P: ECP_ShortW_Prj[Fp[BN254_Nogami], G1]): SecretBool {.inline.} =
|
||||
func isInSubgroup*(P: ECP_ShortW[Fp[BN254_Nogami], G1]): SecretBool {.inline.} =
|
||||
## Returns true if P is in G1 subgroup, i.e. P is a point of order r.
|
||||
## A point may be on a curve but not on the prime order r subgroup.
|
||||
## Not checking subgroup exposes a protocol to small subgroup attacks.
|
||||
@ -124,7 +124,7 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp[BN254_Nogami], G1]): SecretBool {.inline
|
||||
## Warning ⚠: Assumes that P is on curve
|
||||
return CtTrue
|
||||
|
||||
func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]): SecretBool =
|
||||
func isInSubgroup*(P: ECP_ShortW_Jac[Fp2[BN254_Nogami], G2] or ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]): SecretBool =
|
||||
## Returns true if P is in G2 subgroup, i.e. P is a point of order r.
|
||||
## A point may be on a curve but not on the prime order r subgroup.
|
||||
## Not checking subgroup exposes a protocol to small subgroup attacks.
|
||||
@ -140,7 +140,7 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]): SecretBool =
|
||||
# p the prime modulus: 36u⁴ + 36u³ + 24u² + 6u + 1
|
||||
# r the prime order: 36u⁴ + 36u³ + 18u² + 6u + 1
|
||||
# t the trace: 6u² + 1
|
||||
var t0{.noInit.}, t1{.noInit.}: ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]
|
||||
var t0{.noInit.}, t1{.noInit.}: typeof(P)
|
||||
|
||||
t0.pow_BN254_Nogami_u(P) # [u]P
|
||||
t1.pow_BN254_Nogami_u(t0) # [u²]P
|
||||
@ -150,4 +150,14 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BN254_Nogami], G2]): SecretBool =
|
||||
|
||||
t1.frobenius_psi(P) # ψ(P)
|
||||
|
||||
return t0 == t1
|
||||
return t0 == t1
|
||||
|
||||
func isInSubgroup*(P: ECP_ShortW_Aff[Fp2[BN254_Nogami], G2]): SecretBool =
|
||||
## Returns true if P is in 𝔾2 subgroup, i.e. P is a point of order r.
|
||||
## A point may be on a curve but not on the prime order r subgroup.
|
||||
## Not checking subgroup exposes a protocol to small subgroup attacks.
|
||||
##
|
||||
## Warning ⚠: Assumes that P is on curve
|
||||
var t{.noInit.}: ECP_ShortW_Jac[Fp2[BN254_Nogami], G2]
|
||||
t.fromAffine(P)
|
||||
return t.isInSubgroup()
|
27
constantine/math/curves/bn254_snarks_hash_to_curve_g1.nim
Normal file
27
constantine/math/curves/bn254_snarks_hash_to_curve_g1.nim
Normal file
@ -0,0 +1,27 @@
|
||||
# Constantine
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../config/curves,
|
||||
../io/io_fields
|
||||
|
||||
# Hash-to-Curve Shallue-van de Woestijne BN254_Snarks G1 map
|
||||
# -----------------------------------------------------------------
|
||||
# Spec:
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-F.1
|
||||
|
||||
const BN254_Snarks_h2c_svdw_G1_Z* = Fp[BN254_Snarks].fromHex(
|
||||
"0x1")
|
||||
const BN254_Snarks_h2c_svdw_G1_curve_eq_rhs_Z* = Fp[BN254_Snarks].fromHex(
|
||||
"0x4")
|
||||
const BN254_Snarks_h2c_svdw_G1_minus_Z_div_2* = Fp[BN254_Snarks].fromHex(
|
||||
"0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3")
|
||||
const BN254_Snarks_h2c_svdw_G1_z3* = Fp[BN254_Snarks].fromHex(
|
||||
"0x16789af3a83522eb353c98fc6b36d713d5d8d1cc5dffffffa")
|
||||
const BN254_Snarks_h2c_svdw_G1_z4* = Fp[BN254_Snarks].fromHex(
|
||||
"0x10216f7ba065e00de81ac1e7808072c9dd2b2385cd7b438469602eb24829a9bd")
|
37
constantine/math/curves/bn254_snarks_hash_to_curve_g2.nim
Normal file
37
constantine/math/curves/bn254_snarks_hash_to_curve_g2.nim
Normal file
@ -0,0 +1,37 @@
|
||||
# Constantine
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../config/curves,
|
||||
../io/[io_fields, io_extfields]
|
||||
|
||||
# Hash-to-Curve Shallue-van de Woestijne BN254_Snarks G2 map
|
||||
# -----------------------------------------------------------------
|
||||
# Spec:
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-F.1
|
||||
|
||||
const BN254_Snarks_h2c_svdw_G2_Z* = Fp2[BN254_Snarks].fromHex(
|
||||
"0x0",
|
||||
"0x1"
|
||||
)
|
||||
const BN254_Snarks_h2c_svdw_G2_curve_eq_rhs_Z* = Fp2[BN254_Snarks].fromHex(
|
||||
"0x2b149d40ceb8aaae81be18991be06ac3b5b4c5e559dbefa33267e6dc24a138e5",
|
||||
"0x9713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d1"
|
||||
)
|
||||
const BN254_Snarks_h2c_svdw_G2_minus_Z_div_2* = Fp2[BN254_Snarks].fromHex(
|
||||
"0x0",
|
||||
"0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3"
|
||||
)
|
||||
const BN254_Snarks_h2c_svdw_G2_z3* = Fp2[BN254_Snarks].fromHex(
|
||||
"0x1248cccf0e2a72383dec3a1621130a65c0eb5d826ca664d3f4fce46f983efce6",
|
||||
"0x220de2a91cc408cf05ff76bf76fb88febaac1173cab9c8ebc03c7f9dc5569f10"
|
||||
)
|
||||
const BN254_Snarks_h2c_svdw_G2_z4* = Fp2[BN254_Snarks].fromHex(
|
||||
"0x294f62301de5ae301a38098f4f5570e5bfc5e456aa54a6aa847fafc89357f76f",
|
||||
"0xc96f95a3ebfe711190ea3d3e76a7f0df14d60686e6cb1930d8fc08b259726c"
|
||||
)
|
@ -146,7 +146,7 @@ func clearCofactorReference*(P: var ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]) {.inl
|
||||
# BN G1
|
||||
# ------------------------------------------------------------
|
||||
|
||||
func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BN254_Snarks], G1]) {.inline.} =
|
||||
func clearCofactorFast*(P: var ECP_ShortW[Fp[BN254_Snarks], G1]) {.inline.} =
|
||||
## Clear the cofactor of BN254_Snarks G1
|
||||
## BN curves have a prime order r hence all points on curve are in G1
|
||||
## Hence this is a no-op
|
||||
@ -158,7 +158,7 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp[BN254_Snarks], G1]) {.inline.}
|
||||
# Implementation
|
||||
# Fuentes-Castaneda et al, "Fast Hashing to G2 on Pairing-Friendly Curves", https://doi.org/10.1007/978-3-642-28496-0_25*
|
||||
|
||||
func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]) {.inline.} =
|
||||
func clearCofactorFast*(P: var ECP_ShortW[Fp2[BN254_Snarks], G2]) {.inline.} =
|
||||
## Clear the cofactor of BN254_Snarks G2
|
||||
## Optimized using endomorphisms
|
||||
## P' → [x]P + [3x]ψ(P) + [x]ψ²(P) + ψ³(P)
|
||||
@ -180,7 +180,7 @@ func clearCofactorFast*(P: var ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]) {.inline.}
|
||||
#
|
||||
# ############################################################
|
||||
|
||||
func isInSubgroup*(P: ECP_ShortW_Prj[Fp[BN254_Snarks], G1]): SecretBool {.inline.} =
|
||||
func isInSubgroup*(P: ECP_ShortW[Fp[BN254_Snarks], G1]): SecretBool {.inline.} =
|
||||
## Returns true if P is in G1 subgroup, i.e. P is a point of order r.
|
||||
## A point may be on a curve but not on the prime order r subgroup.
|
||||
## Not checking subgroup exposes a protocol to small subgroup attacks.
|
||||
@ -189,7 +189,7 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp[BN254_Snarks], G1]): SecretBool {.inline
|
||||
## Warning ⚠: Assumes that P is on curve
|
||||
return CtTrue
|
||||
|
||||
func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]): SecretBool =
|
||||
func isInSubgroup*(P: ECP_ShortW_Jac[Fp2[BN254_Snarks], G2] or ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]): SecretBool =
|
||||
## Returns true if P is in G2 subgroup, i.e. P is a point of order r.
|
||||
## A point may be on a curve but not on the prime order r subgroup.
|
||||
## Not checking subgroup exposes a protocol to small subgroup attacks.
|
||||
@ -205,7 +205,7 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]): SecretBool =
|
||||
# p the prime modulus: 36u⁴ + 36u³ + 24u² + 6u + 1
|
||||
# r the prime order: 36u⁴ + 36u³ + 18u² + 6u + 1
|
||||
# t the trace: 6u² + 1
|
||||
var t0{.noInit.}, t1{.noInit.}: ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]
|
||||
var t0{.noInit.}, t1{.noInit.}: typeof(P)
|
||||
|
||||
t0.pow_bn254_snarks_u(P) # [u]P
|
||||
t1.pow_bn254_snarks_u(t0) # [u²]P
|
||||
@ -215,4 +215,14 @@ func isInSubgroup*(P: ECP_ShortW_Prj[Fp2[BN254_Snarks], G2]): SecretBool =
|
||||
|
||||
t1.frobenius_psi(P) # ψ(P)
|
||||
|
||||
return t0 == t1
|
||||
return t0 == t1
|
||||
|
||||
func isInSubgroup*(P: ECP_ShortW_Aff[Fp2[BN254_Snarks], G2]): SecretBool =
|
||||
## Returns true if P is in 𝔾2 subgroup, i.e. P is a point of order r.
|
||||
## A point may be on a curve but not on the prime order r subgroup.
|
||||
## Not checking subgroup exposes a protocol to small subgroup attacks.
|
||||
##
|
||||
## Warning ⚠: Assumes that P is on curve
|
||||
var t{.noInit.}: ECP_ShortW_Jac[Fp2[BN254_Snarks], G2]
|
||||
t.fromAffine(P)
|
||||
return t.isInSubgroup()
|
@ -11,19 +11,23 @@ import
|
||||
../config/curves,
|
||||
../elliptic/ec_shortweierstrass_affine,
|
||||
./bls12_381_hash_to_curve_g1,
|
||||
./bls12_381_hash_to_curve_g2
|
||||
./bls12_381_hash_to_curve_g2,
|
||||
./bn254_snarks_hash_to_curve_g1,
|
||||
./bn254_snarks_hash_to_curve_g2
|
||||
|
||||
{.experimental: "dynamicBindSym".}
|
||||
|
||||
macro h2cConst*(C: static Curve, group, value: untyped): untyped =
|
||||
macro h2cConst*(C: static Curve, mapping: untyped, group: static Subgroup, value: untyped): untyped =
|
||||
## Get a Hash-to-Curve constant
|
||||
## for mapping to a elliptic curve group (G1 or G2)
|
||||
return bindSym($C & "_h2c_" & $group & "_" & $value)
|
||||
return bindSym($C & "_h2c_" & $mapping & "_" & $group & "_" & $value)
|
||||
|
||||
macro h2cIsomapPoly*(C: static Curve,
|
||||
mapping: untyped,
|
||||
group: static Subgroup,
|
||||
value: untyped): untyped =
|
||||
## Get an isogeny map polynomial
|
||||
## for mapping to a elliptic curve group (G1 or G2)
|
||||
return bindSym($C & "_h2c_" &
|
||||
$mapping & "_" &
|
||||
$group & "_isogeny_map_" & $value)
|
||||
|
@ -66,6 +66,8 @@ func curve_eq_rhs*[F](y2: var F, x: F, G: static Subgroup) =
|
||||
|
||||
var t{.noInit.}: F
|
||||
t.square(x)
|
||||
when F.C.getCoefA() != 0:
|
||||
t += F.C.getCoefA()
|
||||
t *= x
|
||||
|
||||
when G == G1:
|
||||
@ -78,11 +80,6 @@ func curve_eq_rhs*[F](y2: var F, x: F, G: static Subgroup) =
|
||||
else:
|
||||
y2.sum(F.C.getCoefB_G2(), t)
|
||||
|
||||
when F.C.getCoefA() != 0:
|
||||
t = x
|
||||
t *= F.C.getCoefA()
|
||||
y2 += t
|
||||
|
||||
func isOnCurve*[F](x, y: F, G: static Subgroup): SecretBool =
|
||||
## Returns true if the (x, y) coordinates
|
||||
## represents a point of the elliptic curve
|
||||
|
@ -202,3 +202,11 @@ func sqrt_if_square*(a: var Fp2): SecretBool =
|
||||
result = a.sqrt_if_square_generic()
|
||||
else:
|
||||
result = a.sqrt_if_square_opt()
|
||||
|
||||
func sqrt*(a: var Fp2) =
|
||||
## If ``a`` is a square, compute the square root of ``a``
|
||||
## if not, ``a`` is undefined.
|
||||
##
|
||||
## The square root, if it exist is multivalued,
|
||||
## i.e. both x² == (-x)²
|
||||
discard a.sqrt_if_square()
|
@ -87,7 +87,62 @@ def dump_poly(name, poly, field, curve):
|
||||
result += ']'
|
||||
return result
|
||||
|
||||
# Isogenies
|
||||
ZZR = PolynomialRing(ZZ, name='XX')
|
||||
def sgn0(x):
|
||||
"""
|
||||
Returns 1 if x is 'negative' (little-endian sense), else 0.
|
||||
"""
|
||||
degree = x.parent().degree()
|
||||
if degree == 1:
|
||||
# not a field extension
|
||||
xi_values = (ZZ(x),)
|
||||
else:
|
||||
# field extension
|
||||
xi_values = ZZR(x) # extract vector repr of field element (faster than x._vector_())
|
||||
sign = 0
|
||||
zero = 1
|
||||
# compute the sign in constant time
|
||||
for i in range(0, degree):
|
||||
zz_xi = xi_values[i]
|
||||
# sign of this digit
|
||||
sign_i = zz_xi % 2
|
||||
zero_i = zz_xi == 0
|
||||
# update sign and zero
|
||||
sign = sign | (zero & sign_i)
|
||||
zero = zero & zero_i
|
||||
return sign
|
||||
|
||||
# Generic Shallue-van de Woestijne map
|
||||
# ---------------------------------------------------------
|
||||
|
||||
def find_z_svdw(F, A, B):
|
||||
"""
|
||||
https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-H.1
|
||||
Arguments:
|
||||
- F, a field object, e.g., F = GF(2^521 - 1)
|
||||
- A and B, the coefficients of the curve y^2 = x^3 + A * x + B
|
||||
"""
|
||||
g = lambda x: F(x)^3 + F(A) * F(x) + F(B)
|
||||
h = lambda Z: -(F(3) * Z^2 + F(4) * A) / (F(4) * g(Z))
|
||||
ctr = F.gen()
|
||||
while True:
|
||||
for Z_cand in (F(ctr), F(-ctr)):
|
||||
if g(Z_cand) == F(0):
|
||||
# Criterion 1: g(Z) != 0 in F.
|
||||
continue
|
||||
if h(Z_cand) == F(0):
|
||||
# Criterion 2: -(3 * Z^2 + 4 * A) / (4 * g(Z)) != 0 in F.
|
||||
continue
|
||||
if not h(Z_cand).is_square():
|
||||
# Criterion 3: -(3 * Z^2 + 4 * A) / (4 * g(Z)) is square in F.
|
||||
continue
|
||||
if g(Z_cand).is_square() or g(-Z_cand / F(2)).is_square():
|
||||
# Criterion 4: At least one of g(Z) and g(-Z / 2) is square in F.
|
||||
return Z_cand
|
||||
ctr += 1
|
||||
|
||||
|
||||
# Isogenies for Simplified Shallue-van de Woestijne-Ulas map
|
||||
# ---------------------------------------------------------
|
||||
|
||||
def find_iso(E):
|
||||
@ -100,14 +155,14 @@ def find_iso(E):
|
||||
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}')
|
||||
print(f'✔️✔️✔️ Found {len(isos)} isogenous curves of degree {p_test}')
|
||||
return isos[0].dual()
|
||||
print(f'Found no isogenies')
|
||||
print(f'⚠️⚠️⚠️ Found no isogenies for {E}')
|
||||
return None
|
||||
|
||||
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-14#appendix-H.2
|
||||
Arguments:
|
||||
- F, a field object, e.g., F = GF(2^521 - 1)
|
||||
- A and B, the coefficients of the curve equation y² = x³ + A * x + B
|
||||
@ -187,13 +242,21 @@ def search_isogeny(curve_name, curve_config):
|
||||
else:
|
||||
raise ValueError('E2 must be a D_Twist or M_Twist but found ' + twist)
|
||||
|
||||
|
||||
# Isogenies:
|
||||
iso_G1 = find_iso(E1)
|
||||
iso_G2 = find_iso(E2)
|
||||
|
||||
if iso_G1 == None or iso_G2 == None:
|
||||
# TODO: case when G1 has a cheap isogeny but G2 does not
|
||||
Z_G1 = find_z_svdw(Fp, A, B)
|
||||
print(f"Z G1 (svdw): {Z_G1}")
|
||||
Z_G2 = find_z_svdw(Fp2, A, G2B)
|
||||
print(f"Z G2 (svdw): {fp2_to_hex(Z_G2)}")
|
||||
return
|
||||
|
||||
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()
|
||||
|
||||
@ -204,12 +267,12 @@ def search_isogeny(curve_name, curve_config):
|
||||
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" Z (sswu): {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)}")
|
||||
print(f" Z (sswu): {fp2_to_hex(Z_G2)}")
|
||||
|
||||
# BLS12-381 G1
|
||||
# ---------------------------------------------------------
|
||||
@ -223,7 +286,6 @@ def genBLS12381G1_H2C_constants(curve_config):
|
||||
# ------------------------------------------
|
||||
p = curve_config[curve_name]['field']['modulus']
|
||||
Fp = GF(p)
|
||||
K.<u> = PolynomialRing(Fp)
|
||||
# ------------------------------------------
|
||||
|
||||
# Hash to curve isogenous curve parameters
|
||||
@ -503,6 +565,140 @@ def genBLS12381G2_H2C_isogeny_map(curve_config):
|
||||
|
||||
return buf
|
||||
|
||||
def genSVDW_H2C_G1_constants(curve, curve_config, Z):
|
||||
p = curve_config[curve]['field']['modulus']
|
||||
a = curve_config[curve]['curve']['a']
|
||||
b = curve_config[curve]['curve']['b']
|
||||
|
||||
Fp = GF(p)
|
||||
|
||||
print(f'\n----> Hash-to-Curve Shallue-van de Woestijne {curve} G1 map <----\n')
|
||||
buf = inspect.cleandoc(f"""
|
||||
# Hash-to-Curve Shallue-van de Woestijne {curve} G1 map
|
||||
# -----------------------------------------------------------------
|
||||
# Spec:
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-F.1
|
||||
""")
|
||||
buf += '\n\n'
|
||||
|
||||
c1 = Z^3 + a*Z + b
|
||||
c2 = -Z/2
|
||||
t = 3 * Z^2 + 4 * a
|
||||
c3 = sqrt(-c1 * t)
|
||||
if sgn0(c3) == 1:
|
||||
c3 = -c3
|
||||
c4 = -4 * c1 / t
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G1_Z* = '
|
||||
buf += field_to_nim(Z, 'Fp', curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G1_curve_eq_rhs_Z* = '
|
||||
buf += field_to_nim(c1, 'Fp', curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G1_minus_Z_div_2* = '
|
||||
buf += field_to_nim(c2, 'Fp', curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G1_z3* = '
|
||||
buf += field_to_nim(c3, 'Fp', curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G1_z4* = '
|
||||
buf += field_to_nim(c4, 'Fp', curve)
|
||||
buf += '\n'
|
||||
|
||||
return buf
|
||||
|
||||
def genSVDW_H2C_G2_constants(curve, curve_config, Z):
|
||||
p = curve_config[curve]['field']['modulus']
|
||||
a = curve_config[curve]['curve']['a']
|
||||
b = curve_config[curve]['curve']['b']
|
||||
|
||||
embedding_degree = curve_config[curve]['tower']['embedding_degree']
|
||||
twist_degree = curve_config[curve]['tower']['twist_degree']
|
||||
twist = curve_config[curve]['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]['tower']['QNR_Fp']
|
||||
elif G2_field_degree == 1:
|
||||
if twist_degree == 6:
|
||||
# Only for complete serialization
|
||||
non_residue_fp = curve_config[curve]['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]['tower']['SNR_Fp2']
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
elif G2_field == 'Fp':
|
||||
G2F = Fp
|
||||
if twist_degree == 6:
|
||||
non_residue_twist = curve_config[curve]['tower']['SNR_Fp']
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
if twist == 'D_Twist':
|
||||
G2B = b/G2F(non_residue_twist)
|
||||
elif twist == 'M_Twist':
|
||||
G2B = b*G2F(non_residue_twist)
|
||||
else:
|
||||
raise ValueError('E2 must be a D_Twist or M_Twist but found ' + twist)
|
||||
|
||||
print(f'\n----> Hash-to-Curve Shallue-van de Woestijne {curve} G2 map <----\n')
|
||||
buf = inspect.cleandoc(f"""
|
||||
# Hash-to-Curve Shallue-van de Woestijne {curve} G2 map
|
||||
# -----------------------------------------------------------------
|
||||
# Spec:
|
||||
# - https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-F.1
|
||||
""")
|
||||
buf += '\n\n'
|
||||
|
||||
c1 = Z^3 + a*Z + G2B
|
||||
c2 = -Z/2
|
||||
t = 3 * Z^2 + 4 * a
|
||||
c3 = sqrt(-c1 * t)
|
||||
if sgn0(c3) == 1:
|
||||
c3 = -c3
|
||||
c4 = -4 * c1 / t
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G2_Z* = '
|
||||
buf += field_to_nim(Z, G2_field, curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G2_curve_eq_rhs_Z* = '
|
||||
buf += field_to_nim(c1, G2_field, curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G2_minus_Z_div_2* = '
|
||||
buf += field_to_nim(c2, G2_field, curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G2_z3* = '
|
||||
buf += field_to_nim(c3, G2_field, curve)
|
||||
buf += '\n'
|
||||
|
||||
buf += f'const {curve}_h2c_svdw_G2_z4* = '
|
||||
buf += field_to_nim(c4, G2_field, curve)
|
||||
buf += '\n'
|
||||
|
||||
return buf
|
||||
|
||||
# CLI
|
||||
# ---------------------------------------------------------
|
||||
|
||||
@ -552,6 +748,52 @@ if __name__ == "__main__":
|
||||
h2c += '\n\n'
|
||||
h2c += genBLS12381G2_H2C_isogeny_map(Curves)
|
||||
|
||||
with open(f'{curve.lower()}_hash_to_curve_g2.nim', 'w') as f:
|
||||
f.write(copyright())
|
||||
f.write('\n\n')
|
||||
|
||||
f.write(inspect.cleandoc("""
|
||||
import
|
||||
../config/curves,
|
||||
../io/[io_fields, io_extfields]
|
||||
"""))
|
||||
|
||||
f.write('\n\n')
|
||||
f.write(h2c)
|
||||
|
||||
print(f'Successfully created {curve.lower()}_hash_to_curve_g2.nim')
|
||||
|
||||
elif curve == 'BN254_Snarks' and group_or_iso == 'G1':
|
||||
p = Curves['BN254_Snarks']['field']['modulus']
|
||||
|
||||
Z = GF(p)(1)
|
||||
h2c = genSVDW_H2C_G1_constants('BN254_Snarks', Curves, Z)
|
||||
|
||||
with open(f'{curve.lower()}_hash_to_curve_g1.nim', 'w') as f:
|
||||
f.write(copyright())
|
||||
f.write('\n\n')
|
||||
|
||||
f.write(inspect.cleandoc("""
|
||||
import
|
||||
../config/curves,
|
||||
../io/io_fields
|
||||
"""))
|
||||
|
||||
f.write('\n\n')
|
||||
f.write(h2c)
|
||||
|
||||
print(f'Successfully created {curve.lower()}_hash_to_curve_g1.nim')
|
||||
|
||||
elif curve == 'BN254_Snarks' and group_or_iso == 'G2':
|
||||
p = Curves['BN254_Snarks']['field']['modulus']
|
||||
non_residue_fp = Curves['BN254_Snarks']['tower']['QNR_Fp']
|
||||
Fp = GF(p)
|
||||
K.<u> = PolynomialRing(Fp)
|
||||
Fp2.<beta> = Fp.extension(u^2 - non_residue_fp)
|
||||
|
||||
Z = Fp2([0, 1])
|
||||
h2c = genSVDW_H2C_G2_constants('BN254_Snarks', Curves, Z)
|
||||
|
||||
with open(f'{curve.lower()}_hash_to_curve_g2.nim', 'w') as f:
|
||||
f.write(copyright())
|
||||
f.write('\n\n')
|
||||
|
@ -72,7 +72,7 @@ proc run_EC_addition_tests*(
|
||||
moduleName: string
|
||||
) =
|
||||
|
||||
# Random seed for reproducibility
|
||||
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
|
@ -0,0 +1,96 @@
|
||||
{
|
||||
"L": "0x40",
|
||||
"Z": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaa8",
|
||||
"ciphersuite": "BLS12381G1_XMD:SHA-256_SVDW_RO_",
|
||||
"curve": "BLS12381G1",
|
||||
"dst": "BLS12381G1_XMD:SHA-256_SVDW_RO_TESTGEN",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x1",
|
||||
"p": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SVDW"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x163505b44d4a47de22946139337d787f93f4356075c55401f4fdbeb3ede4f3138684e2437e50175f94eac511d7c673d6",
|
||||
"y": "0x0d09a4540a792daf4d0368f20afb5bd859e537e362edfc9b6f35290b6d05df90937ea91e6277d1cb91638c1abaec4eca"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x04c5db8bf2c09bda41eab080eb6ffed00f30d4c650a0c0c8cb136d9041a9e9b420aa5737fc8dcd1ec2eda971b4bbf7e1",
|
||||
"y": "0x05b8cc1054ff8ec690a4c073649b474b7b96f2b26ebf83cdd354197ab89f66d78f120407a934d5aac78913d16a8092a5"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0ace795fe3b2f40cceda72f6fc9086009db87b1e63e906df2eeca748df8f961ae3c83e83bf6c11b5d833e7b93c8911f6",
|
||||
"y": "0x02be94da9204c38c42828e677cc941184b62ab9aaebe408f90035c50afd732611550dcd31cec9625874596c8d45dd2f5"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x10baa9e54a51ad63c6d8675830a2d74c43abd00a4e56432e90aa77ccf95997286d3b7bf1f61059b76663878995426b9d",
|
||||
"0x0acf2dcf2bf547d48c01b96379801bd7e2b9f815f22132a07d1ae1ffe49040825ba7b28082696a67b3de2cf9de5f886f"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x02967a7955df3c43807263e9d33c28912daebcdf915ada74ea6ec131210a3f304d97a59d6e3b7bcd98d84f61efb2f659",
|
||||
"y": "0x13dab558fae67943edd68f571bdc82ad6944f2d80285d9f578d4b1be0d7b4641c653ca52f13eb3474922617c00e4eab5"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x118e12a015459f171fa12049d2bf7a43aa2d07b10709c2e21757f191cc60a3313e447c4ceefb3dc89e05893af65b133d",
|
||||
"y": "0x0c02fa378304433efcf458c0cc531b72b8613e425cb8404be8612aee0f7850724ed2a6c6d02a8310cf381b99c85293c6"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x107450b1fd1a5e7b8fdf96cd40da9c1919ba86c124160ab6d5d2ed9f83ee8f97c1530437f6f811fa4f4cd1d0a7d69c42",
|
||||
"y": "0x039185c9fb255a0ac30d091675f02d29bfcf6045b1532384056876a389819d48da77fd71669516e7c98e12da273cddd7"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x12b51a783412cbfae1f1b20d7000184c74c889382dc65762ad98a8d6d654aec9a05fa4621693072c67e41987e36b3998",
|
||||
"0x150a735bb2fb20d4b6221a2d20cfbe275826a63a38f04f757ac63a35dc0a26041d842e9d7f27e3394a007bbeee92fe85"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x084b64b095e373b86441e9fe737a3f8e56fe7f0016a973ed9938db9958505a8927ca220d8e8235901d4bc1dccd4362bb",
|
||||
"y": "0x0fd10114cded64bf037d3ba00b4a85e5f19847535dbc960bdaaa8a92bbb9d8a845dc355370ed0edb9d4403afc39bd30c"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x01bbafd66bbe5955cf186e1b050f962f7a2efa4f03ff50353dbda78568f5541aa8582c25057a9fe414f9a1bd82eccf0a",
|
||||
"y": "0x0c96fd01df526fda79643a45b1ec5d435e63a3af5cf4088f30c07302ff8e0a271aff59e5da618ab9b89326fe8b4338fa"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x086bb205df6314011dedc477b201229f383c1e2585b5aaf269fc6762ccb2397690064429dddbf9f304367508aac0fe83",
|
||||
"y": "0x02f80d27fd2981db284b0f66cf3d8e06f751464e610009b9f3fbb818f526ff85f7f1a38ea3c85008c5814ff19d05a1ee"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x163831497fddb01bbad44e3f592ad34635579e055d36be71d53bec8b22c27525a471ea058bea4a188a857861fd1af802",
|
||||
"0x0cf8d175460236795d8163d01d5068d82b218295a1f8a8eca094ce27ff208ab5c9c3f4212e3fcdef3980a267598f6830"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1362872938edd5f0f648d3f8f71225b38a9bbf6c28dee168d76b274125ef4596d1959dfa622861848b2bf713fda12601",
|
||||
"y": "0x0308f950d4321be5e06a751aee088d09da8fdb36c4bc6b801d529e43250f3e90d55c8d9fea6d3762912f92866bd89d02"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x17f78156bb227c0fefb04a3d58f7315cd7eb696e52b7efeef9fa82171e8c6d8dd265f7fcffa8e6e734c6cc2611363e80",
|
||||
"y": "0x000a6e05625536b8cc8fff02ebe2ff0a6f137d5f0b644afae033fdbec60e41e281383e97333a342e3492baeddf637e36"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x191f209664bd324339cbbc4e3afe7e713fd47e57c476ff8c224bef6b59745384ec6f15edd912c56336299733b9650f3a",
|
||||
"y": "0x108c7a3b7d2e6c83e1e9bbcb03960a3b9115d871cce130d8622576339bbb3fd02565de45b06620d557e9244c4a4944d8"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x130bc594dc2a536afba69280db5d4675051f5eb3a5d147290874f53fd275acddf4faca77145fb23aa6d9357a00e0a4f4",
|
||||
"0x02e5a19a37149c402114906448c3f7558125edbfce8c5241056d32bac7980d95d820ecf23dbfa5eafa9c4f8c3dbb4b70"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
{
|
||||
"L": "0x40",
|
||||
"Z": "0x0,0x1",
|
||||
"ciphersuite": "BLS12381G2_XMD:SHA-256_SVDW_RO_",
|
||||
"curve": "BLS12381G2",
|
||||
"dst": "BLS12381G2_XMD:SHA-256_SVDW_RO_TESTGEN",
|
||||
"expand": "XMD",
|
||||
"field": {
|
||||
"m": "0x2",
|
||||
"p": "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab"
|
||||
},
|
||||
"hash": "sha256",
|
||||
"k": "0x80",
|
||||
"map": {
|
||||
"name": "SVDW"
|
||||
},
|
||||
"randomOracle": true,
|
||||
"vectors": [
|
||||
{
|
||||
"P": {
|
||||
"x": "0x1247e409b2a18aa704b37c891ad429af1e81a7d03d97c1651d072a63acc5585967939adfe6b41e608c4cf1444be4ebaf,0x1379e10a574e45e6e8ffc3d403bf975984237d4e0dd350a2209ee5025b738827620301e71bfe4449af7b9ea2a8fc0464",
|
||||
"y": "0x0f171ce60457b1bf85847e48469e8a50e28b26e126201664b2eb962abe38c0eb2e1e84c953521c6e8cd82fe25fca520a,0x02663ec2937ebd48810bbd17d88f03e9abea73025d7a59c5b7a0db80ac3bde5b1b6fb55f825686d170702f9a0b354e7b"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0c518ce5d2e9e96a19ce4737e4f60ef6273231e706540bca662697e16303f0066ace3544d272492b5c01ab2a20d08d0f,0x132f304e07b3a827b26eacbb0e3af39a32b260d95ca86e63aa2f8d0ba99b6f6ee5f15cbcd3afee9f9081879d5709c565",
|
||||
"y": "0x021575725c8fb5107d5ad64c1f178d923e19203590dcb1b509af82ffbf367b9c4cccb89301f0aea987dc788d44547f55,0x00a2ba2f88f654fcde8197b94d1605c24515a5cb7823288d13760cc23e49c424db9a08d37e1e55c425f1334894ce0125"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0fe40888ce7a67c99ba37194b2e62c77c9d2fb5d18d71faf81a4084b8edc805c30776a46dbe6b749ea170868bf4faadc,0x1918a1f78646dc0451cfdd37725fa080cfb9d9ea473b0f58a9929b7b31ab8da8547346a091a7e2b3d073e3cc38ce0b12",
|
||||
"y": "0x152eebe67adbeb41ccc8a03926448c9dbe6692254203c6378f00a7e5bd56acdbde4ab9e8d1809aaf405bbe5ab395e385,0x070cc5025c561c1dfcca06ba88853300d4314db466e187e60cd1915c735bf2c6dc3bd0903d988d7d9b3b9e46dbe3ee1d"
|
||||
},
|
||||
"msg": "",
|
||||
"u": [
|
||||
"0x011a69c0b78b463729c1e9e6c7a543d4c10e1880a6a5c92748db6708c7492b170912c46abf43a50d6af40345ceeb16db,0x1216c67865d83536ff57ed9480ac3ee581b7edc25860f73e2ed967c40f5647a4bc25d54538e14a0404d550acdbe8056f",
|
||||
"0x190bfaa5cd1654a6f71bcff0265236fc73a1a8c72f637b13fa9e3b7c69ad7a82de6419893f1a4f46b0aefeee08a5f877,0x001af2852d68aefb42258ae84e63fa04f45e0603a54d245882a2e2373484d49277d885983e300dcc8a7632c476f6654e"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x14dc75415d6482bae5db292316e9fce2a9ac7c9591222ba12ef70fe4ad5ddd2a95b696857234d9114812394b60f8871a,0x121be08f8e5ebfd6bd080250aac7cde4ceb5672b5fd470bd8a92164e7b7fef93631da6bb514892cf913e5ba6bba00adc",
|
||||
"y": "0x024233ce610d08957a91a989495af524ca3c4409e7f2fd38164ee7e76fc9694338370d90d2150f2e602bec35eda9e22d,0x00bd976560d390194db01606af280f74b6b4282d4bf3f6ed2718ac67ebe1507e52eab74fbdfdfdf0092c0d9a106969e5"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x0d0c596608ea6ae9b18b6e55d21663933db8256234f5c2b3b3479b7bfc490f7828c98f883e1a63c58cdc0fc028d4661a,0x153ca080b13248f5f6b863a409ff2df352041c19f353f72dd0f3233a1ae2fdeea6e31a93a7a290a99a56a7cfe8448ff1",
|
||||
"y": "0x012454a1f725b9b478ebdfaf0e56870fa99a15ff3e003c21a155042b44a39cc3a36421b7e11112da0a43e8528b15f820,0x0116d64afa9e422e1d966a93b0e3a0e40c4e34dc34a4c7b2f71e1520812f401baa979c5c62e67e4adf15ce4a507f7db1"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x0083e95f0c761f7303c593bfacddf994635f12704cec7d2a1e8ce9ce3186b20acad0a8f63ff94cefd67400c72751fa29,0x198853939c488f8d8e5bf0839aff9aee5513205a775a541ea3fbce3ebc27395f811147593a7b51e4b1874cf14c8a5c59",
|
||||
"y": "0x145f9d0d73567c83a5fccb0b05afc9585d302e1fe2e60fa91c673e12a2e760e74c64eb88c7747030b1b50ec8b8111d7f,0x102641fb2d3f4866926783d40d04d3b0f5a6ec4f4aab132053499b50922a29dce7f535502e4038b1a8ce7ae79d2faacd"
|
||||
},
|
||||
"msg": "abc",
|
||||
"u": [
|
||||
"0x08dde2c4f9306a44a460f832d9153c2eccbb8588a7ac35b8476b006be691ce1b340486a56f180be2a022f3cee642ea2a,0x05141fedc77647e15b94c7dd50010f0ab062f44dfb25bc4a127f94aeede48e4f5782c83a29c98295d27210c7ff74ba6c",
|
||||
"0x0f6d3efdc539af5edd8b806160272c9699ab924f37d161509d4cfa5a589d796d7b05b78fe5994bd082aa6765ef468421,0x00ba433ee89bbbb64364644c770149bba3d8fc6de84e2c057fe7ea027fab92261a40a20214f4da43375f5d55d5c74361"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x185cad2867dc5c11b0f42842adc2bc16ebaf95c761b5d26541a089c19f54e5039ad911b2667de073c26d01911d203d58,0x05e0ac4290a0620d1b5d20b8b98ace6d1b198273e05a36daa18b3c591ded4bfebbff7a8bb3bc2b9de009d5e9d0a78a12",
|
||||
"y": "0x025525d91f16601d32379f4d5cba4a256ad84d40423ef294dabdf73e351f86b583c848f974899815a40c569465c68c7f,0x09aa43a981af5885a0f86a1b9a143abbc1570d1bf342f8b506ff9f9bcc15dbb12a8ac062f7e37e06b90881b8cbc1f4e9"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x10319d966d19e9017cd0be3c551e4001c3e9d75a25e1700c3443b7756ae94fe1d442d6b3839d505682fa82269c7e910e,0x1860d1ab41d2ffe81a587e6919b21348bb437a8ea88e932525c803d5c1ee68bf47f515c445ae102cde5cf5569de63970",
|
||||
"y": "0x133af9a9ac415000202b1a1fc258aa773902a937fa09af32267cfcf32baaa002eb80b1aefa92ee759867cd9222c55ea6,0x07abb300d3f1a89f91e55b1abf628f83dd967a97d81d8938c876060455abb77dfc9ce41c5a0beb99e9feb684b9f18d4e"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x14f0b1e5f3d5b113514a1ce6eb17de28d84fb686ed72b9a3091a9be545977acaae253b65268c1057abccb2c47381a7b2,0x136ba736cfc5c767b74be4814e647516ef71e512623d481ec17c6d89d65f536ed679900bf8050bed93a5833df4c032f5",
|
||||
"y": "0x10e035eb449a1ebbc06431ee73251c7a94b96f83102bacb8c3a6bbacf32486bd6715dcfdd1c1a5ac0058f4fd7930e22b,0x06e89c91fe9ed6c5f6184c5e3766d7393002d06cdffe4b084a5cb4fd4ed71fa5f82590927ff983ea84cb7229a688d071"
|
||||
},
|
||||
"msg": "abcdef0123456789",
|
||||
"u": [
|
||||
"0x11cb86b80f5715c34ebbbfd2b535a765de4e5e6de719f804b86e5d0e7415f00a2123397e06a9fe969ef09cd84c4d0146,0x10c642ecf452b47f5dcff39e3ab10d9b240d9511837f2d6eb152f86b2960a2fb8350f9d0387f8a8899a58bd2c5691b92",
|
||||
"0x05c8d547790510132e87b818de01994a7dcccbafcccffbfe38ada5ba2573eda9308f4bad0fb1beb79b12c7329c18766b,0x11931693de41195bec4acae1beea0b9b2bf2e55902bebb8f08da8036989efacda79b275d0a5b06d42905826f99e05dfa"
|
||||
]
|
||||
},
|
||||
{
|
||||
"P": {
|
||||
"x": "0x19925c3d247512c84e3ced29498eada349e82ee96689d5977e627c5b75a904800d789d1848a0551fd1d8b300efef8663,0x07a1af1c92c0723656bb94b0ebae40d4c3e952b32473964710b9b9602b8dbd4e80a8950208fc2cb449daea25af54f138",
|
||||
"y": "0x179c7387bd605a594a778eb6305ba2d96d69383104c41fd6c5b1517b1728959e78fef47260863497292e056b745d847a,0x174fd14a9224fc3a7fa9019b7c344557f67b98f40c4fe7cefffd99a57aac611de1456988947cbfa37728426d9eeaea52"
|
||||
},
|
||||
"Q0": {
|
||||
"x": "0x15e925b755b1d7ffadb242ae97d8f3826a46b6cebb87fc5afafa75a041dce9dab92daff7c76a27fdaabee83b58302e7c,0x198976a1d24b585148aa5331536a8d9747584d2cd86bb424426c4ae7234aed4afb060f1e09d1ab36bbf7a439fc8da6d1",
|
||||
"y": "0x16cda73b5ec6993795f393f19129e0f4e3de82f803ca55f21962162ac599e48e39f0ff78e8159a05d0eceabc6cf01291,0x05b52d7a1673bb8168c3bbad3d3652abca5d7e0027a667914668772ca6ca7e130b07ae7ea6b16695ed53e83789ca3a50"
|
||||
},
|
||||
"Q1": {
|
||||
"x": "0x031241efa254ea61dd01d9ac138fa90b5b5a60b1d37bdac7984f1a038e867acb39f10d616b012b2d64f2a907ccf7a2c5,0x10e01a11fd5e4af0c2f7d373dfd0b565055680087068bfe3d9694b443a76a472c409fd57e86647848615ed54bf85fac6",
|
||||
"y": "0x173cec16ebaf7dc61a0c3fadd3a50bc19362dddfe166c6ff7a84443c04659c096be4982b3db1d7bb26ae16af4bfb532f,0x13e3154a7eee424063ec3826c681675942bd36b9f22898547414420bd69ba4e273090d4722297f6e5ba2729fba8cabd9"
|
||||
},
|
||||
"msg": "a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"u": [
|
||||
"0x1412f7dcbbd4b37d2818e3174f2e51c6767b4d93501208d905d625a6decfd1253c626575c44b838cd8801653909fa3a1,0x17bb0ac3a973bf8d3663102459b8dca358d9b971ebc700126f11110c83f644f0ac5a86f1c7cd6babceb1f3705447665a",
|
||||
"0x0eaa03f98f9aa539262275d8862ce341537228572ea46dcd6e9e8662bd7f986948ddab6cf0594faa7b417b772ec96177,0x0fdb46860616bdbd8faff9859ae8d92f282f9633a4b5050c924d711f1b32a6cc20f431c207d47d66dd27fb6604c871b0"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -12,15 +12,13 @@ import
|
||||
# 3rd party
|
||||
pkg/jsony,
|
||||
# Internals
|
||||
../../constantine/platforms/abstractions,
|
||||
../../constantine/math/config/curves,
|
||||
../../constantine/math/extension_fields,
|
||||
../../constantine/math/io/[io_bigints, io_ec],
|
||||
../../constantine/math/elliptic/[
|
||||
ec_shortweierstrass_affine,
|
||||
ec_shortweierstrass_projective],
|
||||
../../constantine/hash_to_curve/hash_to_curve,
|
||||
../../constantine/hashes
|
||||
../constantine/platforms/abstractions,
|
||||
../constantine/math/config/curves,
|
||||
../constantine/math/extension_fields,
|
||||
../constantine/math/io/[io_bigints, io_ec],
|
||||
../constantine/math/ec_shortweierstrass,
|
||||
../constantine/hash_to_curve/hash_to_curve,
|
||||
../constantine/hashes
|
||||
|
||||
# Serialization
|
||||
# --------------------------------------------------------------------------
|
||||
@ -65,7 +63,7 @@ type
|
||||
|
||||
const
|
||||
TestVectorsDir* =
|
||||
currentSourcePath.rsplit(DirSep, 1)[0] / "vectors"
|
||||
currentSourcePath.rsplit(DirSep, 1)[0] / "protocol_hash_to_curve"
|
||||
|
||||
proc parseHook*(src: string, pos: var int, value: var ECP_ShortW_Aff) =
|
||||
# Note when nim-serialization was used:
|
||||
@ -138,6 +136,41 @@ proc run_hash_to_curve_test(
|
||||
|
||||
doAssert: bool(P == P_ref)
|
||||
|
||||
proc run_hash_to_curve_svdw_test(
|
||||
EC: typedesc,
|
||||
spec_version: string,
|
||||
filename: string
|
||||
) =
|
||||
|
||||
when EC.G == G1:
|
||||
const G1_or_G2 = "G1"
|
||||
else:
|
||||
const G1_or_G2 = "G2"
|
||||
let vec = loadVectors(HashToCurveTest[ECP_ShortW_Aff[EC.F, EC.G]], filename)
|
||||
|
||||
let testSuiteDesc = "Hash to Curve " & $EC.F.C & " " & G1_or_G2 & " - official specs " & spec_version & " test vectors"
|
||||
|
||||
suite testSuiteDesc & " [" & $WordBitwidth & "-bit mode]":
|
||||
|
||||
doAssert vec.hash == "sha256"
|
||||
doAssert vec.k == "0x80" # 128
|
||||
|
||||
for i in 0 ..< vec.vectors.len:
|
||||
test "test " & $i & " - msg: \'" & vec.vectors[i].msg & "\'":
|
||||
var P{.noInit.}: EC
|
||||
sha256.hashToCurve_svdw(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = vec.vectors[i].msg,
|
||||
domainSepTag = vec.dst
|
||||
)
|
||||
|
||||
var P_ref: EC
|
||||
P_ref.fromAffine(vec.vectors[i].P)
|
||||
|
||||
doAssert: bool(P == P_ref)
|
||||
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "Hash-to-curve" & '\n'
|
||||
|
||||
@ -168,3 +201,16 @@ run_hash_to_curve_test(
|
||||
"v7",
|
||||
"tv_h2c_v7_BLS12_381_hash_to_G2_SHA256_SSWU_RO.json"
|
||||
)
|
||||
|
||||
# With the slower universal SVDW mapping instead of SSWU
|
||||
run_hash_to_curve_svdw_test(
|
||||
ECP_ShortW_Jac[Fp[BLS12_381], G1],
|
||||
"v7 (SVDW)",
|
||||
"tv_h2c_v7_BLS12_381_hash_to_G1_SHA256_SVDW_RO.json"
|
||||
)
|
||||
|
||||
run_hash_to_curve_svdw_test(
|
||||
ECP_ShortW_Jac[Fp2[BLS12_381], G2],
|
||||
"v7 (SVDW)",
|
||||
"tv_h2c_v7_BLS12_381_hash_to_G2_SHA256_SVDW_RO.json"
|
||||
)
|
57
tests/t_hash_to_curve_random.nim
Normal file
57
tests/t_hash_to_curve_random.nim
Normal file
@ -0,0 +1,57 @@
|
||||
# Constantine
|
||||
# Copyright (c) 2018-2019 Status Research & Development GmbH
|
||||
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
|
||||
# Licensed and distributed under either of
|
||||
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
# Standard library
|
||||
std/[unittest, times, os, strutils],
|
||||
# Internals
|
||||
../constantine/math/config/curves,
|
||||
../constantine/math/extension_fields,
|
||||
../constantine/math/ec_shortweierstrass,
|
||||
../constantine/hash_to_curve/hash_to_curve,
|
||||
../constantine/hashes,
|
||||
../constantine/math/curves/zoo_subgroups,
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe
|
||||
|
||||
const Iters = 6
|
||||
|
||||
# Random seed for reproducibility
|
||||
var rng: RngState
|
||||
let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32
|
||||
rng.seed(seed)
|
||||
echo "\n------------------------------------------------------\n"
|
||||
echo "Hash-to-curve (randomized) xoshiro512** seed: ", seed
|
||||
|
||||
proc testH2C_consistency[EC: ECP_ShortW](curve: typedesc[EC]) =
|
||||
var P{.noInit.}: EC
|
||||
let msg = rng.random_byte_seq(32)
|
||||
sha256.hashToCurve(
|
||||
k = 128,
|
||||
output = P,
|
||||
augmentation = "",
|
||||
message = msg,
|
||||
domainSepTag = "H2C-CONSTANTINE-TESTSUITE"
|
||||
)
|
||||
|
||||
doAssert bool isOnCurve(P.x, P.y, EC.G)
|
||||
doAssert bool isInSubgroup(P)
|
||||
|
||||
suite "Hash-to-curve produces points on curve and in correct subgroup":
|
||||
test "BLS12-381 G1":
|
||||
for i in 0 ..< Iters:
|
||||
testH2C_consistency(ECP_ShortW_Aff[Fp[BLS12_381], G1])
|
||||
test "BLS12-381 G2":
|
||||
for i in 0 ..< Iters:
|
||||
testH2C_consistency(ECP_ShortW_Aff[Fp2[BLS12_381], G2])
|
||||
test "BN254_Snarks G1":
|
||||
for i in 0 ..< Iters:
|
||||
testH2C_consistency(ECP_ShortW_Aff[Fp[BN254_Snarks], G1])
|
||||
test "BN254_Snarks G2":
|
||||
for i in 0 ..< Iters:
|
||||
testH2C_consistency(ECP_ShortW_Aff[Fp2[BN254_Snarks], G2])
|
@ -7,12 +7,11 @@
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
|
||||
import
|
||||
../../constantine/hashes,
|
||||
../../constantine/hash_to_curve/h2c_hash_to_field,
|
||||
../../constantine/math/config/[curves_declaration, type_ff],
|
||||
../../constantine/math/extension_fields/towers,
|
||||
|
||||
../../constantine/math/io/[io_fields, io_extfields],
|
||||
../constantine/hashes,
|
||||
../constantine/hash_to_curve/h2c_hash_to_field,
|
||||
../constantine/math/config/[curves_declaration, type_ff],
|
||||
../constantine/math/extension_fields/towers,
|
||||
../constantine/math/io/[io_fields, io_extfields],
|
||||
|
||||
# Third-party
|
||||
stew/byteutils
|
Loading…
x
Reference in New Issue
Block a user