mirror of
https://github.com/codex-storage/constantine.git
synced 2025-01-27 11:04:51 +00:00
Fuzz Fix - Hash-To-Curve - Isogeny EC add non-fully-reduced input (#250)
* H2C: fix fuzz failure 2, non-fully reduced in isogeny EC addition * faster hashToG2 by using sparsity
This commit is contained in:
parent
b7687ddc4a
commit
d69c7bf8e9
@ -483,7 +483,7 @@ const testDesc: seq[tuple[path: string, useGMP: bool]] = @[
|
||||
# Hashing to elliptic curves
|
||||
# ----------------------------------------------------------
|
||||
("tests/t_hash_to_field.nim", false),
|
||||
# ("tests/t_hash_to_curve_random.nim", false),
|
||||
("tests/t_hash_to_curve_random.nim", false),
|
||||
("tests/t_hash_to_curve.nim", false),
|
||||
|
||||
# Protocols
|
||||
|
@ -133,12 +133,12 @@ func mapToCurve_svdw_fusedAdd[F; G: static Subgroup](
|
||||
## finite or extension field F
|
||||
## to an elliptic curve E
|
||||
## and add them
|
||||
var P0{.noInit.}, P1{.noInit.}: ECP_ShortW_Aff[F, G]
|
||||
P0.mapToCurve_svdw(u0)
|
||||
P1.mapToCurve_svdw(u1)
|
||||
var Q0{.noInit.}, Q1{.noInit.}: ECP_ShortW_Aff[F, G]
|
||||
Q0.mapToCurve_svdw(u0)
|
||||
Q1.mapToCurve_svdw(u1)
|
||||
|
||||
r.fromAffine(P0)
|
||||
r += P1
|
||||
r.fromAffine(Q0)
|
||||
r += Q1
|
||||
|
||||
func mapToCurve_sswu_fusedAdd[F; G: static Subgroup](
|
||||
r: var ECP_ShortW_Jac[F, G],
|
||||
@ -164,25 +164,24 @@ func mapToCurve_sswu_fusedAdd[F; G: static Subgroup](
|
||||
# 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]
|
||||
var Q0{.noInit.}, Q1{.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, sswu, G1, Aprime_E1))
|
||||
Q0.mapToIsoCurve_sswuG1_opt3mod4(u0)
|
||||
Q1.mapToIsoCurve_sswuG1_opt3mod4(u1)
|
||||
Q0.sum(Q0, Q1, 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, sswu, G2, Aprime_E2))
|
||||
Q0.mapToIsoCurve_sswuG2_opt9mod16(u0)
|
||||
Q1.mapToIsoCurve_sswuG2_opt9mod16(u1)
|
||||
Q0.sum(Q0, Q1, h2CConst(F.C, sswu, G2, Aprime_E2))
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
|
||||
# 2. Map from E'2 to E2
|
||||
r.h2c_isogeny_map(P0)
|
||||
r.h2c_isogeny_map(Q0)
|
||||
else:
|
||||
{.error: "Not implemented".}
|
||||
|
||||
|
@ -43,7 +43,7 @@ func isInf*(P: ECP_ShortW_Jac): SecretBool {.inline.} =
|
||||
##
|
||||
## Note: the jacobian coordinates equation is
|
||||
## Y² = X³ + aXZ⁴ + bZ⁶
|
||||
##
|
||||
##
|
||||
## When Z = 0 in the equation, it reduces to
|
||||
## Y² = X³
|
||||
## (yZ³)² = (xZ²)³ which is true for any x, y coordinates
|
||||
@ -209,6 +209,15 @@ template sumImpl[F; G: static Subgroup](
|
||||
# | Y₃ = R*(V-X₃)-S₁*HHH | Y₃ = M*(S-X₃)-YY*YY | | |
|
||||
# | Z₃ = Z₁*Z₂*H | Z₃ = Y₁*Z₁ | | |
|
||||
|
||||
# "when" static evaluation doesn't shortcut booleans :/
|
||||
# which causes issues when CoefA isn't an int but Fp or Fp2
|
||||
when CoefA is int:
|
||||
const CoefA_eq_zero = CoefA == 0
|
||||
const CoefA_eq_minus3 {.used.} = CoefA == -3
|
||||
else:
|
||||
const CoefA_eq_zero = false
|
||||
const CoefA_eq_minus3 = false
|
||||
|
||||
var Z1Z1 {.noInit.}, U1 {.noInit.}, S1 {.noInit.}, H {.noInit.}, R {.noinit.}: F
|
||||
|
||||
block: # Addition-only, check for exceptional cases
|
||||
@ -218,7 +227,7 @@ template sumImpl[F; G: static Subgroup](
|
||||
S1 *= P.y # S₁ = Y₁*Z₂³
|
||||
U1.prod(P.x, Z2Z2) # U₁ = X₁*Z₂²
|
||||
|
||||
Z1Z1.square(P.z, skipFinalSub = true)
|
||||
Z1Z1.square(P.z, skipFinalSub = not CoefA_eq_minus3)
|
||||
S2.prod(P.z, Z1Z1, skipFinalSub = true)
|
||||
S2 *= Q.y # S₂ = Y₂*Z₁³
|
||||
U2.prod(Q.x, Z1Z1) # U₂ = X₂*Z₁²
|
||||
@ -248,15 +257,6 @@ template sumImpl[F; G: static Subgroup](
|
||||
V_or_S *= HH_or_YY # V = U₁*HH (add) or S = X₁*YY (dbl)
|
||||
|
||||
block: # Compute M for doubling
|
||||
# "when" static evaluation doesn't shortcut booleans :/
|
||||
# which causes issues when CoefA isn't an int but Fp or Fp2
|
||||
when CoefA is int:
|
||||
const CoefA_eq_zero = CoefA == 0
|
||||
const CoefA_eq_minus3 {.used.} = CoefA == -3
|
||||
else:
|
||||
const CoefA_eq_zero = false
|
||||
const CoefA_eq_minus3 = false
|
||||
|
||||
when CoefA_eq_zero:
|
||||
var a {.noInit.} = H
|
||||
var b {.noInit.} = HH_or_YY
|
||||
@ -289,14 +289,13 @@ template sumImpl[F; G: static Subgroup](
|
||||
var b{.noInit.} = HH_or_YY
|
||||
a.ccopy(P.x, isDbl)
|
||||
b.ccopy(P.x, isDbl)
|
||||
HHH_or_Mpre.prod(a, b, true) # HHH or X₁²
|
||||
HHH_or_Mpre.prod(a, b) # HHH or X₁²
|
||||
|
||||
# Assuming doubling path
|
||||
a.square(HHH_or_Mpre, skipFinalSub = true)
|
||||
a *= HHH_or_Mpre # a = 3X₁²
|
||||
b.square(Z1Z1)
|
||||
# b.mulCheckSparse(CoefA) # TODO: broken static compile-time type inference
|
||||
b *= CoefA # b = αZZ, with α the "a" coefficient of the curve
|
||||
b.mulCheckSparse(CoefA) # b = αZZ, with α the "a" coefficient of the curve
|
||||
|
||||
a += b
|
||||
a.div2()
|
||||
@ -430,6 +429,17 @@ func madd*[F; G: static Subgroup](
|
||||
# | Z₃ = Z₁*Z₂*H | Z₃ = Y₁*Z₁ | | |
|
||||
#
|
||||
# For mixed adddition we just set Z₂ = 1
|
||||
|
||||
# "when" static evaluation doesn't shortcut booleans :/
|
||||
# which causes issues when CoefA isn't an int but Fp or Fp2
|
||||
const CoefA = F.C.getCoefA()
|
||||
when CoefA is int:
|
||||
const CoefA_eq_zero = CoefA == 0
|
||||
const CoefA_eq_minus3 {.used.} = CoefA == -3
|
||||
else:
|
||||
const CoefA_eq_zero = false
|
||||
const CoefA_eq_minus3 = false
|
||||
|
||||
var Z1Z1 {.noInit.}, U1 {.noInit.}, S1 {.noInit.}, H {.noInit.}, R {.noinit.}: F
|
||||
|
||||
block: # Addition-only, check for exceptional cases
|
||||
@ -437,7 +447,7 @@ func madd*[F; G: static Subgroup](
|
||||
U1 = P.x
|
||||
S1 = P.y
|
||||
|
||||
Z1Z1.square(P.z, skipFinalSub = true)
|
||||
Z1Z1.square(P.z, skipFinalSub = not CoefA_eq_minus3)
|
||||
S2.prod(P.z, Z1Z1, skipFinalSub = true)
|
||||
S2 *= Q.y # S₂ = Y₂*Z₁³
|
||||
U2.prod(Q.x, Z1Z1) # U₂ = X₂*Z₁²
|
||||
@ -467,16 +477,6 @@ func madd*[F; G: static Subgroup](
|
||||
V_or_S *= HH_or_YY # V = U₁*HH (add) or S = X₁*YY (dbl)
|
||||
|
||||
block: # Compute M for doubling
|
||||
# "when" static evaluation doesn't shortcut booleans :/
|
||||
# which causes issues when CoefA isn't an int but Fp or Fp2
|
||||
const CoefA = F.C.getCoefA()
|
||||
when CoefA is int:
|
||||
const CoefA_eq_zero = CoefA == 0
|
||||
const CoefA_eq_minus3 {.used.} = CoefA == -3
|
||||
else:
|
||||
const CoefA_eq_zero = false
|
||||
const CoefA_eq_minus3 = false
|
||||
|
||||
when CoefA_eq_zero:
|
||||
var a {.noInit.} = H
|
||||
var b {.noInit.} = HH_or_YY
|
||||
@ -509,14 +509,13 @@ func madd*[F; G: static Subgroup](
|
||||
var b{.noInit.} = HH_or_YY
|
||||
a.ccopy(P.x, isDbl)
|
||||
b.ccopy(P.x, isDbl)
|
||||
HHH_or_Mpre.prod(a, b, true) # HHH or X₁²
|
||||
HHH_or_Mpre.prod(a, b) # HHH or X₁²
|
||||
|
||||
# Assuming doubling path
|
||||
a.square(HHH_or_Mpre, skipFinalSub = true)
|
||||
a *= HHH_or_Mpre # a = 3X₁²
|
||||
b.square(Z1Z1)
|
||||
# b.mulCheckSparse(CoefA) # TODO: broken static compile-time type inference
|
||||
b *= CoefA # b = αZZ, with α the "a" coefficient of the curve
|
||||
b.mulCheckSparse(CoefA) # b = αZZ, with α the "a" coefficient of the curve
|
||||
|
||||
a += b
|
||||
a.div2()
|
||||
|
@ -1440,11 +1440,11 @@ func mul_sparse_by_x0*(a: var QuadraticExt, sparseB: QuadraticExt) =
|
||||
a.mul_sparse_by_x0(a, sparseB)
|
||||
|
||||
template mulCheckSparse*(a: var QuadraticExt, b: QuadraticExt) =
|
||||
when b.isOne().bool:
|
||||
when isOne(b).bool:
|
||||
discard
|
||||
elif b.isMinusOne().bool:
|
||||
elif isMinusOne(b).bool:
|
||||
a.neg()
|
||||
elif b.c0.isZero().bool and b.c1.isOne().bool:
|
||||
elif isZero(c0(b)).bool and isOne(c1(b)).bool:
|
||||
var t {.noInit.}: type(a.c0)
|
||||
when fromComplexExtension(b):
|
||||
t.neg(a.c1)
|
||||
@ -1454,7 +1454,7 @@ template mulCheckSparse*(a: var QuadraticExt, b: QuadraticExt) =
|
||||
t.prod(a.c1, NonResidue)
|
||||
a.c1 = a.c0
|
||||
a.c0 = t
|
||||
elif b.c0.isZero().bool and b.c1.isMinusOne().bool:
|
||||
elif isZero(c0(b)).bool and isMinusOne(c1(b)).bool:
|
||||
var t {.noInit.}: type(a.c0)
|
||||
when fromComplexExtension(b):
|
||||
t = a.c1
|
||||
@ -1464,9 +1464,9 @@ template mulCheckSparse*(a: var QuadraticExt, b: QuadraticExt) =
|
||||
t.prod(a.c1, NonResidue)
|
||||
a.c1.neg(a.c0)
|
||||
a.c0.neg(t)
|
||||
elif b.c0.isZero().bool:
|
||||
elif isZero(c0(b)).bool:
|
||||
a.mul_sparse_by_0y(b)
|
||||
elif b.c1.isZero().bool:
|
||||
elif isZero(c1(b)).bool:
|
||||
a.mul_sparse_by_x0(b)
|
||||
else:
|
||||
a *= b
|
||||
|
@ -16,6 +16,7 @@ import
|
||||
../constantine/hash_to_curve/hash_to_curve,
|
||||
../constantine/hashes,
|
||||
../constantine/math/constants/zoo_subgroups,
|
||||
../constantine/math/io/io_ec,
|
||||
# Test utilities
|
||||
../helpers/prng_unsafe
|
||||
|
||||
@ -54,4 +55,36 @@ suite "Hash-to-curve produces points on curve and in correct subgroup":
|
||||
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])
|
||||
testH2C_consistency(ECP_ShortW_Aff[Fp2[BN254_Snarks], G2])
|
||||
|
||||
proc testH2C_guidovranken_fuzz_failure_2() =
|
||||
# From Guido Vranken differential fuzzing
|
||||
# Summing elliptic curve on an isogeny was mistakenly not fully reducing HHH_or_Mpre
|
||||
let msg = [
|
||||
uint8 0xa7, 0x1b, 0x0a, 0x38, 0xd4, 0x09, 0x2b, 0x3b,
|
||||
0xdc, 0x9e, 0x75, 0x0a, 0x27, 0x0a, 0xd5, 0xdd,
|
||||
0x16, 0x6f, 0x32, 0x5c, 0x16, 0xf5, 0x6d, 0x2f,
|
||||
0x87, 0xbb, 0x6b, 0xf5, 0xd2]
|
||||
let dst = [
|
||||
uint8 0x5a, 0x59, 0xae, 0x59, 0x04, 0x8a, 0x29, 0x0f,
|
||||
0x9a, 0xc1, 0x80, 0x26, 0xba, 0x6d, 0xd8, 0x7f,
|
||||
0x54, 0xf0, 0x5a, 0x01, 0x49, 0xad, 0x2b, 0x95,
|
||||
0xfe]
|
||||
let aug = [
|
||||
uint8 0x70, 0x20, 0xde, 0x7c, 0x51, 0x88, 0x88, 0x54,
|
||||
0xf1, 0xaf, 0xa5, 0x06, 0x78, 0x80, 0xde, 0xf0,
|
||||
0x0d, 0xdf]
|
||||
|
||||
var r{.noInit}: ECP_ShortW_Jac[Fp[BLS12_381], G1]
|
||||
sha256.hashToCurve(128, r, aug, msg, dst)
|
||||
|
||||
let expected = ECP_ShortW_Jac[Fp[BLS12_381], G1].fromHex(
|
||||
x = "0x48f2bbee30aa236feaa7fb924d8a3de3090ff160f9972a8afda302bd248248527dcc59ce195cd5f5a1488417cfc64cc",
|
||||
y = "0xe91b0a3cdea4981741791c8e9b4287d2f693c6626d8e4408ecaaa473e6ff2f691f5f23f8b7b46bdf3560e7cca67e5bc"
|
||||
)
|
||||
|
||||
doAssert bool(r == expected)
|
||||
|
||||
suite "Hash-to-curve anti-regression":
|
||||
test "BLS12-381 G1 - Fuzzing Failure 2":
|
||||
testH2C_guidovranken_fuzz_failure_2()
|
Loading…
x
Reference in New Issue
Block a user