diff --git a/constantine/arithmetic/finite_fields.nim b/constantine/arithmetic/finite_fields.nim index c4cd12f..04be32d 100644 --- a/constantine/arithmetic/finite_fields.nim +++ b/constantine/arithmetic/finite_fields.nim @@ -115,6 +115,10 @@ func isOne*(a: Fp): SecretBool {.inline.} = ## Constant-time check if one a.mres == Fp.C.getMontyOne() +func isMinusOne*(a: Fp): SecretBool {.inline.} = + ## Constant-time check if -1 (mod p) + a.mres == Fp.C.getMontyPrimeMinus1() + func setZero*(a: var Fp) {.inline.} = ## Set ``a`` to zero a.mres.setZero() diff --git a/constantine/arithmetic/finite_fields_square_root.nim b/constantine/arithmetic/finite_fields_square_root.nim index 7649bf5..7a23cf3 100644 --- a/constantine/arithmetic/finite_fields_square_root.nim +++ b/constantine/arithmetic/finite_fields_square_root.nim @@ -31,7 +31,7 @@ func isSquare*[C](a: Fp[C]): SecretBool {.inline.} = # as we assume that var xi {.noInit.} = a # TODO: is noInit necessary? see https://github.com/mratsim/constantine/issues/21 xi.powUnsafeExponent(C.getPrimeMinus1div2_BE()) - result = not(xi.mres == C.getMontyPrimeMinus1()) + result = not(xi.isMinusOne()) # xi can be: # - 1 if a square # - 0 if 0 @@ -40,7 +40,7 @@ func isSquare*[C](a: Fp[C]): SecretBool {.inline.} = doAssert: bool( xi.isZero or xi.isOne or - xi.mres == C.getMontyPrimeMinus1() + xi.isMinusOne() ) # Specialized routine for p ≡ 3 (mod 4) @@ -91,7 +91,7 @@ func sqrt_invsqrt_if_square_p3mod4[C](sqrt, invsqrt: var Fp[C], a: Fp[C]): Secre sqrt_invsqrt_p3mod4(sqrt, invsqrt, a) var euler {.noInit.}: Fp[C] euler.prod(sqrt, invsqrt) - result = not(euler.mres == C.getMontyPrimeMinus1()) + result = not(euler.isMinusOne()) func sqrt_if_square_p3mod4[C](a: var Fp[C]): SecretBool {.inline.} = ## If ``a`` is a square, compute the square root of ``a`` @@ -131,7 +131,7 @@ func isSquare_tonelli_shanks[C]( for _ in 0 ..< e-1: r.square() # a^((q-1)/2) - result = not(r.mres == C.getMontyPrimeMinus1()) + result = not(r.isMinusOne()) # r can be: # - 1 if a square # - 0 if 0 @@ -140,7 +140,7 @@ func isSquare_tonelli_shanks[C]( doAssert: bool( r.isZero or r.isOne or - r.mres == C.getMontyPrimeMinus1() + r.isMinusOne() ) func sqrt_invsqrt_tonelli_shanks[C]( diff --git a/constantine/config/curves.nim b/constantine/config/curves.nim index 99de3c6..3bd5894 100644 --- a/constantine/config/curves.nim +++ b/constantine/config/curves.nim @@ -93,6 +93,13 @@ macro get_CNR_Fp2*(C: static Curve): untyped = ## if -2 is chosen as a quadratic non-residue 𝑗 = √-2 result = bindSym($C & "_nonresidue_cube_fp2") +macro getEmbeddingDegree*(C: static Curve): untyped = + ## Returns the prime embedding degree, + ## i.e. the smallest k such that r|𝑝^𝑘−1 + ## equivalently 𝑝^𝑘 ≡ 1 (mod r) + ## with r the curve order and p its field modulus + result = bindSym($C & "_embedding_degree") + macro getSexticTwist*(C: static Curve): untyped = ## Returns if D-Twist or M-Twist result = bindSym($C & "_sexticTwist") diff --git a/constantine/config/curves_declaration.nim b/constantine/config/curves_declaration.nim index 68b781a..33b14e3 100644 --- a/constantine/config/curves_declaration.nim +++ b/constantine/config/curves_declaration.nim @@ -86,6 +86,7 @@ declareCurves: nonresidue_quad_fp: -1 # -1 is not a square in 𝔽p nonresidue_cube_fp2: (1, 1) # 1+𝑖 1+𝑖 is not a cube in 𝔽p² + embedding_degree: 12 sexticTwist: D_Twist sexticNonResidue_fp2: (1, 1) # 1+𝑖 @@ -105,6 +106,7 @@ declareCurves: nonresidue_quad_fp: -1 # -1 is not a square in 𝔽p nonresidue_cube_fp2: (9, 1) # 9+𝑖 9+𝑖 is not a cube in 𝔽p² + embedding_degree: 12 sexticTwist: D_Twist sexticNonResidue_fp2: (9, 1) # 9+𝑖 @@ -137,6 +139,7 @@ declareCurves: nonresidue_quad_fp: -5 # -5 is not a square in 𝔽p nonresidue_cube_fp2: (0, 1) # √-5 √-5 is not a cube in 𝔽p² + embedding_degree: 12 sexticTwist: D_Twist sexticNonResidue_fp2: (0, 1) # √-5 @@ -157,6 +160,7 @@ declareCurves: nonresidue_quad_fp: -1 # -1 is not a square in 𝔽p nonresidue_cube_fp2: (1, 1) # 1+𝑖 1+𝑖 is not a cube in 𝔽p² + embedding_degree: 12 sexticTwist: M_Twist sexticNonResidue_fp2: (1, 1) # 1+𝑖 @@ -181,5 +185,6 @@ declareCurves: nonresidue_quad_fp: -4 # -4 is not a square in 𝔽p nonresidue_cube_fp2: (0, 1) # -4 is not a cube in 𝔽p² + embedding_degree: 6 sexticTwist: M_Twist sexticNonResidue_fp2: (0, 1) # -4 diff --git a/constantine/config/curves_parser.nim b/constantine/config/curves_parser.nim index 37174b8..09846fe 100644 --- a/constantine/config/curves_parser.nim +++ b/constantine/config/curves_parser.nim @@ -106,6 +106,7 @@ type order: NimNode # nnkStrLit (hex) orderBitwidth: NimNode # nnkIntLit + embedding_degree: int sexticTwist: SexticTwist sexticNonResidue_fp2: NimNode # nnkPar(nnkIntLit, nnkIntLit) @@ -174,6 +175,7 @@ proc parseCurveDecls(defs: var seq[CurveParams], curves: NimNode) = params.modulus = sectionVal elif sectionId.eqIdent"family": params.family = parseEnum[CurveFamily]($sectionVal) + elif sectionId.eqIdent"eq_form": params.eq_form = parseEnum[CurveEquationForm]($sectionVal) elif sectionId.eqIdent"coef_a": @@ -200,6 +202,9 @@ proc parseCurveDecls(defs: var seq[CurveParams], curves: NimNode) = params.nonresidue_quad_fp = sectionVal elif sectionId.eqIdent"nonresidue_cube_fp2": params.nonresidue_cube_fp2 = sectionVal + + elif sectionId.eqIdent"embedding_degree": + params.embedding_degree = sectionVal.intVal.int elif sectionId.eqIdent"sexticTwist": params.sexticTwist = parseEnum[SexticTwist]($sectionVal) elif sectionId.eqIdent"sexticNonResidue_fp2": @@ -294,6 +299,9 @@ proc genMainConstants(defs: var seq[CurveParams]): NimNode = exported($curve & "_coef_B"), curveDef.coef_B.getCoef(bitWidth) ) + + # Towering + # ----------------------------------------------- curveEllipticStmts.add newConstStmt( exported($curve & "_nonresidue_quad_fp"), curveDef.nonresidue_quad_fp @@ -302,6 +310,13 @@ proc genMainConstants(defs: var seq[CurveParams]): NimNode = exported($curve & "_nonresidue_cube_fp2"), curveDef.nonresidue_cube_fp2 ) + + # Pairing + # ----------------------------------------------- + curveEllipticStmts.add newConstStmt( + exported($curve & "_embedding_degree"), + newLit curveDef.embedding_degree + ) curveEllipticStmts.add newConstStmt( exported($curve & "_sexticTwist"), newLit curveDef.sexticTwist diff --git a/constantine/curves/bls12_377_frobenius.nim b/constantine/curves/bls12_377_frobenius.nim index af70278..fd039b1 100644 --- a/constantine/curves/bls12_377_frobenius.nim +++ b/constantine/curves/bls12_377_frobenius.nim @@ -14,9 +14,38 @@ import # Frobenius map - on extension fields # ----------------------------------------------------------------- -# c = (SNR^((p-1)/6)^coef). -# Then for frobenius(2): c * conjugate(c) -# And for frobenius(3): c² * conjugate(c) +# We start from base frobenius constant for a 12 embedding degree. +# with +# - a sextic twist, SNR being the Sextic Non-Residue. +# - coef being the Frobenius coefficient "ID" +# c = SNR^((p-1)/6)^coef +# +# On Fp2 frobenius(c) = conj(c) so we have +# For n=2, with n the number of Frobenius applications +# c2 = c * (c^p) = c * frobenius(c) = c * conj(c) +# c2 = (SNR * conj(SNR))^((p-1)/6)^coef) +# c2 = (norm(SNR))^((p-1)/6)^coef) +# For k=3 +# c3 = c * c2^p = c * frobenius(c2) = c * conj(c2) +# with conj(norm(SNR)) = norm(SNR) as a norm is strictly on the base field. +# c3 = (SNR * norm(SNR))^((p-1)/6)^coef) +# +# A more generic formula can be derived by observing that +# c3 = c * c2^p = c * (c * c^p)^p +# c3 = c * c^p * c^p² +# with 4, we have +# c4 = c * c3^p = c * (c * c^p * c^p²)^p +# c4 = c * c^p * c^p² * c^p³ +# with n we have +# cn = c * c^p * c^p² ... * c^p^(n-1) +# cn = c^(1+p+p² + ... + p^(n-1)) +# This is the sum of first n terms of a geometric series +# hence cn = c^((p^n-1)/(p-1)) +# We now expand c +# cn = SNR^((p-1)/6)^coef^((p^n-1)/(p-1)) +# cn = SNR^((p^n-1)/6)^coef +# cn = SNR^(coef * (p^n-1)/6) + const BLS12_377_FrobeniusMapCoefficients* = [ # frobenius(1) ----------------------- [Fp2[BLS12_377].fromHex( # SNR^((p-1)/6)^0 @@ -43,73 +72,130 @@ const BLS12_377_FrobeniusMapCoefficients* = [ "0xcd70cb3fc936348d0351d498233f1fe379531411832232f6648a9a9fc0b9c4e3e21b7467077c05853e2c1be0e9fc32", "0x0" )], + # frobenius(2) ----------------------- - [Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^0 + [Fp2[BLS12_377].fromHex( # SNR^((p^2-1)/6)^0 "0x1", "0x0" ), - Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^1 + Fp2[BLS12_377].fromHex( # SNR^((p^2-1)/6)^1 "0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002", "0x0" ), - Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^2 + Fp2[BLS12_377].fromHex( # SNR^((p^2-1)/6)^2 "0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001", "0x0" ), - Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^3 + Fp2[BLS12_377].fromHex( # SNR^((p^2-1)/6)^3 "0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000", "0x0" ), - Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^4 + Fp2[BLS12_377].fromHex( # SNR^((p^2-1)/6)^4 "0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e945779fffffffffffffffffffffff", "0x0" ), - Fp2[BLS12_377].fromHex( # norm(SNR)^((p-1)/6)^5 + Fp2[BLS12_377].fromHex( # SNR^((p^2-1)/6)^5 "0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e94577a00000000000000000000000", "0x0" )], + # frobenius(3) ----------------------- - [Fp2[BLS12_377].fromHex( # (SNR²)^((p-1)/6)^0 + [Fp2[BLS12_377].fromHex( # SNR^((p^3-1)/6)^0 "0x1", "0x0" ), - Fp2[BLS12_377].fromHex( # (SNR²)^((p-1)/6)^1 + Fp2[BLS12_377].fromHex( # SNR^((p^3-1)/6)^1 "0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63", "0x0" ), - Fp2[BLS12_377].fromHex( # (SNR²)^((p-1)/6)^2 + Fp2[BLS12_377].fromHex( # SNR^((p^3-1)/6)^2 "0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000", "0x0" ), - Fp2[BLS12_377].fromHex( # (SNR²)^((p-1)/6)^3 + Fp2[BLS12_377].fromHex( # SNR^((p^3-1)/6)^3 "0x4630059e5fd9200575d0e552278a89da1f40fdf62334cd620d1860769e389d7db2d8ea700d82721691ea130ec6e39e", "0x0" ), - Fp2[BLS12_377].fromHex( # (SNR²)^((p-1)/6)^4 + Fp2[BLS12_377].fromHex( # SNR^((p^3-1)/6)^4 "0x1", "0x0" ), - Fp2[BLS12_377].fromHex( # (SNR²)^((p-1)/6)^5 + Fp2[BLS12_377].fromHex( # SNR^((p^3-1)/6)^5 "0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63", "0x0" - )]] + )], +] # ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves # ----------------------------------------------------------------- # BLS12_377 is a D-Twist: psi1_coef1 = SNR^((p-1)/6) -# SNR^((p-1)/3) -const BLS12_377_FrobeniusPsi_psi1_coef2* = Fp2[BLS12_377].fromHex( +# SNR^(2(p-1)/6) +const BLS12_377_FrobeniusPsi_psi1_coef2* = Fp2[BLS12_377].fromHex( "0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002", "0x0" ) -# SNR^((p-1)/2) -const BLS12_377_FrobeniusPsi_psi1_coef3* = Fp2[BLS12_377].fromHex( +# SNR^(3(p-1)/6) +const BLS12_377_FrobeniusPsi_psi1_coef3* = Fp2[BLS12_377].fromHex( "0x1680a40796537cac0c534db1a79beb1400398f50ad1dec1bce649cf436b0f6299588459bff27d8e6e76d5ecf1391c63", "0x0" ) -# norm(SNR)^((p-1)/3) -const BLS12_377_FrobeniusPsi_psi2_coef2* = Fp2[BLS12_377].fromHex( +# SNR^(2(p^2-1)/6) +const BLS12_377_FrobeniusPsi_psi2_coef2* = Fp2[BLS12_377].fromHex( "0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001", "0x0" -) \ No newline at end of file +) +# SNR^(3(p^2-1)/6) +const BLS12_377_FrobeniusPsi_psi2_coef3* = Fp2[BLS12_377].fromHex( + "0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000", + "0x0" +) +# SNR^(2(p^3-1)/6) +const BLS12_377_FrobeniusPsi_psi3_coef2* = Fp2[BLS12_377].fromHex( + "0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000000", + "0x0" +) +# SNR^(3(p^3-1)/6) +const BLS12_377_FrobeniusPsi_psi3_coef3* = Fp2[BLS12_377].fromHex( + "0x4630059e5fd9200575d0e552278a89da1f40fdf62334cd620d1860769e389d7db2d8ea700d82721691ea130ec6e39e", + "0x0" +) +# SNR^(2(p^4-1)/6) +const BLS12_377_FrobeniusPsi_psi4_coef2* = Fp2[BLS12_377].fromHex( + "0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e945779fffffffffffffffffffffff", + "0x0" +) +# SNR^(3(p^4-1)/6) +const BLS12_377_FrobeniusPsi_psi4_coef3* = Fp2[BLS12_377].fromHex( + "0x1", + "0x0" +) + +# For a sextic twist +# - p ≡ 1 (mod 2) +# - p ≡ 1 (mod 3) +# +# psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg +# Recap, with ξ (xi) the sextic non-residue for D-Twist or 1/SNR for M-Twist +# psi_2 ≡ ξ^((p-1)/6)^2 ≡ ξ^((p-1)/3) +# psi_3 ≡ psi_2 * ξ^((p-1)/6) ≡ ξ^((p-1)/3) * ξ^((p-1)/6) ≡ ξ^((p-1)/2) +# +# In Fp² (i.e. embedding degree of 12, G2 on Fp2) +# - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol +# - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) +# - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test +# +# We have psi2_3 ≡ psi_3 * psi_3^p ≡ psi_3^(p+1) +# ≡ (ξ^(p-1)/2)^(p+1) (mod p²) +# ≡ ξ^((p-1)(p+1)/2) (mod p²) +# ≡ ξ^((p²-1)/2) (mod p²) +# And ξ^((p²-1)/2) ≡ -1 (mod p²) since ξ is a quadratic non-residue +# So psi2_3 ≡ -1 (mod p²) +# +# +# In Fp (i.e. embedding degree of 6, G2 on Fp) +# - Fermat's Little Theorem gives us a^(p-1) ≡ 1 (mod p) +# +# psi2_3 ≡ ξ^((p-1)(p+1)/2) (mod p) +# ≡ ξ^((p+1)/2)^(p-1) (mod p) as we have 2|p+1 +# ≡ 1 (mod p) by Fermat's Little Theorem diff --git a/constantine/curves/bls12_381_frobenius.nim b/constantine/curves/bls12_381_frobenius.nim index 01825a2..761ae96 100644 --- a/constantine/curves/bls12_381_frobenius.nim +++ b/constantine/curves/bls12_381_frobenius.nim @@ -14,9 +14,38 @@ import # Frobenius map - on extension fields # ----------------------------------------------------------------- -# c = (SNR^((p-1)/6)^coef). -# Then for frobenius(2): c * conjugate(c) -# And for frobenius(3): c² * conjugate(c) +# We start from base frobenius constant for a 12 embedding degree. +# with +# - a sextic twist, SNR being the Sextic Non-Residue. +# - coef being the Frobenius coefficient "ID" +# c = SNR^((p-1)/6)^coef +# +# On Fp2 frobenius(c) = conj(c) so we have +# For n=2, with n the number of Frobenius applications +# c2 = c * (c^p) = c * frobenius(c) = c * conj(c) +# c2 = (SNR * conj(SNR))^((p-1)/6)^coef) +# c2 = (norm(SNR))^((p-1)/6)^coef) +# For k=3 +# c3 = c * c2^p = c * frobenius(c2) = c * conj(c2) +# with conj(norm(SNR)) = norm(SNR) as a norm is strictly on the base field. +# c3 = (SNR * norm(SNR))^((p-1)/6)^coef) +# +# A more generic formula can be derived by observing that +# c3 = c * c2^p = c * (c * c^p)^p +# c3 = c * c^p * c^p² +# with 4, we have +# c4 = c * c3^p = c * (c * c^p * c^p²)^p +# c4 = c * c^p * c^p² * c^p³ +# with n we have +# cn = c * c^p * c^p² ... * c^p^(n-1) +# cn = c^(1+p+p² + ... + p^(n-1)) +# This is the sum of first n terms of a geometric series +# hence cn = c^((p^n-1)/(p-1)) +# We now expand c +# cn = SNR^((p-1)/6)^coef^((p^n-1)/(p-1)) +# cn = SNR^((p^n-1)/6)^coef +# cn = SNR^(coef * (p^n-1)/6) + const BLS12_381_FrobeniusMapCoefficients* = [ # frobenius(1) ----------------------- [Fp2[BLS12_381].fromHex( # SNR^((p-1)/6)^0 @@ -43,73 +72,130 @@ const BLS12_381_FrobeniusMapCoefficients* = [ "0x5b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116", "0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995" )], + # frobenius(2) ----------------------- - [Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^0 + [Fp2[BLS12_381].fromHex( # SNR^((p^2-1)/6)^0 "0x1", "0x0" ), - Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^1 + Fp2[BLS12_381].fromHex( # SNR^((p^2-1)/6)^1 "0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff", "0x0" ), - Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^2 + Fp2[BLS12_381].fromHex( # SNR^((p^2-1)/6)^2 "0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe", "0x0" ), - Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^3 + Fp2[BLS12_381].fromHex( # SNR^((p^2-1)/6)^3 "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa", "0x0" ), - Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^4 + Fp2[BLS12_381].fromHex( # SNR^((p^2-1)/6)^4 "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac", "0x0" ), - Fp2[BLS12_381].fromHex( # norm(SNR)^((p-1)/6)^5 + Fp2[BLS12_381].fromHex( # SNR^((p^2-1)/6)^5 "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad", "0x0" )], + # frobenius(3) ----------------------- - [Fp2[BLS12_381].fromHex( # (SNR²)^((p-1)/6)^0 + [Fp2[BLS12_381].fromHex( # SNR^((p^3-1)/6)^0 "0x1", "0x0" ), - Fp2[BLS12_381].fromHex( # (SNR²)^((p-1)/6)^1 + Fp2[BLS12_381].fromHex( # SNR^((p^3-1)/6)^1 "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2", "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09" ), - Fp2[BLS12_381].fromHex( # (SNR²)^((p-1)/6)^2 + Fp2[BLS12_381].fromHex( # SNR^((p^3-1)/6)^2 "0x0", "0x1" ), - Fp2[BLS12_381].fromHex( # (SNR²)^((p-1)/6)^3 + Fp2[BLS12_381].fromHex( # SNR^((p^3-1)/6)^3 "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2", "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2" ), - Fp2[BLS12_381].fromHex( # (SNR²)^((p-1)/6)^4 + Fp2[BLS12_381].fromHex( # SNR^((p^3-1)/6)^4 "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa", "0x0" ), - Fp2[BLS12_381].fromHex( # (SNR²)^((p-1)/6)^5 + Fp2[BLS12_381].fromHex( # SNR^((p^3-1)/6)^5 "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09", "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2" - )]] + )], +] # ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves # ----------------------------------------------------------------- # BLS12_381 is a M-Twist: psi1_coef1 = (1/SNR)^((p-1)/6) -# (1/SNR)^((p-1)/3) -const BLS12_381_FrobeniusPsi_psi1_coef2* = Fp2[BLS12_381].fromHex( +# (1/SNR)^(2(p-1)/6) +const BLS12_381_FrobeniusPsi_psi1_coef2* = Fp2[BLS12_381].fromHex( "0x0", "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad" ) -# (1/SNR)^((p-1)/2) -const BLS12_381_FrobeniusPsi_psi1_coef3* = Fp2[BLS12_381].fromHex( +# (1/SNR)^(3(p-1)/6) +const BLS12_381_FrobeniusPsi_psi1_coef3* = Fp2[BLS12_381].fromHex( "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2", "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09" ) -# norm((1/SNR))^((p-1)/3) -const BLS12_381_FrobeniusPsi_psi2_coef2* = Fp2[BLS12_381].fromHex( +# (1/SNR)^(2(p^2-1)/6) +const BLS12_381_FrobeniusPsi_psi2_coef2* = Fp2[BLS12_381].fromHex( "0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac", "0x0" -) \ No newline at end of file +) +# (1/SNR)^(3(p^2-1)/6) +const BLS12_381_FrobeniusPsi_psi2_coef3* = Fp2[BLS12_381].fromHex( + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa", + "0x0" +) +# (1/SNR)^(2(p^3-1)/6) +const BLS12_381_FrobeniusPsi_psi3_coef2* = Fp2[BLS12_381].fromHex( + "0x0", + "0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa" +) +# (1/SNR)^(3(p^3-1)/6) +const BLS12_381_FrobeniusPsi_psi3_coef3* = Fp2[BLS12_381].fromHex( + "0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09", + "0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2" +) +# (1/SNR)^(2(p^4-1)/6) +const BLS12_381_FrobeniusPsi_psi4_coef2* = Fp2[BLS12_381].fromHex( + "0x5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe", + "0x0" +) +# (1/SNR)^(3(p^4-1)/6) +const BLS12_381_FrobeniusPsi_psi4_coef3* = Fp2[BLS12_381].fromHex( + "0x1", + "0x0" +) + +# For a sextic twist +# - p ≡ 1 (mod 2) +# - p ≡ 1 (mod 3) +# +# psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg +# Recap, with ξ (xi) the sextic non-residue for D-Twist or 1/SNR for M-Twist +# psi_2 ≡ ξ^((p-1)/6)^2 ≡ ξ^((p-1)/3) +# psi_3 ≡ psi_2 * ξ^((p-1)/6) ≡ ξ^((p-1)/3) * ξ^((p-1)/6) ≡ ξ^((p-1)/2) +# +# In Fp² (i.e. embedding degree of 12, G2 on Fp2) +# - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol +# - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) +# - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test +# +# We have psi2_3 ≡ psi_3 * psi_3^p ≡ psi_3^(p+1) +# ≡ (ξ^(p-1)/2)^(p+1) (mod p²) +# ≡ ξ^((p-1)(p+1)/2) (mod p²) +# ≡ ξ^((p²-1)/2) (mod p²) +# And ξ^((p²-1)/2) ≡ -1 (mod p²) since ξ is a quadratic non-residue +# So psi2_3 ≡ -1 (mod p²) +# +# +# In Fp (i.e. embedding degree of 6, G2 on Fp) +# - Fermat's Little Theorem gives us a^(p-1) ≡ 1 (mod p) +# +# psi2_3 ≡ ξ^((p-1)(p+1)/2) (mod p) +# ≡ ξ^((p+1)/2)^(p-1) (mod p) as we have 2|p+1 +# ≡ 1 (mod p) by Fermat's Little Theorem diff --git a/constantine/curves/bn254_nogami_frobenius.nim b/constantine/curves/bn254_nogami_frobenius.nim index 6ce3f8b..69535c9 100644 --- a/constantine/curves/bn254_nogami_frobenius.nim +++ b/constantine/curves/bn254_nogami_frobenius.nim @@ -14,9 +14,38 @@ import # Frobenius map - on extension fields # ----------------------------------------------------------------- -# c = (SNR^((p-1)/6)^coef). -# Then for frobenius(2): c * conjugate(c) -# And for frobenius(3): c² * conjugate(c) +# We start from base frobenius constant for a 12 embedding degree. +# with +# - a sextic twist, SNR being the Sextic Non-Residue. +# - coef being the Frobenius coefficient "ID" +# c = SNR^((p-1)/6)^coef +# +# On Fp2 frobenius(c) = conj(c) so we have +# For n=2, with n the number of Frobenius applications +# c2 = c * (c^p) = c * frobenius(c) = c * conj(c) +# c2 = (SNR * conj(SNR))^((p-1)/6)^coef) +# c2 = (norm(SNR))^((p-1)/6)^coef) +# For k=3 +# c3 = c * c2^p = c * frobenius(c2) = c * conj(c2) +# with conj(norm(SNR)) = norm(SNR) as a norm is strictly on the base field. +# c3 = (SNR * norm(SNR))^((p-1)/6)^coef) +# +# A more generic formula can be derived by observing that +# c3 = c * c2^p = c * (c * c^p)^p +# c3 = c * c^p * c^p² +# with 4, we have +# c4 = c * c3^p = c * (c * c^p * c^p²)^p +# c4 = c * c^p * c^p² * c^p³ +# with n we have +# cn = c * c^p * c^p² ... * c^p^(n-1) +# cn = c^(1+p+p² + ... + p^(n-1)) +# This is the sum of first n terms of a geometric series +# hence cn = c^((p^n-1)/(p-1)) +# We now expand c +# cn = SNR^((p-1)/6)^coef^((p^n-1)/(p-1)) +# cn = SNR^((p^n-1)/6)^coef +# cn = SNR^(coef * (p^n-1)/6) + const BN254_Nogami_FrobeniusMapCoefficients* = [ # frobenius(1) ----------------------- [Fp2[BN254_Nogami].fromHex( # SNR^((p-1)/6)^0 @@ -43,73 +72,130 @@ const BN254_Nogami_FrobeniusMapCoefficients* = [ "0x19f3db6884cdca43c2b0d5792cd135accb1baea0b017046e859975ab54b5ef9b", "0xb2f8919bb3235bdf7837806d32eca5b9605515f4fe8fba521668a54ab4a1078" )], + # frobenius(2) ----------------------- - [Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^0 + [Fp2[BN254_Nogami].fromHex( # SNR^((p^2-1)/6)^0 "0x1", "0x0" ), - Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^1 + Fp2[BN254_Nogami].fromHex( # SNR^((p^2-1)/6)^1 "0x49b36240000000024909000000000006cd80000000000008", "0x0" ), - Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^2 + Fp2[BN254_Nogami].fromHex( # SNR^((p^2-1)/6)^2 "0x49b36240000000024909000000000006cd80000000000007", "0x0" ), - Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^3 + Fp2[BN254_Nogami].fromHex( # SNR^((p^2-1)/6)^3 "0x2523648240000001ba344d80000000086121000000000013a700000000000012", "0x0" ), - Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^4 + Fp2[BN254_Nogami].fromHex( # SNR^((p^2-1)/6)^4 "0x25236482400000017080eb4000000006181800000000000cd98000000000000b", "0x0" ), - Fp2[BN254_Nogami].fromHex( # norm(SNR)^((p-1)/6)^5 + Fp2[BN254_Nogami].fromHex( # SNR^((p^2-1)/6)^5 "0x25236482400000017080eb4000000006181800000000000cd98000000000000c", "0x0" )], + # frobenius(3) ----------------------- - [Fp2[BN254_Nogami].fromHex( # (SNR²)^((p-1)/6)^0 + [Fp2[BN254_Nogami].fromHex( # SNR^((p^3-1)/6)^0 "0x1", "0x0" ), - Fp2[BN254_Nogami].fromHex( # (SNR²)^((p-1)/6)^1 + Fp2[BN254_Nogami].fromHex( # SNR^((p^3-1)/6)^1 "0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e", "0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5" ), - Fp2[BN254_Nogami].fromHex( # (SNR²)^((p-1)/6)^2 + Fp2[BN254_Nogami].fromHex( # SNR^((p^3-1)/6)^2 "0x0", "0x1" ), - Fp2[BN254_Nogami].fromHex( # (SNR²)^((p-1)/6)^3 + Fp2[BN254_Nogami].fromHex( # SNR^((p^3-1)/6)^3 "0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e", "0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e" ), - Fp2[BN254_Nogami].fromHex( # (SNR²)^((p-1)/6)^4 + Fp2[BN254_Nogami].fromHex( # SNR^((p^3-1)/6)^4 "0x2523648240000001ba344d80000000086121000000000013a700000000000012", "0x0" ), - Fp2[BN254_Nogami].fromHex( # (SNR²)^((p-1)/6)^5 + Fp2[BN254_Nogami].fromHex( # SNR^((p^3-1)/6)^5 "0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5", "0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e" - )]] + )], +] # ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves # ----------------------------------------------------------------- # BN254_Nogami is a D-Twist: psi1_coef1 = SNR^((p-1)/6) -# SNR^((p-1)/3) -const BN254_Nogami_FrobeniusPsi_psi1_coef2* = Fp2[BN254_Nogami].fromHex( +# SNR^(2(p-1)/6) +const BN254_Nogami_FrobeniusPsi_psi1_coef2* = Fp2[BN254_Nogami].fromHex( "0x0", "0x25236482400000017080eb4000000006181800000000000cd98000000000000b" ) -# SNR^((p-1)/2) -const BN254_Nogami_FrobeniusPsi_psi1_coef3* = Fp2[BN254_Nogami].fromHex( +# SNR^(3(p-1)/6) +const BN254_Nogami_FrobeniusPsi_psi1_coef3* = Fp2[BN254_Nogami].fromHex( "0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5", "0x23dfc9d1a39f4db8c69b87a8848aa075a7333a0e62d78cbf4b1b8eeae58b81c5" ) -# norm(SNR)^((p-1)/3) -const BN254_Nogami_FrobeniusPsi_psi2_coef2* = Fp2[BN254_Nogami].fromHex( +# SNR^(2(p^2-1)/6) +const BN254_Nogami_FrobeniusPsi_psi2_coef2* = Fp2[BN254_Nogami].fromHex( "0x49b36240000000024909000000000006cd80000000000007", "0x0" -) \ No newline at end of file +) +# SNR^(3(p^2-1)/6) +const BN254_Nogami_FrobeniusPsi_psi2_coef3* = Fp2[BN254_Nogami].fromHex( + "0x2523648240000001ba344d80000000086121000000000013a700000000000012", + "0x0" +) +# SNR^(2(p^3-1)/6) +const BN254_Nogami_FrobeniusPsi_psi3_coef2* = Fp2[BN254_Nogami].fromHex( + "0x0", + "0x1" +) +# SNR^(3(p^3-1)/6) +const BN254_Nogami_FrobeniusPsi_psi3_coef3* = Fp2[BN254_Nogami].fromHex( + "0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e", + "0x1439ab09c60b248f398c5d77b755f92b9edc5f19d2873545be471151a747e4e" +) +# SNR^(2(p^4-1)/6) +const BN254_Nogami_FrobeniusPsi_psi4_coef2* = Fp2[BN254_Nogami].fromHex( + "0x25236482400000017080eb4000000006181800000000000cd98000000000000b", + "0x0" +) +# SNR^(3(p^4-1)/6) +const BN254_Nogami_FrobeniusPsi_psi4_coef3* = Fp2[BN254_Nogami].fromHex( + "0x1", + "0x0" +) + +# For a sextic twist +# - p ≡ 1 (mod 2) +# - p ≡ 1 (mod 3) +# +# psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg +# Recap, with ξ (xi) the sextic non-residue for D-Twist or 1/SNR for M-Twist +# psi_2 ≡ ξ^((p-1)/6)^2 ≡ ξ^((p-1)/3) +# psi_3 ≡ psi_2 * ξ^((p-1)/6) ≡ ξ^((p-1)/3) * ξ^((p-1)/6) ≡ ξ^((p-1)/2) +# +# In Fp² (i.e. embedding degree of 12, G2 on Fp2) +# - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol +# - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) +# - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test +# +# We have psi2_3 ≡ psi_3 * psi_3^p ≡ psi_3^(p+1) +# ≡ (ξ^(p-1)/2)^(p+1) (mod p²) +# ≡ ξ^((p-1)(p+1)/2) (mod p²) +# ≡ ξ^((p²-1)/2) (mod p²) +# And ξ^((p²-1)/2) ≡ -1 (mod p²) since ξ is a quadratic non-residue +# So psi2_3 ≡ -1 (mod p²) +# +# +# In Fp (i.e. embedding degree of 6, G2 on Fp) +# - Fermat's Little Theorem gives us a^(p-1) ≡ 1 (mod p) +# +# psi2_3 ≡ ξ^((p-1)(p+1)/2) (mod p) +# ≡ ξ^((p+1)/2)^(p-1) (mod p) as we have 2|p+1 +# ≡ 1 (mod p) by Fermat's Little Theorem diff --git a/constantine/curves/bn254_snarks_frobenius.nim b/constantine/curves/bn254_snarks_frobenius.nim index 151e1b1..0dd6c91 100644 --- a/constantine/curves/bn254_snarks_frobenius.nim +++ b/constantine/curves/bn254_snarks_frobenius.nim @@ -14,9 +14,38 @@ import # Frobenius map - on extension fields # ----------------------------------------------------------------- -# c = (SNR^((p-1)/6)^coef). -# Then for frobenius(2): c * conjugate(c) -# And for frobenius(3): c² * conjugate(c) +# We start from base frobenius constant for a 12 embedding degree. +# with +# - a sextic twist, SNR being the Sextic Non-Residue. +# - coef being the Frobenius coefficient "ID" +# c = SNR^((p-1)/6)^coef +# +# On Fp2 frobenius(c) = conj(c) so we have +# For n=2, with n the number of Frobenius applications +# c2 = c * (c^p) = c * frobenius(c) = c * conj(c) +# c2 = (SNR * conj(SNR))^((p-1)/6)^coef) +# c2 = (norm(SNR))^((p-1)/6)^coef) +# For k=3 +# c3 = c * c2^p = c * frobenius(c2) = c * conj(c2) +# with conj(norm(SNR)) = norm(SNR) as a norm is strictly on the base field. +# c3 = (SNR * norm(SNR))^((p-1)/6)^coef) +# +# A more generic formula can be derived by observing that +# c3 = c * c2^p = c * (c * c^p)^p +# c3 = c * c^p * c^p² +# with 4, we have +# c4 = c * c3^p = c * (c * c^p * c^p²)^p +# c4 = c * c^p * c^p² * c^p³ +# with n we have +# cn = c * c^p * c^p² ... * c^p^(n-1) +# cn = c^(1+p+p² + ... + p^(n-1)) +# This is the sum of first n terms of a geometric series +# hence cn = c^((p^n-1)/(p-1)) +# We now expand c +# cn = SNR^((p-1)/6)^coef^((p^n-1)/(p-1)) +# cn = SNR^((p^n-1)/6)^coef +# cn = SNR^(coef * (p^n-1)/6) + const BN254_Snarks_FrobeniusMapCoefficients* = [ # frobenius(1) ----------------------- [Fp2[BN254_Snarks].fromHex( # SNR^((p-1)/6)^0 @@ -43,73 +72,130 @@ const BN254_Snarks_FrobeniusMapCoefficients* = [ "0x183c1e74f798649e93a3661a4353ff4425c459b55aa1bd32ea2c810eab7692f", "0x12acf2ca76fd0675a27fb246c7729f7db080cb99678e2ac024c6b8ee6e0c2c4b" )], + # frobenius(2) ----------------------- - [Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^0 + [Fp2[BN254_Snarks].fromHex( # SNR^((p^2-1)/6)^0 "0x1", "0x0" ), - Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^1 + Fp2[BN254_Snarks].fromHex( # SNR^((p^2-1)/6)^1 "0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd49", "0x0" ), - Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^2 + Fp2[BN254_Snarks].fromHex( # SNR^((p^2-1)/6)^2 "0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48", "0x0" ), - Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^3 + Fp2[BN254_Snarks].fromHex( # SNR^((p^2-1)/6)^3 "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", "0x0" ), - Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^4 + Fp2[BN254_Snarks].fromHex( # SNR^((p^2-1)/6)^4 "0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe", "0x0" ), - Fp2[BN254_Snarks].fromHex( # norm(SNR)^((p-1)/6)^5 + Fp2[BN254_Snarks].fromHex( # SNR^((p^2-1)/6)^5 "0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177ffffff", "0x0" )], + # frobenius(3) ----------------------- - [Fp2[BN254_Snarks].fromHex( # (SNR²)^((p-1)/6)^0 + [Fp2[BN254_Snarks].fromHex( # SNR^((p^3-1)/6)^0 "0x1", "0x0" ), - Fp2[BN254_Snarks].fromHex( # (SNR²)^((p-1)/6)^1 + Fp2[BN254_Snarks].fromHex( # SNR^((p^3-1)/6)^1 "0x19dc81cfcc82e4bbefe9608cd0acaa90894cb38dbe55d24ae86f7d391ed4a67f", "0xabf8b60be77d7306cbeee33576139d7f03a5e397d439ec7694aa2bf4c0c101" ), - Fp2[BN254_Snarks].fromHex( # (SNR²)^((p-1)/6)^2 + Fp2[BN254_Snarks].fromHex( # SNR^((p^3-1)/6)^2 "0x856e078b755ef0abaff1c77959f25ac805ffd3d5d6942d37b746ee87bdcfb6d", "0x4f1de41b3d1766fa9f30e6dec26094f0fdf31bf98ff2631380cab2baaa586de" ), - Fp2[BN254_Snarks].fromHex( # (SNR²)^((p-1)/6)^3 + Fp2[BN254_Snarks].fromHex( # SNR^((p^3-1)/6)^3 "0x2a275b6d9896aa4cdbf17f1dca9e5ea3bbd689a3bea870f45fcc8ad066dce9ed", "0x28a411b634f09b8fb14b900e9507e9327600ecc7d8cf6ebab94d0cb3b2594c64" ), - Fp2[BN254_Snarks].fromHex( # (SNR²)^((p-1)/6)^4 + Fp2[BN254_Snarks].fromHex( # SNR^((p^3-1)/6)^4 "0xbc58c6611c08dab19bee0f7b5b2444ee633094575b06bcb0e1a92bc3ccbf066", "0x23d5e999e1910a12feb0f6ef0cd21d04a44a9e08737f96e55fe3ed9d730c239f" ), - Fp2[BN254_Snarks].fromHex( # (SNR²)^((p-1)/6)^5 + Fp2[BN254_Snarks].fromHex( # SNR^((p^3-1)/6)^5 "0x13c49044952c0905711699fa3b4d3f692ed68098967c84a5ebde847076261b43", "0x16db366a59b1dd0b9fb1b2282a48633d3e2ddaea200280211f25041384282499" - )]] + )], +] # ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves # ----------------------------------------------------------------- # BN254_Snarks is a D-Twist: psi1_coef1 = SNR^((p-1)/6) -# SNR^((p-1)/3) -const BN254_Snarks_FrobeniusPsi_psi1_coef2* = Fp2[BN254_Snarks].fromHex( +# SNR^(2(p-1)/6) +const BN254_Snarks_FrobeniusPsi_psi1_coef2* = Fp2[BN254_Snarks].fromHex( "0x2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d", "0x16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2" ) -# SNR^((p-1)/2) -const BN254_Snarks_FrobeniusPsi_psi1_coef3* = Fp2[BN254_Snarks].fromHex( +# SNR^(3(p-1)/6) +const BN254_Snarks_FrobeniusPsi_psi1_coef3* = Fp2[BN254_Snarks].fromHex( "0x63cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a", "0x7c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3" ) -# norm(SNR)^((p-1)/3) -const BN254_Snarks_FrobeniusPsi_psi2_coef2* = Fp2[BN254_Snarks].fromHex( +# SNR^(2(p^2-1)/6) +const BN254_Snarks_FrobeniusPsi_psi2_coef2* = Fp2[BN254_Snarks].fromHex( "0x30644e72e131a0295e6dd9e7e0acccb0c28f069fbb966e3de4bd44e5607cfd48", "0x0" -) \ No newline at end of file +) +# SNR^(3(p^2-1)/6) +const BN254_Snarks_FrobeniusPsi_psi2_coef3* = Fp2[BN254_Snarks].fromHex( + "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", + "0x0" +) +# SNR^(2(p^3-1)/6) +const BN254_Snarks_FrobeniusPsi_psi3_coef2* = Fp2[BN254_Snarks].fromHex( + "0x856e078b755ef0abaff1c77959f25ac805ffd3d5d6942d37b746ee87bdcfb6d", + "0x4f1de41b3d1766fa9f30e6dec26094f0fdf31bf98ff2631380cab2baaa586de" +) +# SNR^(3(p^3-1)/6) +const BN254_Snarks_FrobeniusPsi_psi3_coef3* = Fp2[BN254_Snarks].fromHex( + "0x2a275b6d9896aa4cdbf17f1dca9e5ea3bbd689a3bea870f45fcc8ad066dce9ed", + "0x28a411b634f09b8fb14b900e9507e9327600ecc7d8cf6ebab94d0cb3b2594c64" +) +# SNR^(2(p^4-1)/6) +const BN254_Snarks_FrobeniusPsi_psi4_coef2* = Fp2[BN254_Snarks].fromHex( + "0x59e26bcea0d48bacd4f263f1acdb5c4f5763473177fffffe", + "0x0" +) +# SNR^(3(p^4-1)/6) +const BN254_Snarks_FrobeniusPsi_psi4_coef3* = Fp2[BN254_Snarks].fromHex( + "0x1", + "0x0" +) + +# For a sextic twist +# - p ≡ 1 (mod 2) +# - p ≡ 1 (mod 3) +# +# psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg +# Recap, with ξ (xi) the sextic non-residue for D-Twist or 1/SNR for M-Twist +# psi_2 ≡ ξ^((p-1)/6)^2 ≡ ξ^((p-1)/3) +# psi_3 ≡ psi_2 * ξ^((p-1)/6) ≡ ξ^((p-1)/3) * ξ^((p-1)/6) ≡ ξ^((p-1)/2) +# +# In Fp² (i.e. embedding degree of 12, G2 on Fp2) +# - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol +# - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) +# - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test +# +# We have psi2_3 ≡ psi_3 * psi_3^p ≡ psi_3^(p+1) +# ≡ (ξ^(p-1)/2)^(p+1) (mod p²) +# ≡ ξ^((p-1)(p+1)/2) (mod p²) +# ≡ ξ^((p²-1)/2) (mod p²) +# And ξ^((p²-1)/2) ≡ -1 (mod p²) since ξ is a quadratic non-residue +# So psi2_3 ≡ -1 (mod p²) +# +# +# In Fp (i.e. embedding degree of 6, G2 on Fp) +# - Fermat's Little Theorem gives us a^(p-1) ≡ 1 (mod p) +# +# psi2_3 ≡ ξ^((p-1)(p+1)/2) (mod p) +# ≡ ξ^((p+1)/2)^(p-1) (mod p) as we have 2|p+1 +# ≡ 1 (mod p) by Fermat's Little Theorem diff --git a/constantine/curves/bw6_761_frobenius.nim b/constantine/curves/bw6_761_frobenius.nim new file mode 100644 index 0000000..b634e01 --- /dev/null +++ b/constantine/curves/bw6_761_frobenius.nim @@ -0,0 +1,137 @@ +# 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, type_fp], + ../towers, + ../io/[io_fields, io_towers] + +# Frobenius map - on extension fields +# ----------------------------------------------------------------- + +# We start from base frobenius constant for a 6 embedding degree. +# with +# - a sextic twist, SNR being the Sextic Non-Residue. +# - coef being the Frobenius coefficient "ID" +# c = SNR^((p-1)/3)^coef +# +# On Fp2 frobenius(c) = conj(c) so we have +# For n=2, with n the number of Frobenius applications +# c2 = c * (c^p) = c * frobenius(c) = c * conj(c) +# c2 = (SNR * conj(SNR))^((p-1)/3)^coef) +# c2 = (norm(SNR))^((p-1)/3)^coef) +# For k=3 +# c3 = c * c2^p = c * frobenius(c2) = c * conj(c2) +# with conj(norm(SNR)) = norm(SNR) as a norm is strictly on the base field. +# c3 = (SNR * norm(SNR))^((p-1)/3)^coef) +# +# A more generic formula can be derived by observing that +# c3 = c * c2^p = c * (c * c^p)^p +# c3 = c * c^p * c^p² +# with 4, we have +# c4 = c * c3^p = c * (c * c^p * c^p²)^p +# c4 = c * c^p * c^p² * c^p³ +# with n we have +# cn = c * c^p * c^p² ... * c^p^(n-1) +# cn = c^(1+p+p² + ... + p^(n-1)) +# This is the sum of first n terms of a geometric series +# hence cn = c^((p^n-1)/(p-1)) +# We now expand c +# cn = SNR^((p-1)/3)^coef^((p^n-1)/(p-1)) +# cn = SNR^((p^n-1)/3)^coef +# cn = SNR^(coef * (p^n-1)/3) + +const BW6_761_FrobeniusMapCoefficients* = [ + # frobenius(1) ----------------------- + [Fp2[BW6_761].fromHex( # SNR^((p-1)/3)^0 + "0x1", + "0x0" + ), + Fp2[BW6_761].fromHex( # SNR^((p-1)/3)^1 + "0xcfca638f1500e327035cdf02acb2744d06e68545f7e64c256ab7ae14297a1a823132b971cdefc65870636cb60d217ff87fa59308c07a8fab8579e02ed3cddca5b093ed79b1c57b5fe3f89c11811c1e214983de300000535e7bc00000000061", + "0x0" + ), + Fp2[BW6_761].fromHex( # SNR^((p-1)/3)^2 + "0xcfca638f1500e327035cdf02acb2744d06e68545f7e64c256ab7ae14297a1a823132b971cdefc65870636cb60d217ff87fa59308c07a8fab8579e02ed3cddca5b093ed79b1c57b5fe3f89c11811c1e214983de300000535e7bc00000000060", + "0x0" + )], + + # frobenius(2) ----------------------- + [Fp2[BW6_761].fromHex( # SNR^((p^2-1)/3)^0 + "0x1", + "0x0" + ), + Fp2[BW6_761].fromHex( # SNR^((p^2-1)/3)^1 + "0xcfca638f1500e327035cdf02acb2744d06e68545f7e64c256ab7ae14297a1a823132b971cdefc65870636cb60d217ff87fa59308c07a8fab8579e02ed3cddca5b093ed79b1c57b5fe3f89c11811c1e214983de300000535e7bc00000000060", + "0x0" + ), + Fp2[BW6_761].fromHex( # SNR^((p^2-1)/3)^2 + "0x531dc16c6ecd27aa846c61024e4cca6c1f31e53bd9603c2d17be416c5e4426ee4a737f73b6f952ab5e57926fa701848e0a235a0a398300c65759fc45183151f2f082d4dcb5e37cb6290012d96f8819c547ba8a4000002f962140000000002a", + "0x0" + )], + + # frobenius(3) ----------------------- + [Fp2[BW6_761].fromHex( # SNR^((p^3-1)/3)^0 + "0x1", + "0x0" + ), + Fp2[BW6_761].fromHex( # SNR^((p^3-1)/3)^1 + "0x122e824fb83ce0ad187c94004faff3eb926186a81d14688528275ef8087be41707ba638e584e91903cebaff25b423048689c8ed12f9fd9071dcd3dc73ebff2e98a116c25667a8f8160cf8aeeaf0a437e6913e6870000082f49d00000000008a", + "0x0" + ), + Fp2[BW6_761].fromHex( # SNR^((p^3-1)/3)^2 + "0x1", + "0x0" + )], +] + +# ψ (Psi) - Untwist-Frobenius-Twist Endomorphisms on twisted curves +# ----------------------------------------------------------------- +# BW6_761 is a M-Twist: psi1_coef1 = (1/SNR)^((p-1)/6) + +# (1/SNR)^(2(p-1)/6) +const BW6_761_FrobeniusPsi_psi1_coef2* = Fp[BW6_761].fromHex( + "0x531dc16c6ecd27aa846c61024e4cca6c1f31e53bd9603c2d17be416c5e4426ee4a737f73b6f952ab5e57926fa701848e0a235a0a398300c65759fc45183151f2f082d4dcb5e37cb6290012d96f8819c547ba8a4000002f962140000000002a") +# (1/SNR)^(3(p-1)/6) +const BW6_761_FrobeniusPsi_psi1_coef3* = Fp[BW6_761].fromHex( + "0x122e824fb83ce0ad187c94004faff3eb926186a81d14688528275ef8087be41707ba638e584e91903cebaff25b423048689c8ed12f9fd9071dcd3dc73ebff2e98a116c25667a8f8160cf8aeeaf0a437e6913e6870000082f49d00000000008a") +# (1/SNR)^(2(p^2-1)/6) +const BW6_761_FrobeniusPsi_psi2_coef2* = Fp[BW6_761].fromHex( + "0xcfca638f1500e327035cdf02acb2744d06e68545f7e64c256ab7ae14297a1a823132b971cdefc65870636cb60d217ff87fa59308c07a8fab8579e02ed3cddca5b093ed79b1c57b5fe3f89c11811c1e214983de300000535e7bc00000000060") +# (1/SNR)^(3(p^2-1)/6) +const BW6_761_FrobeniusPsi_psi2_coef3* = Fp[BW6_761].fromHex( + "0x1") + +# For a sextic twist +# - p ≡ 1 (mod 2) +# - p ≡ 1 (mod 3) +# +# psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg +# Recap, with ξ (xi) the sextic non-residue for D-Twist or 1/SNR for M-Twist +# psi_2 ≡ ξ^((p-1)/6)^2 ≡ ξ^((p-1)/3) +# psi_3 ≡ psi_2 * ξ^((p-1)/6) ≡ ξ^((p-1)/3) * ξ^((p-1)/6) ≡ ξ^((p-1)/2) +# +# In Fp² (i.e. embedding degree of 12, G2 on Fp2) +# - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol +# - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) +# - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test +# +# We have psi2_3 ≡ psi_3 * psi_3^p ≡ psi_3^(p+1) +# ≡ (ξ^(p-1)/2)^(p+1) (mod p²) +# ≡ ξ^((p-1)(p+1)/2) (mod p²) +# ≡ ξ^((p²-1)/2) (mod p²) +# And ξ^((p²-1)/2) ≡ -1 (mod p²) since ξ is a quadratic non-residue +# So psi2_3 ≡ -1 (mod p²) +# +# +# In Fp (i.e. embedding degree of 6, G2 on Fp) +# - Fermat's Little Theorem gives us a^(p-1) ≡ 1 (mod p) +# +# psi2_3 ≡ ξ^((p-1)(p+1)/2) (mod p) +# ≡ ξ^((p+1)/2)^(p-1) (mod p) as we have 2|p+1 +# ≡ 1 (mod p) by Fermat's Little Theorem diff --git a/constantine/curves/bw6_761_glv.nim b/constantine/curves/bw6_761_glv.nim new file mode 100644 index 0000000..7daa708 --- /dev/null +++ b/constantine/curves/bw6_761_glv.nim @@ -0,0 +1,49 @@ +# 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, type_bigint, type_fp], + ../io/[io_bigints, io_fields] + +# BW6_761 G1 +# ------------------------------------------------------------ + +const BW6_761_cubicRootOfUnity_mod_p* = + Fp[BW6_761].fromHex"0x531dc16c6ecd27aa846c61024e4cca6c1f31e53bd9603c2d17be416c5e4426ee4a737f73b6f952ab5e57926fa701848e0a235a0a398300c65759fc45183151f2f082d4dcb5e37cb6290012d96f8819c547ba8a4000002f962140000000002a" + +const BW6_761_Lattice_G1* = ( + # (BigInt, isNeg) + ((BigInt[188].fromHex"0xbf9b117dd04a4002e16ba885fffffffd3a7bfffffffffff", false), + (BigInt[188].fromHex"0xbf9b117dd04a4002e16ba886000000058b0800000000001", true)), + ((BigInt[188].fromHex"0xbf9b117dd04a4002e16ba886000000058b0800000000001", false), + (BigInt[189].fromHex"0x17f3622fba0948005c2d7510c00000002c58400000000000", false)) +) + +const BW6_761_Babai_G1* = ( + # (BigInt, isNeg) + (BigInt[196].fromHex"0xe4061751dd380c86085f6e7602b7a9d8c2289a5d86c78aa7a", false), + (BigInt[195].fromHex"0x72030ba8ee9c0643042fb73b015bd4eeda5ba6bfab7176f0a", false) +) + + +# BW6_761 G2 +# ------------------------------------------------------------ + +const BW6_761_Lattice_G2* = ( + # (BigInt, isNeg) + ((BigInt[188].fromHex"0xbf9b117dd04a4002e16ba886000000058b0800000000001", true), + (BigInt[188].fromHex"0xbf9b117dd04a4002e16ba885fffffffd3a7bfffffffffff", true)), + ((BigInt[188].fromHex"0xbf9b117dd04a4002e16ba885fffffffd3a7bfffffffffff", false), + (BigInt[189].fromHex"0x17f3622fba0948005c2d7510c00000002c58400000000000", true)) +) + +const BW6_761_Babai_G2* = ( + # (BigInt, isNeg) + (BigInt[196].fromHex"0xe4061751dd380c86085f6e7602b7a9d8c2289a5d86c78aa7a", true), + (BigInt[195].fromHex"0x72030ba8ee9c0643042fb73b015bd4e9e7ccf39ddb5613b6f", false) +) diff --git a/constantine/curves/zoo_frobenius.nim b/constantine/curves/zoo_frobenius.nim index 6c8d5e1..ea2ab01 100644 --- a/constantine/curves/zoo_frobenius.nim +++ b/constantine/curves/zoo_frobenius.nim @@ -12,7 +12,8 @@ import ./bls12_377_frobenius, ./bls12_381_frobenius, ./bn254_nogami_frobenius, - ./bn254_snarks_frobenius + ./bn254_snarks_frobenius, + ./bw6_761_frobenius {.experimental: "dynamicBindSym".} diff --git a/constantine/curves/zoo_glv.nim b/constantine/curves/zoo_glv.nim index 55e0e3f..a69b6eb 100644 --- a/constantine/curves/zoo_glv.nim +++ b/constantine/curves/zoo_glv.nim @@ -13,7 +13,8 @@ import ./bls12_377_glv, ./bls12_381_glv, ./bn254_nogami_glv, - ./bn254_snarks_glv + ./bn254_snarks_glv, + ./bw6_761_glv {.experimental: "dynamicBindSym".} @@ -41,5 +42,6 @@ func hasEndomorphismAcceleration*(C: static Curve): bool = BN254_Nogami, BN254_Snarks, BLS12_377, - BLS12_381 + BLS12_381, + BW6_761 } diff --git a/constantine/elliptic/ec_endomorphism_accel.nim b/constantine/elliptic/ec_endomorphism_accel.nim index 856e95f..405c2d7 100644 --- a/constantine/elliptic/ec_endomorphism_accel.nim +++ b/constantine/elliptic/ec_endomorphism_accel.nim @@ -15,7 +15,8 @@ import ../curves/zoo_glv, ../arithmetic, ../towers, - ../isogeny/frobenius + ../isogeny/frobenius, + ./ec_shortweierstrass_affine # ############################################################ # @@ -290,15 +291,19 @@ func scalarMulEndo*[scalBits; EC]( const M = 2 # 1. Compute endomorphisms var endomorphisms {.noInit.}: array[M-1, typeof(P)] - endomorphisms[0] = P - endomorphisms[0].x *= C.getCubicRootOfUnity_mod_p() + when P.Tw == NotOnTwist: + endomorphisms[0] = P + endomorphisms[0].x *= C.getCubicRootOfUnity_mod_p() + else: + endomorphisms[0].frobenius_psi(P, 2) + elif P.F is Fp2: const M = 4 # 1. Compute endomorphisms var endomorphisms {.noInit.}: array[M-1, typeof(P)] endomorphisms[0].frobenius_psi(P) - endomorphisms[1].frobenius_psi2(P) - endomorphisms[2].frobenius_psi(endomorphisms[1]) + endomorphisms[1].frobenius_psi(P, 2) + endomorphisms[2].frobenius_psi(P, 3) else: {.error: "Unconfigured".} @@ -475,8 +480,12 @@ func scalarMulGLV_m2w2*[scalBits; EC]( static: doAssert: scalBits == C.getCurveOrderBitwidth() # 1. Compute endomorphisms - var P1 = P0 - P1.x *= C.getCubicRootOfUnity_mod_p() + when P0.Tw == NotOnTwist: + var P1 = P0 + P1.x *= C.getCubicRootOfUnity_mod_p() + else: + var P1 {.noInit.}: typeof(P0) + P1.frobenius_psi(P0, 2) # 2. Decompose scalar into mini-scalars const L = computeRecodedLength(C.getCurveOrderBitwidth(), 2) diff --git a/constantine/io/io_ec.nim b/constantine/io/io_ec.nim index d10519e..73b4370 100644 --- a/constantine/io/io_ec.nim +++ b/constantine/io/io_ec.nim @@ -26,7 +26,7 @@ import # # ############################################################ -func toHex*[EC](P: EC): string = +func toHex*[EC: ECP_ShortW_Proj or ECP_ShortW_Jac or ECP_ShortW_Aff](P: EC): string = ## Stringify an elliptic curve point to Hex ## Note. Leading zeros are not removed. ## Result is prefixed with 0x diff --git a/constantine/isogeny/frobenius.nim b/constantine/isogeny/frobenius.nim index 47ab215..7e1ee42 100644 --- a/constantine/isogeny/frobenius.nim +++ b/constantine/isogeny/frobenius.nim @@ -35,6 +35,12 @@ import # whether u = √-1 = i # or √-2 or √-5 +func frobenius_map*(r: var Fp, a: Fp, k: static int = 1) {.inline.} = + ## Computes a^(p^k) + ## The p-power frobenius automorphism on 𝔽p + ## This is identity per Fermat's little theorem + r = a + func frobenius_map*(r: var Fp2, a: Fp2, k: static int = 1) {.inline.} = ## Computes a^(p^k) ## The p-power frobenius automorphism on 𝔽p2 @@ -43,9 +49,21 @@ func frobenius_map*(r: var Fp2, a: Fp2, k: static int = 1) {.inline.} = else: r = a -template mulCheckSparse[Fp2](a: var Fp2, b: Fp2) = - when b.c0.isOne().bool and b.c1.isZero().bool: +template mulCheckSparse(a: var Fp, b: Fp) = + when b.isOne().bool: discard + elif b.isZero().bool: + a.setZero() + elif b.isMinusOne().bool: + a.neg() + else: + a *= b + +template mulCheckSparse(a: var Fp2, b: Fp2) = + when b.isOne().bool: + discard + elif b.isMinusOne().bool: + a.neg() elif b.c0.isZero().bool and b.c1.isOne().bool: var t {.noInit.}: type(a.c0) when fromComplexExtension(b): @@ -56,6 +74,16 @@ template mulCheckSparse[Fp2](a: var Fp2, b: Fp2) = t = NonResidue * a.c1 a.c1 = a.c0 a.c0 = t + elif b.c0.isZero().bool and b.c1.isMinusOne().bool: + var t {.noInit.}: type(a.c0) + when fromComplexExtension(b): + t = a.c1 + a.c1.neg(a.c0) + a.c0 = t + else: + t = NonResidue * a.c1 + a.c1.neg(a.c0) + a.c0.neg(t) elif b.c0.isZero().bool: a.mul_sparse_by_0y(b) elif b.c1.isZero().bool: @@ -79,8 +107,15 @@ func frobenius_map*[C](r: var Fp6[C], a: Fp6[C], k: static int = 1) {.inline.} = r.c0.frobenius_map(a.c0, k) r.c1.frobenius_map(a.c1, k) r.c2.frobenius_map(a.c2, k) - r.c1.mulCheckSparse frobMapConst(C, 2, k) - r.c2.mulCheckSparse frobMapConst(C, 4, k) + + when C.getEmbeddingDegree == 12: + r.c1.mulCheckSparse frobMapConst(C, 2, k) + r.c2.mulCheckSparse frobMapConst(C, 4, k) + elif C.getEmbeddingDegree == 6: + r.c1.mulCheckSparse frobMapConst(C, 1, k) + r.c2.mulCheckSparse frobMapConst(C, 2, k) + else: + {.error: "Not Implemented".} func frobenius_map*[C](r: var Fp12[C], a: Fp12[C], k: static int = 1) {.inline.} = ## Computes a^(p^k) @@ -105,57 +140,11 @@ func frobenius_map*[C](r: var Fp12[C], a: Fp12[C], k: static int = 1) {.inline.} # with SNR the sextic non-residue # -func frobenius_psi*[PointG2](r: var PointG2, P: PointG2) = - ## "Untwist-Frobenius-Twist" endomorphism +func frobenius_psi*[PointG2](r: var PointG2, P: PointG2, k: static int = 1) = + ## "Untwist-Frobenius-Twist" endomorphism applied k times ## r = ψ(P) for coordR, coordP in fields(r, P): - coordR.frobenius_map(coordP, 1) + coordR.frobenius_map(coordP, k) - # With ξ (xi) the sextic non-residue - # c = ξ^((p-1)/6) for D-Twist - # c = (1/ξ)^((p-1)/6) for M-Twist - # - # c1_2 = c² - # c1_3 = c³ - - r.x.mulCheckSparse frobPsiConst(PointG2.F.C, psipow=1, coefpow=2) - r.y.mulCheckSparse frobPsiConst(PointG2.F.C, psipow=1, coefpow=3) - -func frobenius_psi2*[PointG2](r: var PointG2, P: PointG2) = - ## "Untwist-Frobenius-Twist" endomorphism applied twice - ## r = ψ(ψ(P)) - for coordR, coordP in fields(r, P): - coordR.frobenius_map(coordP, 2) - - # With ξ (xi) the sextic non-residue - # c = ξ for D-Twist - # c = (1/ξ) for M-Twist - # - # frobenius(a) = conj(a) = a^p - # - # c1_2 = (c^((p-1)/6))² = c^((p-1)/3) - # c1_3 = (c^((p-1)/6))³ = c^((p-1)/2) - # - # c2_2 = c1_2 * frobenius(c1_2) = c^((p-1)/3) * c^((p-1)/3)^p - # = c^((p-1)/3) * conj(c)^((p-1)/3) - # = norm(c)^((p-1)/3) - # - # c2_3 = c1_3 * frobenius(c1_3) = c^((p-1)/2) * c^((p-1)/2)^p - # = c^((p-1)/2) * conj(c)^((p-1)/2) - # = norm(c)^((p-1)/2) - # We prove that c2_3 ≡ -1 (mod p²) with the following: - # - # - Whether c = ξ or c = (1/ξ), c is a quadratic non-residue (QNR) in 𝔽p2 - # because: - # - ξ is quadratic non-residue as it is a sextic non-residue - # by construction of the tower extension - # - if a is QNR then 1/a is also a QNR - # - Then c^((p²-1)/2) ≡ -1 (mod p²) from the Legendre symbol in 𝔽p2 - # - # c2_3 = c^((p-1)/2) * c^((p-1)/2)^p = c^((p+1)*(p-1)/2) - # = c^((p²-1)/2) - # c2_3 ≡ -1 (mod p²) - # QED - - r.x.mulCheckSparse frobPsiConst(PointG2.F.C, psipow=2, coefpow=2) - r.y.neg(r.y) + r.x.mulCheckSparse frobPsiConst(PointG2.F.C, psipow=k, coefpow=2) + r.y.mulCheckSparse frobPsiConst(PointG2.F.C, psipow=k, coefpow=3) diff --git a/constantine/pairing/pairing_bn.nim b/constantine/pairing/pairing_bn.nim index 8c49959..1c5a288 100644 --- a/constantine/pairing/pairing_bn.nim +++ b/constantine/pairing/pairing_bn.nim @@ -115,7 +115,7 @@ func millerLoopGenericBN*[C]( line.line_add(T, V, P) f.mul(line) - V.frobenius_psi2(Q) + V.frobenius_psi(Q, 2) V.neg() line.line_add(T, V, P) f.mul(line) diff --git a/constantine/tower_field_extensions/quadratic_extensions.nim b/constantine/tower_field_extensions/quadratic_extensions.nim index d6abcf5..b8957b5 100644 --- a/constantine/tower_field_extensions/quadratic_extensions.nim +++ b/constantine/tower_field_extensions/quadratic_extensions.nim @@ -243,6 +243,24 @@ func mul_sparse_generic_by_x0(r: var QuadraticExt, a, sparseB: QuadraticExt) = r.c0.prod(a.c0, b.c0) r.c1.prod(a.c1, b.c0) +func mul_sparse_generic_by_0y(r: var QuadraticExt, a, sparseB: QuadraticExt) = + ## Multiply `a` by `b` with sparse coordinates (0, y) + ## On a generic quadratic extension field + # Algorithm (with β the non-residue in the base field) + # + # r0 = a0 b0 + β a1 b1 + # r1 = (a0 + a1) (b0 + b1) - a0 b0 - a1 b1 (Karatsuba) + # + # with b0 = 0, hence + # + # r0 = β a1 b1 + # r1 = (a0 + a1) b1 - a1 b1 = a0 b1 + template b(): untyped = sparseB + + r.c0.prod(a.c1, b.c1) + r.c0 *= NonResidue + r.c1.prod(a.c0, b.c1) + # Exported symbols # ------------------------------------------------------------------- @@ -339,7 +357,8 @@ func mul_sparse_by_0y*(a: var QuadraticExt, sparseB: QuadraticExt) {.inline.} = let t = a a.mul_sparse_complex_by_0y(t, sparseB) else: - {.error: "Not implemented".} + let t = a + a.mul_sparse_generic_by_0y(t, sparseB) func mul_sparse_by_x0*(a: var QuadraticExt, sparseB: QuadraticExt) {.inline.} = ## Sparse in-place multiplication diff --git a/constantine/tower_field_extensions/tower_common.nim b/constantine/tower_field_extensions/tower_common.nim index d214d41..0e1f17e 100644 --- a/constantine/tower_field_extensions/tower_common.nim +++ b/constantine/tower_field_extensions/tower_common.nim @@ -88,6 +88,15 @@ func isOne*(a: ExtensionField): SecretBool = else: result = result and fA.isZero() +func isMinusOne*(a: ExtensionField): SecretBool = + ## Constant-time check if -1 + result = CtTrue + for fieldName, fA in fieldPairs(a): + when fieldName == "c0": + result = result and fA.isMinusOne() + else: + result = result and fA.isZero() + # Copies # ------------------------------------------------------------------- diff --git a/sage/curves.sage b/sage/curves.sage index c9790dc..c54b48a 100644 --- a/sage/curves.sage +++ b/sage/curves.sage @@ -42,6 +42,27 @@ def derive_BLS12_field(x): } return params +def derive_BW6_compose_BLS12_field(x, cofactor_trace, cofactor_y): + # Brezing-Weng input + r = (x^6 - 2*x^5 + 2*x^3 + x + 1) // 3 # BLS12 modulus + + # 6-th root of unity output + cofactors + t = x^5 - 3*x^4 + 3*x^3 - x + 3 + cofactor_trace*r + y = (x^5 - 3*x^4 + 3*x^3 - x + 3)//3 + cofactor_y*r + + # Curve parameters + p = (t^2 + 3*y^2)/4 + trace = p+1-r # (3*y+t)/2 + + params = { + 'param': x, + 'modulus': p, + 'order': r, + 'trace': trace, + 'family': 'BW6' + } + return params + def copyright(): return inspect.cleandoc(""" # Constantine @@ -113,5 +134,23 @@ Curves = { 'SNR_Fp2': [1, 1], 'twist': 'M_Twist' } + }, + 'BW6_761': { + 'field': derive_BW6_compose_BLS12_field( + 3 * 2^46 * (7 * 13 * 499) + 1, + cofactor_trace = 13, + cofactor_y = 9 + ), + 'curve': { + 'form': 'short_weierstrass', + 'a': 0, + 'b': -1 + }, + 'tower': { + 'embedding_degree': 6, + 'twist_degree': 6, + 'SNR_Fp': -4, + 'twist': 'M_Twist' + } } } diff --git a/sage/derive_endomorphisms.sage b/sage/derive_endomorphisms.sage index 1c6d806..32f90de 100644 --- a/sage/derive_endomorphisms.sage +++ b/sage/derive_endomorphisms.sage @@ -116,12 +116,23 @@ def genCubicRootEndo(curve_name, curve_config): r = curve_config[curve_name]['field']['order'] b = curve_config[curve_name]['curve']['b'] + print('Constructing G1') Fp = GF(p) G1 = EllipticCurve(Fp, [0, b]) + print('Computing cofactor') cofactor = G1.order() // r - (phi1, phi2) = (Fp(root) for root in Fp(1).nth_root(3, all=True) if root != 1) - (lambda1, lambda2) = (GF(r)(root) for root in GF(r)(1).nth_root(3, all=True) if root != 1) + # slow for large inputs - https://pari.math.u-bordeaux.fr/archives/pari-dev-0412/msg00020.html + if curve_name != 'BW6_761': + print('Finding cube roots') + (phi1, phi2) = (Fp(root) for root in Fp(1).nth_root(3, all=True) if root != 1) + (lambda1, lambda2) = (GF(r)(root) for root in GF(r)(1).nth_root(3, all=True) if root != 1) + else: + print('Skip finding cube roots for BW6_761, too slow, use values from paper https://eprint.iacr.org/2020/351') + phi1 = Integer('0x531dc16c6ecd27aa846c61024e4cca6c1f31e53bd9603c2d17be416c5e4426ee4a737f73b6f952ab5e57926fa701848e0a235a0a398300c65759fc45183151f2f082d4dcb5e37cb6290012d96f8819c547ba8a4000002f962140000000002a') + phi2 = Integer('0xcfca638f1500e327035cdf02acb2744d06e68545f7e64c256ab7ae14297a1a823132b971cdefc65870636cb60d217ff87fa59308c07a8fab8579e02ed3cddca5b093ed79b1c57b5fe3f89c11811c1e214983de300000535e7bc00000000060') + lambda1 = Integer('0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000001') + lambda2 = Integer('-0x9b3af05dd14f6ec619aaf7d34594aabc5ed1347970dec00452217cc900000008508c00000000002') print('𝜑1 (mod p): 0x' + Integer(phi1).hex()) print('λᵩ1 (mod r): 0x' + Integer(lambda1).hex()) @@ -149,9 +160,11 @@ def genCubicRootEndo(curve_name, curve_config): print(' 𝜑 (mod p): 0x' + Integer(phi1).hex()) print(' λᵩ (mod r): 0x' + Integer(lambda1).hex()) + print('Deriving Lattice') lattice = derive_lattice(r, lambda1, 2) pretty_print_lattice(lattice) + print('Deriving Babai basis') babai = derive_babai(r, lattice, 2) pretty_print_babai(babai) @@ -170,9 +183,11 @@ def genPsiEndo(curve_name, curve_config): # λψ is the trace of Frobenius - 1 lambda_psi = t - 1 + print('Deriving Lattice') lattice = derive_lattice(r, lambda_psi, m) pretty_print_lattice(lattice) + print('Deriving Babai basis') babai = derive_babai(r, lattice, m) pretty_print_babai(babai) diff --git a/sage/derive_frobenius.sage b/sage/derive_frobenius.sage index dbc5426..b5a5630 100644 --- a/sage/derive_frobenius.sage +++ b/sage/derive_frobenius.sage @@ -43,20 +43,26 @@ def fp2_to_hex(a): return '0x' + Integer(v[0]).hex() + ' + β * ' + '0x' + Integer(v[1]).hex() def field_to_nim(value, field, curve, prefix = "", comment_above = "", comment_right = ""): + result = '# ' + comment_above + '\n' if comment_above else '' + comment_right = ' # ' + comment_right if comment_right else '' + if field == 'Fp2': v = vector(value) - result = '# ' + comment_above + '\n' if comment_above else '' - comment_right = ' # ' + comment_right if comment_right else '' - result += inspect.cleandoc(f""" {prefix}Fp2[{curve}].fromHex( {comment_right} "0x{Integer(v[0]).hex()}", "0x{Integer(v[1]).hex()}" )""") - return result + elif field == 'Fp': + result += inspect.cleandoc(f""" + {prefix}Fp[{curve}].fromHex( {comment_right} + "0x{Integer(value).hex()}") + """) else: - raise newException(NotImplementedError) + raise NotImplementedError() + + return result # Code generators # --------------------------------------------------------- @@ -72,68 +78,78 @@ def genFrobeniusMapConstants(curve_name, curve_config): if g2field == 'Fp2': QNR_Fp = curve_config[curve_name]['tower']['QNR_Fp'] Fp2. = Fp.extension(u^2 - QNR_Fp) + else: + SNR_Fp = curve_config[curve_name]['tower']['SNR_Fp'] + Fp2. = Fp.extension(u^2 - SNR_Fp) - SNR = curve_config[curve_name]['tower']['SNR_Fp2'] if g2field == 'Fp2': - cur = Fp2([1, 0]) + SNR = curve_config[curve_name]['tower']['SNR_Fp2'] SNR = Fp2(SNR) else: - cur = Fp(1) - SNR = Fp(SNR) + # To build the Fp6 extension, since we use a SexticNonResidue + # to build Fp2, we can reuse it as a cubic non-residue + # It always has [0, 1] coordinates in Fp2 + SNR = Fp2([0, 1]) + + halfK = embdeg//2 print('\n----> Frobenius extension field constants <----\n') buf = inspect.cleandoc(f""" # Frobenius map - on extension fields # ----------------------------------------------------------------- - # c = (SNR^((p-1)/{twdeg})^coef). - # Then for frobenius(2): c * conjugate(c) - # And for frobenius(3): c² * conjugate(c) + # We start from base frobenius constant for a {embdeg} embedding degree. + # with + # - a sextic twist, SNR being the Sextic Non-Residue. + # - coef being the Frobenius coefficient "ID" + # c = SNR^((p-1)/{halfK})^coef + # + # On Fp2 frobenius(c) = conj(c) so we have + # For n=2, with n the number of Frobenius applications + # c2 = c * (c^p) = c * frobenius(c) = c * conj(c) + # c2 = (SNR * conj(SNR))^((p-1)/{halfK})^coef) + # c2 = (norm(SNR))^((p-1)/{halfK})^coef) + # For k=3 + # c3 = c * c2^p = c * frobenius(c2) = c * conj(c2) + # with conj(norm(SNR)) = norm(SNR) as a norm is strictly on the base field. + # c3 = (SNR * norm(SNR))^((p-1)/{halfK})^coef) + # + # A more generic formula can be derived by observing that + # c3 = c * c2^p = c * (c * c^p)^p + # c3 = c * c^p * c^p² + # with 4, we have + # c4 = c * c3^p = c * (c * c^p * c^p²)^p + # c4 = c * c^p * c^p² * c^p³ + # with n we have + # cn = c * c^p * c^p² ... * c^p^(n-1) + # cn = c^(1+p+p² + ... + p^(n-1)) + # This is the sum of first n terms of a geometric series + # hence cn = c^((p^n-1)/(p-1)) + # We now expand c + # cn = SNR^((p-1)/{halfK})^coef^((p^n-1)/(p-1)) + # cn = SNR^((p^n-1)/{halfK})^coef + # cn = SNR^(coef * (p^n-1)/{halfK}) + const {curve_name}_FrobeniusMapCoefficients* = [ """) - FrobConst_map = SNR^((p-1)/6) - FrobConst_map_list = [] - arr = "" + maxN = 3 # We only need up to f^(p^3) in final exponentiation - for i in range(twdeg): - if i == 0: - arr += '\n# frobenius(1) -----------------------\n' - arr += '[' - arr += field_to_nim(cur, g2field, curve_name, comment_right = f'SNR^((p-1)/{twdeg})^{i}') - FrobConst_map_list.append(cur) - cur *= FrobConst_map - if i == twdeg - 1: - arr += ']' - arr += ',\n' - - for i in range(twdeg): - if i == 0: - arr += '# frobenius(2) -----------------------\n' - arr += '[' - - val = FrobConst_map_list[i]*conjugate(FrobConst_map_list[i]) - arr += field_to_nim(val, g2field, curve_name, comment_right = f'norm(SNR)^((p-1)/{twdeg})^{i}') - - if i == twdeg - 1: - arr += ']' - arr += ',\n' - - for i in range(twdeg): - if i == 0: - arr += '# frobenius(3) -----------------------\n' - arr += '[' - - val = FrobConst_map_list[i]^2 * conjugate(FrobConst_map_list[i]) - arr += field_to_nim(val, g2field, curve_name, comment_right = f'(SNR²)^((p-1)/{twdeg})^{i}') - - if i == twdeg - 1: - arr += ']]' - else: - arr += ',\n' + for n in range(1, maxN + 1): + for coef in range(halfK): + if coef == 0: + arr += f'\n# frobenius({n}) -----------------------\n' + arr += '[' + frobmapcoef = SNR^(coef*((p^n-1)/halfK)) + hatN = '^' + str(n) if n>1 else '' + arr += field_to_nim(frobmapcoef, 'Fp2', curve_name, comment_right = f'SNR^((p{hatN}-1)/{halfK})^{coef}') + if coef != halfK - 1: + arr += ',\n' + arr += '],\n' buf += textwrap.indent(arr, ' ') + buf += ']' return buf def genFrobeniusPsiConstants(curve_name, curve_config): @@ -149,12 +165,11 @@ def genFrobeniusPsiConstants(curve_name, curve_config): QNR_Fp = curve_config[curve_name]['tower']['QNR_Fp'] Fp2. = Fp.extension(u^2 - QNR_Fp) - SNR = curve_config[curve_name]['tower']['SNR_Fp2'] if g2field == 'Fp2': - cur = Fp2([1, 0]) + SNR = curve_config[curve_name]['tower']['SNR_Fp2'] SNR = Fp2(SNR) else: - cur = Fp(1) + SNR = curve_config[curve_name]['tower']['SNR_Fp'] SNR = Fp(SNR) print('\n----> ψ (Psi) - Untwist-Frobenius-Twist Endomorphism constants <----\n') @@ -165,56 +180,62 @@ def genFrobeniusPsiConstants(curve_name, curve_config): buf += '\n' if twkind == 'D_Twist': buf += f'# {curve_name} is a D-Twist: psi1_coef1 = SNR^((p-1)/{twdeg})\n\n' - FrobConst_psi = SNR^((p-1)/twdeg) + xi = SNR snrUsed = 'SNR' else: buf += f'# {curve_name} is a M-Twist: psi1_coef1 = (1/SNR)^((p-1)/{twdeg})\n\n' - FrobConst_psi = (1/SNR)^((p-1)/twdeg) + xi = 1/SNR snrUsed = '(1/SNR)' - FrobConst_psi1_coef2 = FrobConst_psi^2 - FrobConst_psi1_coef3 = FrobConst_psi1_coef2 * FrobConst_psi + maxPsi = CyclotomicField(embdeg).degree() - buf += field_to_nim( - FrobConst_psi1_coef2, g2field, curve_name, - prefix = f'const {curve_name}_FrobeniusPsi_psi1_coef2* = ', - comment_above = f'{snrUsed}^((p-1)/{twdeg//2})' - ) + '\n' + for n in range(1, maxPsi+1): + for coef in range(2, 3+1): + # Same formula as FrobeniusMap constants + # except that + # - we only need 2 coefs for elliptic curve twists + # - xi = SNR or 1/SNR depending on D-Twist or M-Twist respectively + # - the divisor is the twist degree isntead of half the embedding degree + frobpsicoef = xi^(coef*(p^n - 1)/twdeg) + hatN = '^' + str(n) if n>1 else '' + buf += field_to_nim( + frobpsicoef, g2field, curve_name, + prefix = f'const {curve_name}_FrobeniusPsi_psi{n}_coef{coef}* = ', + comment_above = f'{snrUsed}^({coef}(p{hatN}-1)/{twdeg})' + ) + '\n' - buf += field_to_nim( - FrobConst_psi1_coef3, g2field, curve_name, - prefix = f'const {curve_name}_FrobeniusPsi_psi1_coef3* = ', - comment_above = f'{snrUsed}^((p-1)/{twdeg//3})' - ) + '\n' + buf += '\n' - FrobConst_psi2_coef2 = FrobConst_psi1_coef2 * FrobConst_psi1_coef2**p - - buf += field_to_nim( - FrobConst_psi2_coef2, g2field, curve_name, - prefix = f'const {curve_name}_FrobeniusPsi_psi2_coef2* = ', - comment_above = f'norm({snrUsed})^((p-1)/{twdeg//2})' - ) - - # psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg - # Recap, with ξ (xi) the sextic non-residue - # psi_2 = ((1/ξ)^((p-1)/6))^2 = (1/ξ)^((p-1)/3) - # psi_3 = psi_2 * (1/ξ)^((p-1)/6) = (1/ξ)^((p-1)/3) * (1/ξ)^((p-1)/6) = (1/ξ)^((p-1)/2) - # - # Reminder, in 𝔽p2, frobenius(a) = a^p = conj(a) - # psi2_2 = psi_2 * psi_2^p = (1/ξ)^((p-1)/3) * (1/ξ)^((p-1)/3)^p = (1/ξ)^((p-1)/3) * frobenius((1/ξ))^((p-1)/3) - # = norm(1/ξ)^((p-1)/3) - # psi2_3 = psi_3 * psi_3^p = (1/ξ)^((p-1)/2) * (1/ξ)^((p-1)/2)^p = (1/ξ)^((p-1)/2) * frobenius((1/ξ))^((p-1)/2) - # = norm(1/ξ)^((p-1)/2) - # - # In Fp²: - # - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol - # - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) - # - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test - # - # We have norm(ξ)^((p-1)/2) = (ξ*frobenius(ξ))^((p-1)/2) = (ξ*(ξ^p))^((p-1)/2) = ξ^(p+1)^(p-1)/2 - # = ξ^((p²-1)/2) - # And ξ^((p²-1)/2) ≡ -1 (mod p²) - # So psi2_3 ≡ -1 (mod p²) + buf += inspect.cleandoc(f""" + # For a sextic twist + # - p ≡ 1 (mod 2) + # - p ≡ 1 (mod 3) + # + # psi2_coef3 is always -1 (mod p^m) with m = embdeg/twdeg + # Recap, with ξ (xi) the sextic non-residue for D-Twist or 1/SNR for M-Twist + # psi_2 ≡ ξ^((p-1)/6)^2 ≡ ξ^((p-1)/3) + # psi_3 ≡ psi_2 * ξ^((p-1)/6) ≡ ξ^((p-1)/3) * ξ^((p-1)/6) ≡ ξ^((p-1)/2) + # + # In Fp² (i.e. embedding degree of 12, G2 on Fp2) + # - quadratic non-residues respect the equation a^((p²-1)/2) ≡ -1 (mod p²) by the Legendre symbol + # - sextic non-residues are also quadratic non-residues so ξ^((p²-1)/2) ≡ -1 (mod p²) + # - QRT(1/a) = QRT(a) with QRT the quadratic residuosity test + # + # We have psi2_3 ≡ psi_3 * psi_3^p ≡ psi_3^(p+1) + # ≡ (ξ^(p-1)/2)^(p+1) (mod p²) + # ≡ ξ^((p-1)(p+1)/2) (mod p²) + # ≡ ξ^((p²-1)/2) (mod p²) + # And ξ^((p²-1)/2) ≡ -1 (mod p²) since ξ is a quadratic non-residue + # So psi2_3 ≡ -1 (mod p²) + # + # + # In Fp (i.e. embedding degree of 6, G2 on Fp) + # - Fermat's Little Theorem gives us a^(p-1) ≡ 1 (mod p) + # + # psi2_3 ≡ ξ^((p-1)(p+1)/2) (mod p) + # ≡ ξ^((p+1)/2)^(p-1) (mod p) as we have 2|p+1 + # ≡ 1 (mod p) by Fermat's Little Theorem + """) return buf @@ -241,18 +262,33 @@ if __name__ == "__main__": str(Curves.keys()) ) else: + trace = Curves[curve]['field']['trace'] + print(f'trace of Frobenius ({int(trace).bit_length()}-bit): 0x{Integer(trace).hex()}') + FrobMap = genFrobeniusMapConstants(curve, Curves) FrobPsi = genFrobeniusPsiConstants(curve, Curves) with open(f'{curve.lower()}_frobenius.nim', 'w') as f: f.write(copyright()) f.write('\n\n') - f.write(inspect.cleandoc(""" - import - ../config/curves, - ../towers, - ../io/io_towers - """)) + + embdeg = Curves[curve]['tower']['embedding_degree'] + twdeg = Curves[curve]['tower']['twist_degree'] + + if embdeg//twdeg >= 2: + f.write(inspect.cleandoc(""" + import + ../config/curves, + ../towers, + ../io/io_towers + """)) + else: + f.write(inspect.cleandoc(""" + import + ../config/[curves, type_fp], + ../towers, + ../io/[io_fields, io_towers] + """)) f.write('\n\n') f.write(FrobMap) f.write('\n\n') diff --git a/sage/testgen_scalar_mul.sage b/sage/testgen_scalar_mul.sage index ac47ec5..ab12566 100644 --- a/sage/testgen_scalar_mul.sage +++ b/sage/testgen_scalar_mul.sage @@ -54,7 +54,7 @@ def progressbar(it, prefix="", size=60, file=sys.stdout): def serialize_bigint(x): return '0x' + Integer(x).hex() -def serialize_G1(P): +def serialize_EC_Fp(P): (Px, Py, Pz) = P coords = { 'x': serialize_bigint(Px), @@ -62,7 +62,7 @@ def serialize_G1(P): } return coords -def serialize_G2(P): +def serialize_EC_Fp2(P): (Px, Py, Pz) = P Px = vector(Px) Py = vector(Py) @@ -112,13 +112,12 @@ def genScalarMulG1(curve_name, curve_config, count, seed): scalar = randrange(r) P *= cofactor # clear cofactor + Q = scalar * P v['id'] = i - v['P'] = serialize_G1(P) + v['P'] = serialize_EC_Fp(P) v['scalar'] = serialize_bigint(scalar) - - Q = scalar * P - v['Q'] = serialize_G1(Q) + v['Q'] = serialize_EC_Fp(Q) vectors.append(v) out['vectors'] = vectors @@ -139,6 +138,12 @@ def genScalarMulG2(curve_name, curve_config, count, seed): if G2_field_degree == 2: non_residue_fp = curve_config[curve_name]['tower']['QNR_Fp'] + elif G2_field_degree == 1: + if twist_degree == 6: + # Only for complete serialization + non_residue_fp = curve_config[curve_name]['tower']['SNR_Fp'] + else: + raise NotImplementedError() else: raise NotImplementedError() @@ -152,8 +157,13 @@ def genScalarMulG2(curve_name, curve_config, count, seed): non_residue_twist = curve_config[curve_name]['tower']['SNR_Fp2'] else: raise NotImplementedError() - else: + elif G2_field == 'Fp': G2F = Fp + if twist_degree == 6: + non_residue_twist = curve_config[curve_name]['tower']['SNR_Fp'] + else: + raise NotImplementedError() + else: raise NotImplementedError() if twist == 'D_Twist': @@ -190,13 +200,17 @@ def genScalarMulG2(curve_name, curve_config, count, seed): scalar = randrange(r) P *= cofactor # clear cofactor + Q = scalar * P v['id'] = i - v['P'] = serialize_G2(P) - v['scalar'] = serialize_bigint(scalar) - - Q = scalar * P - v['Q'] = serialize_G2(Q) + if G2_field == 'Fp2': + v['P'] = serialize_EC_Fp2(P) + v['scalar'] = serialize_bigint(scalar) + v['Q'] = serialize_EC_Fp2(Q) + elif G2_field == 'Fp': + v['P'] = serialize_EC_Fp(P) + v['scalar'] = serialize_bigint(scalar) + v['Q'] = serialize_EC_Fp(Q) vectors.append(v) out['vectors'] = vectors diff --git a/tests/t_ec_frobenius.nim b/tests/t_ec_frobenius.nim index 203a51f..33e46df 100644 --- a/tests/t_ec_frobenius.nim +++ b/tests/t_ec_frobenius.nim @@ -224,7 +224,7 @@ suite "ψ - psi(psi(P)) == psi2(P) - (Untwist-Frobenius-Twist Endomorphism)" & " Q1.frobenius_psi(Q1) var Q2 {.noInit.}: EC - Q2.frobenius_psi2(P) + Q2.frobenius_psi(P, 2) doAssert bool(Q1 == Q2), "\nIters: " & $i & "\n" & "P: " & P.toHex() & "\n" & @@ -244,6 +244,7 @@ suite "ψ - psi(psi(P)) == psi2(P) - (Untwist-Frobenius-Twist Endomorphism)" & " testAll(ECP_ShortW_Proj[Fp2[BN254_Snarks], OnTwist]) testAll(ECP_ShortW_Proj[Fp2[BLS12_377], OnTwist]) testAll(ECP_ShortW_Proj[Fp2[BLS12_381], OnTwist]) + testAll(ECP_ShortW_Proj[Fp[BW6_761], OnTwist]) suite "ψ²(P) - [t]ψ(P) + [p]P = Inf" & " [" & $WordBitwidth & "-bit mode]": const Iters = 10 @@ -266,6 +267,12 @@ suite "ψ²(P) - [t]ψ(P) + [p]P = Inf" & " [" & $WordBitwidth & "-bit mode]": # x = "-(2^63 + 2^62 + 2^60 + 2^57 + 2^48 + 2^16)" # t = x+1 return (BigInt[64].fromHex"0xd20100000000ffff", true) + elif C == BW6_761: + # x = 3 * 2^46 * (7 * 13 * 499) + 1 + # x = 0x8508c00000000001 + # t = x^5 - 3*x^4 + 3*x^3 - x + 3 + cofactor_trace*r + # t = 0x15d8f58f3501dbec1ab2f9cb6145aeecb55fc0d440cb48f058490fb40986940170b5d44300000007467a800000000010 + return (BigInt[381].fromHex"0x15d8f58f3501dbec1ab2f9cb6145aeecb55fc0d440cb48f058490fb40986940170b5d44300000007467a800000000010", false) else: {.error: "Not implemented".} @@ -277,7 +284,7 @@ suite "ψ²(P) - [t]ψ(P) + [p]P = Inf" & " [" & $WordBitwidth & "-bit mode]": var r {.noInit.}, psi2 {.noInit.}, tpsi {.noInit.}, pP {.noInit.}: EC - psi2.frobenius_psi2(P) + psi2.frobenius_psi(P, 2) tpsi.frobenius_psi(P) tpsi.scalarMulGeneric(trace[0]) # Cofactor not cleared, invalid for GLS if trace[1]: # negative trace @@ -304,6 +311,7 @@ suite "ψ²(P) - [t]ψ(P) + [p]P = Inf" & " [" & $WordBitwidth & "-bit mode]": testAll(ECP_ShortW_Proj[Fp2[BN254_Snarks], OnTwist]) testAll(ECP_ShortW_Proj[Fp2[BLS12_377], OnTwist]) testAll(ECP_ShortW_Proj[Fp2[BLS12_381], OnTwist]) + testAll(ECP_ShortW_Proj[Fp[BW6_761], OnTwist]) suite "ψ⁴(P) - ψ²(P) + P = Inf (k-th cyclotomic polynomial with embedding degree k=12)" & " [" & $WordBitwidth & "-bit mode]": const Iters = 10 @@ -314,8 +322,8 @@ suite "ψ⁴(P) - ψ²(P) + P = Inf (k-th cyclotomic polynomial with embedding d var r {.noInit.}, psi4 {.noInit.}, psi2 {.noInit.}: EC - psi2.frobenius_psi2(P) - psi4.frobenius_psi2(psi2) + psi2.frobenius_psi(P, 2) + psi4.frobenius_psi(P, 4) r.diff(psi4, psi2) r += P @@ -334,3 +342,30 @@ suite "ψ⁴(P) - ψ²(P) + P = Inf (k-th cyclotomic polynomial with embedding d testAll(ECP_ShortW_Proj[Fp2[BN254_Snarks], OnTwist]) testAll(ECP_ShortW_Proj[Fp2[BLS12_377], OnTwist]) testAll(ECP_ShortW_Proj[Fp2[BLS12_381], OnTwist]) + +suite "ψ²(P) - ψ(P) + P = Inf (k-th cyclotomic polynomial with embedding degree k=6)" & " [" & $WordBitwidth & "-bit mode]": + const Iters = 10 + + proc test(EC: typedesc, randZ: static bool, gen: static RandomGen) = + for i in 0 ..< Iters: + let P = rng.random_point(EC, randZ, gen) + + var r {.noInit.}, psi2 {.noInit.}, psi {.noInit.}: EC + + psi2.frobenius_psi(P, 2) + psi.frobenius_psi(P) + r.diff(psi2, psi) + r += P + + doAssert bool(r.isInf()) + + proc testAll(EC: typedesc) = + test "ψ²(P) - ψ(P) + P = Inf " & $EC: + test(EC, randZ = false, gen = Uniform) + test(EC, randZ = true, gen = Uniform) + test(EC, randZ = false, gen = HighHammingWeight) + test(EC, randZ = true, gen = HighHammingWeight) + test(EC, randZ = false, gen = Long01Sequence) + test(EC, randZ = true, gen = Long01Sequence) + + testAll(ECP_ShortW_Proj[Fp[BW6_761], OnTwist]) diff --git a/tests/t_ec_sage_bw6_761_g1.nim b/tests/t_ec_sage_bw6_761_g1.nim new file mode 100644 index 0000000..b69e109 --- /dev/null +++ b/tests/t_ec_sage_bw6_761_g1.nim @@ -0,0 +1,41 @@ +# 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 + ../constantine/config/[type_fp, curves], + ../constantine/elliptic/ec_shortweierstrass_jacobian, + ../constantine/elliptic/ec_shortweierstrass_projective, + # Test utilities + ./t_ec_sage_template + +# When ECP_ShortW_Aff[Fp[Foo], NotOnTwist] +# and ECP_ShortW_Aff[Fp[Foo], OnTwist] +# are generated in the same file (i.e. twists and base curve are both on Fp) +# this creates bad codegen, in the C code, the `value`parameter gets the wrong type +# TODO: upstream + +run_scalar_mul_test_vs_sage( + ECP_ShortW_Proj[Fp[BW6_761], NotOnTwist], + "t_ec_sage_bw6_761_g1_projective" +) + +run_scalar_mul_test_vs_sage( + ECP_ShortW_Jac[Fp[BW6_761], NotOnTwist], + "t_ec_sage_bw6_761_g1_jacobian" +) + +# run_scalar_mul_test_vs_sage( +# ECP_ShortW_Proj[Fp[BW6_761], OnTwist], +# "t_ec_sage_bw6_761_g2_projective" +# ) + +# run_scalar_mul_test_vs_sage( +# ECP_ShortW_Jac[Fp[BW6_761], OnTwist], +# "t_ec_sage_bw6_761_g2_jacobian" +# ) diff --git a/tests/t_ec_sage_bw6_761_g2.nim b/tests/t_ec_sage_bw6_761_g2.nim new file mode 100644 index 0000000..c3c2269 --- /dev/null +++ b/tests/t_ec_sage_bw6_761_g2.nim @@ -0,0 +1,41 @@ +# 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 + ../constantine/config/[type_fp, curves], + ../constantine/elliptic/ec_shortweierstrass_jacobian, + ../constantine/elliptic/ec_shortweierstrass_projective, + # Test utilities + ./t_ec_sage_template + +# When ECP_ShortW_Aff[Fp[Foo], NotOnTwist] +# and ECP_ShortW_Aff[Fp[Foo], OnTwist] +# are generated in the same file (i.e. twists and base curve are both on Fp) +# this creates bad codegen, in the C code, the `value`parameter gets the wrong type +# TODO: upstream + +# run_scalar_mul_test_vs_sage( +# ECP_ShortW_Proj[Fp[BW6_761], NotOnTwist], +# "t_ec_sage_bw6_761_g1_projective" +# ) + +# run_scalar_mul_test_vs_sage( +# ECP_ShortW_Jac[Fp[BW6_761], NotOnTwist], +# "t_ec_sage_bw6_761_g1_jacobian" +# ) + +run_scalar_mul_test_vs_sage( + ECP_ShortW_Proj[Fp[BW6_761], OnTwist], + "t_ec_sage_bw6_761_g2_projective" +) + +run_scalar_mul_test_vs_sage( + ECP_ShortW_Jac[Fp[BW6_761], OnTwist], + "t_ec_sage_bw6_761_g2_jacobian" +) diff --git a/tests/t_ec_sage_template.nim b/tests/t_ec_sage_template.nim index 306258d..7132b9e 100644 --- a/tests/t_ec_sage_template.nim +++ b/tests/t_ec_sage_template.nim @@ -70,6 +70,28 @@ macro matchingScalar*(EC: type ECP_ShortW_Aff): untyped = bitwidth ) +macro matchingNonResidueType*(EC: type ECP_ShortW_Aff): untyped = + ## Workaround the annoying type system + ## 1. Higher-kinded type + ## 2. Computation in type section needs template or macro indirection + ## 3. Converting NimNode to typedesc + ## https://github.com/nim-lang/Nim/issues/6785 + let ec = EC.getTypeImpl() + doAssert ec[0].eqIdent"typedesc" + doAssert ec[1][0].eqIdent"ECP_ShortW_Aff" + ec[1][1].expectkind(nnkBracketExpr) + doAssert ($ec[1][1][0]).startsWith"Fp" + + # int or array[2, int] + if ec[1][1][0].eqIdent"Fp": + result = bindSym"int" + elif ec[1][1][0].eqIdent"Fp2": + result = nnkBracketExpr.newTree( + bindSym"array", + newLit 2, + bindSym"int" + ) + type TestVector*[EC: ECP_ShortW_Aff] = object id: int @@ -115,7 +137,7 @@ type twist: string non_residue_fp: int G2_field: string - non_residue_twist: array[2, int] + non_residue_twist: matchingNonResidueType(EC) # int or array[2, int] # vectors ------------------ vectors: seq[TestVector[EC]] @@ -127,6 +149,11 @@ proc readValue*(reader: var JsonReader, value: var BigInt) = value.fromHex(reader.readValue(string)) proc readValue*(reader: var JsonReader, value: var ECP_ShortW_Aff) = + # When ECP_ShortW_Aff[Fp[Foo], NotOnTwist] + # and ECP_ShortW_Aff[Fp[Foo], OnTwist] + # are generated in the same file (i.e. twists and base curve are both on Fp) + # this creates bad codegen, in the C code, the `value`parameter gets the wrong type + # TODO: upstream when ECP_ShortW_Aff.F is Fp: let P = reader.readValue(EC_G1_hex) let ok = value.fromHex(P.x, P.y) diff --git a/tests/t_fp2_frobenius.nim b/tests/t_fp2_frobenius.nim index 8b5847e..cc37f49 100644 --- a/tests/t_fp2_frobenius.nim +++ b/tests/t_fp2_frobenius.nim @@ -18,6 +18,7 @@ const TestCurves = [ BN254_Snarks, BLS12_377, BLS12_381, + BW6_761 ] runFrobeniusTowerTests( diff --git a/tests/t_fp6_frobenius.nim b/tests/t_fp6_frobenius.nim index 99b0e45..cc9701f 100644 --- a/tests/t_fp6_frobenius.nim +++ b/tests/t_fp6_frobenius.nim @@ -18,10 +18,11 @@ const TestCurves = [ BN254_Snarks, BLS12_377, BLS12_381, + BW6_761 ] runFrobeniusTowerTests( - ExtDegree =6, + ExtDegree = 6, Iters = 8, TestCurves = TestCurves, moduleName = "test_fp6_frobenius", diff --git a/tests/t_fp_tower_frobenius_template.nim b/tests/t_fp_tower_frobenius_template.nim index ec08121..6c9d272 100644 --- a/tests/t_fp_tower_frobenius_template.nim +++ b/tests/t_fp_tower_frobenius_template.nim @@ -61,7 +61,7 @@ proc runFrobeniusTowerTests*[N]( ) = # Random seed for reproducibility var rng: RngState - let seed = uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32 + let seed = 0 # uint32(getTime().toUnix() and (1'i64 shl 32 - 1)) # unixTime mod 2^32 rng.seed(seed) echo moduleName, " xoshiro512** seed: ", seed @@ -77,6 +77,7 @@ proc runFrobeniusTowerTests*[N]( check: bool(a == fa) staticFor(curve, TestCurves): + echo " Frobenius(a) for ", $ExtField(ExtDegree, curve) test(ExtField(ExtDegree, curve), Iters, gen = Uniform) test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) @@ -95,6 +96,7 @@ proc runFrobeniusTowerTests*[N]( bool(a == fa) staticFor(curve, TestCurves): + echo " Frobenius(a, 2) for ", $ExtField(ExtDegree, curve) test(ExtField(ExtDegree, curve), Iters, gen = Uniform) test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) @@ -112,6 +114,7 @@ proc runFrobeniusTowerTests*[N]( check: bool(a == fa) staticFor(curve, TestCurves): + echo " Frobenius(a, 3) for ", $ExtField(ExtDegree, curve) test(ExtField(ExtDegree, curve), Iters, gen = Uniform) test(ExtField(ExtDegree, curve), Iters, gen = HighHammingWeight) test(ExtField(ExtDegree, curve), Iters, gen = Long01Sequence) diff --git a/tests/vectors/tv_BW6_761_scalar_mul_G1.json b/tests/vectors/tv_BW6_761_scalar_mul_G1.json new file mode 100644 index 0000000..75b220b --- /dev/null +++ b/tests/vectors/tv_BW6_761_scalar_mul_G1.json @@ -0,0 +1,492 @@ +{ + "curve": "BW6_761", + "group": "G1", + "modulus": "0x122e824fb83ce0ad187c94004faff3eb926186a81d14688528275ef8087be41707ba638e584e91903cebaff25b423048689c8ed12f9fd9071dcd3dc73ebff2e98a116c25667a8f8160cf8aeeaf0a437e6913e6870000082f49d00000000008b", + "order": "0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001", + "cofactor": "0xad1972339049ce762c77d5ac34cb12efc856a0853c9db94cc61c554757551c0c832ba4061000003b3de580000000007c", + "form": "short_weierstrass", + "a": "0x0", + "b": "0x-1", + "vectors": [ + { + "id": 0, + "P": { + "x": "0x5545f882f8e079c50c17588c42111420a6ac7a9a44528480efa364358de0fdbd1f6af42ed542e285c70c7ea7f30154d4ac74c100e91e834159849cd44668c564a2f70a8770edc74f4fcd226598a02d4aaf2846c6fed2ed74656b9a2e6bd628", + "y": "0x3f114b0d3c383561977824d49b0fa01c915025bee25758db6922e55616e7329f7c21478c6c5183b306ef22c779bfb5011193a81cf2e47011127344d628b2f1c7397fe6182dce2070b4ba5fdb0b9987d5a23328a4cc8dd6ca8847f6ec11e814" + }, + "scalar": "0x16f42b8a4f8f69aee37bf282d4aac82b7bd1fd47139250b9c708997a7ff8f603e48f0471c2cfe03e77fec558ef287c9", + "Q": { + "x": "0x299c105c1d3fe580706b83811bf4aae65bca7bf4778aae0cf35f75fe62b68335b82ec3786a4f25d459331aa9b369316518a6f8acf07fd494b42a72521919eaa720bd67ad01714df0e7e0c78e9d0e59c63823563742111a405000090603f7cc", + "y": "0x893f6d95ac2085a14d452c8c2ec97f9751ccd4dfbd8fd737129bd5b30fec75b17845baa290966222a33e4336ecbb550fa098d5b1e940f98855734bc1ecdf2a39d6f06c7118e2fd68e340557bdd4a792ef34dc498406c8a6d1388a72a9b40bf" + } + }, + { + "id": 1, + "P": { + "x": "0xbc521723a760d04132b9bc4e8b5ba8ba87c6856c9a254fe169b7d7c0c269bafa81ebb9f70dd5d49a328996605433d92d132d76c1e19ff9514e83531cd5c53ed40980ecf3cdd66394a37421070bc697fdf2ac057a5d3622ebab925531267703", + "y": "0xa04a6eeafbf50d540e29231ff57b4b0ca52b1c1873228c9fe4fd0b09d67ed67f9ae7376ce1572a8ec063e92ab6ae1dc94b4cba5079c92da32ecfed47214c0520ebc410c8ba53ce933a8e450d93e305e59c947b739c3de9550cf85ffffc0cd6" + }, + "scalar": "0x373cefa5f6ac9d1085a890088c51eac4edfebf978946e523021c72bc7db6b54def07e6b2da232a8507ac66a7c7422d", + "Q": { + "x": "0xebb58d673f89191cedf4c3ebb59877703d36172e5888d6bfa96298f02b7ac98c208a4a896c3ffb8c9b708b0d0c0f7509dc740f4b3e9567fc7144cc278c73531d2e964fe146f314a4ab00d0777dbdd2589e0cea78d7d4ecd6781e506fccc9fa", + "y": "0xf6e96dbf68e6ce30c14a2ea434e4529bced7348e644e62a8133c4f749a54be12ec75c8dd1691e32ac3e0e803f45fb7ba4cb5cc77def0285350536f4c53f8a697c07c578c1b8ee798aa1f9abc6f5158d5256c966033e91a2a79264be14dedc0" + } + }, + { + "id": 2, + "P": { + "x": "0xde30e20472ef1876a39b7914e6dce371524825cb36061eafcfdda891ee2af8f57379eccc33397d8af62015b8c6dd479d546cd4a5a6b6fe9e7228b79b0e0b698e6a624a8908b9cff01be1e26162e6908da2767b030927e5f99ec01294e47274", + "y": "0x155676883b538dc85db423946ab25ec36f8789adf71a891ad71a50c9b330c4c728bd08fdd7d411a3f938c512cb3e7676de67d191ba84dcf8424c2cdebfa1824816a3787d9f10ba3fb9abb35b0d3ecaeb9ac86112f0b0578fec724c48184dc8" + }, + "scalar": "0x25dbb5bdba82fde2fbe2947d0b49131d8c5116e57423d7543cd4525af2f97abd462e08b0bc81c48f645759bb5d0512", + "Q": { + "x": "0xfd70f9eb071c5a45507ccf6c21129c2f0afdcae1d5a2950aee7979bc63a6145bb82ce4a10e727d1981be7d8299d44cd32dd6b10b63d3486b02b0608ffde5e56e54c8ca45e8e5776a5036459fe8824d44c01a043432dcf767d3551babc2d93e", + "y": "0x19db03fd3c09b89b7d7e711c49bed8f172d6b7dd9487e402e008607195276721d95f9b204d9dbd9ecaf9c4e4c7c32bf88123d9e9c8c803cec156feaa8ba91a3dd1a21498ad07d416b35f7f0def99b51186ac9e2d9275ae521d26377f080e0a" + } + }, + { + "id": 3, + "P": { + "x": "0x87fac29ea121e5888c9aaaf2ff931cb37b7f6c70012b147711a0236077abedb871f6dda3a1c0d79d7cc3d38c0b785721cfc28a3720532dadd147d14301c55ef9485a1459bedbdc4f897eea390b40fbf77225a9e81bb9a310f7c8438f960250", + "y": "0xefba3f41a1b415cc88293cd0b09b6e4cbbf7df5bbed1aad46656826481277f3e288211f81dc67ea9b8a0a773851e1af9ea28080049579e3c88f29269ba39cb74abeac52275d16b75a2ee685d20f03d0359eaf33475cb283716f1698ea90e13" + }, + "scalar": "0x1a5f4af45fd88b7345433d8eb1b55be02dd782f825f901078267cd2c5a702877f0161ed2339c026fb9841a73c44eba9", + "Q": { + "x": "0x52473f405d568dd6018d309a1b677f9ce5ecaf37a41f2857363a9b3e4ce1973c11637d6eb74b1b507ed8984504cc11c5f3528bb625b117249f0f5b823cf12f1c0545d227bf71d56528b02ece7a60dab3fdba92a11f8b3e91366f511a5ed1a0", + "y": "0x8b7be61db413913bdcaf27b24f5fb6aa2f7a2a3fc71b1bef626a3a05cf1a3edfc1691027041b004f43bd8dcc82c87d7058fa3c8ca59996b2b3a02ba613d6eb3f362341fcaf7f651b003638672c6b624e5c66c2d46e968f4b72f7880588e9c9" + } + }, + { + "id": 4, + "P": { + "x": "0x1e4967374ce67cd73d0a9c88e6b6a4535a4dc3125855806b3435d8e0b0b14af8f46f5e8d61d5e74d713ec57ba303c0ce51e7fdfa9c77a894ecc6f9608f79ab8d50233ef4a05ae2ad42c8c62dc4169fb50ee484c2e51b96b54ea68943411b57", + "y": "0x46538c65b371d8cf43f051b222155ce8c0d4d444749272770e5007625b59a5206daa13957eae8b24629e49116a2d5f2df76593212306ec0b19023002caf7de4a3309b2cc9e040c45878a29767cd2b914df3ceb7070a3787c2b303d1aecbb22" + }, + "scalar": "0x1656931ba49c3036bf5e127d7a7a609b093f5fca57a6d8f2dd64b0bc11bb33d8f60ca1af2b149e991f1e8035fc86ae1", + "Q": { + "x": "0xe6a74aecda6866bcc332e59bb183320789be7a9fc26206da10c661a1a7215f777bdac451e9c543c9470b059fefecc3a3e0f56ceff3c37b40d74abbf31b09506aeeab97a74d8bedf5343b1eeea1caf4e40e376d17c2093065b423b1c1e65489", + "y": "0x34a9fb3176f70e8b758033b8274a5f343d95e73e6f819af4ae9a4b5340635e51f823cc7dab3d149e22d5c3508b3ee962f2777f3f101388429c7722fe073d78fbc9256bdc8c50028dee1ff7d6d2c0648c73230f0897c57dfd6131074fd9e368" + } + }, + { + "id": 5, + "P": { + "x": "0x469635bb906ebf2524e4dd42939f9835009d72040b371f9bd0b5f02872cd7bc378cbba4e349ee6004fe3cb979c9cd13714ec130ec42eea98ae771b28cb7adcd4cde1007a011e8dbc9944d217dfdfb93cf24b9a05e04f1a6945841c51faf786", + "y": "0x43c135a716eb43309899293af6f367bad79fb2a87071e8fdcd0a64b40d59d6d09b03ddcdd23b1371c56aa697f6a9628f12405e3036dd22ed21ff1975333a66cd761fb2dad9a6368dff94a170109bb1c1725fca912d43c3fb9f1f0cfb4f1e12" + }, + "scalar": "0x1568c3511475177a15f32f53fdee1358bbc3456140aa92b4565ea0847c0fb2e1e513cc6cd67499b5fb3d2408ab7e447", + "Q": { + "x": "0xf9d4e8bc31485f711c8ecb9c14a4bb0c8c503c71b12d8e3e09726068794eb033ad7742728d2189048b8fbb60947f3d8518a04d75fd0b88e4416d67674ed5dfd20e9e6b74cacfc91584158c203fdf1a52901f794cb166059fd119a7bbfe45e", + "y": "0x89d6e336e5a479e3d66831be6afe6aa4bc00539585d94632804325e21a2a1d6afb4c4d63b08d9b8b3f92366f9e62528d02206ee2fb985d67f9bd80b959a2348ecddae93971e0bd36b3327cf7f3b60eb46cc5e6a2d7ace3b427cc5a77c45895" + } + }, + { + "id": 6, + "P": { + "x": "0x69621d65f6712778c4e8b774b1b811e4eba1c3659aee7d7d5c13b2cbb050d73f282fcae8179c62a0936a69ae0d8c33fc2e935d221b1d881d34f18eaad986f2b42f9da0bf132e73368f95addc66a1f8dd567ba0b2e64a0bb50e8684d1dba527", + "y": "0x8b3db64d3a25b11f0b60c58c2d810f8f29c17278d983b25391b9404a6b7e5fcc117eff9e718083d538ab872cfb9ff96dd380665520c8114c3cab62ac331e430a241fb216b9ce96729229803f505dc2b7d3f0370751037db29c7b77d6984f93" + }, + "scalar": "0x377eb12184799f184744146162e9acd6ad59a60e1a7a6ab4c6437148569d5d30a0a30ea926046ab6790c3dbf0b397b", + "Q": { + "x": "0x1e9bf1fbb3e68629925f240b8f4e013d88d539038d872ee0fe8fddd69dd77c2b937d7ead319dcd1895e095f2613787b2d7e905bb86c283301797c9339333d974e3785eedd913c9cb90a048810ae5fd357a50d0c438a6da35cb7da51f5703fa", + "y": "0x744a9a604a0cc478a6cca7d793c8d427f540ff53bbd18e21deca13f485f8c19fa7e7942155425a5125ea6ee3f3f966384621ca7f256166375b40b5448676c1386b71325054031978e0ba3bc3f14aace164e2cbf3178be6b19b2d26605da9b8" + } + }, + { + "id": 7, + "P": { + "x": "0x880e24712c86f8e6d0951e510a889c656f39b9e5d3008ce1df691d5bd5464cf7673e6f15aa34467ab12edc0e899e24ed4ae1b6d19b23cc172cc80f681e8978098d256475a199361b8537e430b9b1e476abf8daacea5fd5ae0585a0c6ed5923", + "y": "0x2d0b591b1f4957c7e7f4b424b25c89f58b54c3b82113c4883ca4eda5b7964c616837166e78ffe1f492311a8268215c5e5b1727722e6df4bc374e578f37e30fe9324b1d161a3ebe7db9f0ce1e56261a333f21a3a86c1de8337cece77dc663a4" + }, + "scalar": "0x1a54bf2547af5d9cf0af76ef5a8a77d1ee843b60d4036c6b2e0382c0942cb1a93c45ba61ef313e31abea00b8643a39a", + "Q": { + "x": "0xd37a301b2d7e9558fe72fc981ca584ca51380fd8c5fb8ca42807cc7b2472db2ec82d142423949e8f8bedcd050bd1793aa6f71e4d2062b9c725db264323d42bed74dbb1c1a2fdcc149eb104bbdb4879516bb631530413e3487886fa9f950feb", + "y": "0x65140b12709b43a39fa03d53e7b262321abbdef949388136a5286853ee5c16a2c5f6c9f1163ffa5f91d47222896ea1199e5749c23d81dde1cbae5e84f9c45066dd39db4e882af78fb9af1c328b4a09e074e4ac585eddc9e438dc52b1d1b228" + } + }, + { + "id": 8, + "P": { + "x": "0xd6e05afa1604cb7a083054dc0cc3d511c0354e4074a0a2e852f81209d6077a3339fa734aa97273ec8bbeed9a1cf80df88e9b849deed6a8d6e1eeead7bffb7c55cd401abe3773fac5e71d588b67c136dff46c3a87c1281d27e81dd30b375f89", + "y": "0x2654cf67fec9cba1e4ef3a7f6defda140b9392b0cf960e0fa674846a0b85f6d691c40b8fd86f080da55555cc8e8b49ea008d66132f3f7924ab939436a26b37300d0b1e5f0e4a9fad6c47efb06557af7960f24821d9b44877ca3c7697fee530" + }, + "scalar": "0xf83110568923c9515755e6c030b5dab546348eeb3e5f90a769dad3decfd7b3d43dc95624a2caab32626a00f3c92f6a", + "Q": { + "x": "0xdfc0db9923bf3bf5fd043d1860402770ec47f680a2ca8ecf31a1407fc4e765d05d8fb8d7e66a338049748946e2a85feeabbb0631dbe3f7a33248a9b5ee8a5d768a0deb4d7e113754d1ca9758c8f0c391a9bc3c89865082345442eb27cd8441", + "y": "0x1668e0b639522ae11dc72891e6f3690ada39888f6f8c7ac92a89b4a73bc42a5dc68c1ac3b0de15d243b33546f33d30e4302a8636786c4823779f3a51037d40f2adbe01a6dcf344f3f91c4bddcbfe0628e57d5dc8588254e033325f8d05aabe" + } + }, + { + "id": 9, + "P": { + "x": "0x12169c4c3e8e254a4c89c1793cbe1b1c34d2123de56b2ad1dc991f8388810774a660f637ec94d7401d5b96d2007a6d68c8a435ca71928d4c222fa6a0710e062bd5b35454e098178cd4a6161930f7ec64b6a0580ec14815b937dd3eac7c7e977", + "y": "0x90c69ca2f7ec3f4b5b915b8f325dd4dd5a1ec26a31d1bae8f10f611eace0f94bdec8c515ecf45a2d39dbe29c8703c3d0564b8e331172bff08b3be5c48506e7c30f0548ad543302df171cf561e8b3b9348597cd4bde41d66d14aec7e578c52e" + }, + "scalar": "0x115b6bdff18cb8de3f71fe01590f070f1e108a299b60bcf8163534c45d2eb401b2886507be36b85852cda082f4741d5", + "Q": { + "x": "0x28ef28c54e08b29e4c25d141272795df1919d28f8c5dba50057090f089cf8b2433e2e83013ebc4d271fa84c71a88d5b0ffe7be95d921384d873a77dccca409f48069d8ef5459077baa4e6416332047396f186d14505e066622adb71ed972bd", + "y": "0x10b08059ecfa23c11606841be22ddfaa6ac3cbcc00dadf59ed2bf01a8e0b032f73ef09d248c5ec55895945a71985b59721f2765ff271750d2a83d9a1c62c31e209ba09fdb205d87ac206599698a25f17a9e22014b1f5468961b57316be6f323" + } + }, + { + "id": 10, + "P": { + "x": "0x15f1eab3d6f9ea528647e74ed1974cede345d7d17a6a89a230933877dab9c798a1a4f9699b69316560208e02bbb61fc2de6f6360132d986b1c738959b86754cc29c28ecab6dc36e5630766673c8b029e73ab3994e88d9ac0bf613099c917c1", + "y": "0x90748552b18cb01d9ec84967daf03f6b8e8e1c2daafe2c19d80cd3eab20763bb293a2cb3ddfc4ffff172bdeb633bd0ae061b621bee176d8914fd125cdbaf61cd28bc67b1a5f49a0a404f5f6a01dcce130dd25651d9753be0cd0cbb7095e123" + }, + "scalar": "0x10cd8e83c7142db6b415301882e5afd9c5960ea4855bb76eee2f1fe6250630fdbaac2918c86a665a5a7e1a2ed2daa62", + "Q": { + "x": "0x3db6f683f04025665c23e3897cb93232161104d320fd03cfd3a068bc05941873c46a21a98305679b2f15b200580c505ff11dd7f473ab006c64198ca2f214224ab5580e593d5607c93279d23c781a2557e0adfa5dc6ee6e85b91a118661f882", + "y": "0x6922c1eaac86b64497d7949efda303867f9802f5b15588d1bc2aba86b578be28409cfe098875d75ad3ec1a8f17cbf163b8a4ab655a25405985960fec287fcfe557ed2a5b04e2c671a0a293e5ae973ba60724837ad4ef2ea6c9f66d0a16fab1" + } + }, + { + "id": 11, + "P": { + "x": "0x697f5f580ede11feea2e9b9e74f5b82c1cf17233b853e6e685e98397726d12be4b96d867a98e5a565ceadaa23999a0a6ae9588f56da323032fb41760d0dd8907a79d3eb09c0d683d47cc1542e011c7d7ced2fa3ae1a22ffcb4c31c3df7d346", + "y": "0xb213c11e57b9d92abec187cdd6dca14afe82142dc76b3d97bbc7dd3d5d6367e0133c00c557e54d808f623d7eb1b4077f0b4126dad0896eeb19d8533e369a4027110fb476fe95acc7485a54cc87301654a30abd8d3e620f25930412c9486db4" + }, + "scalar": "0x111b62aafa254fb7b237323f185f6c6cf34ebf5cc5e2728a5d7c3cc18c65b2b52ba8da3e12c8cf06ad4566e9811ce13", + "Q": { + "x": "0x3586b34e285f71b881c9db444fa289c32be5a90d92a674e529a959c46e5ffd0f10ef2c6759f37503da6f2bdb35496d67ea27e77785e98c0ed018f09875084591e9cd0ead04caea9139b613d1955639873aaa5be951783a4d9e79d4886635c0", + "y": "0xea9cca12b22fd930fd7d7f4b4ac38367e9de328536ae152efa0127cc2a6e146f9167a836dd6c7bd234c3c4c0f20f7c5adb9a9b7f1cf353f6c0cadc2159206a640b338730b9bf1879503084ee8a3dbf288c301f1cd6564aa04aef60f783a329" + } + }, + { + "id": 12, + "P": { + "x": "0x58e44444653b857c32777f0d4c6bd24bff430cd4b5d5e2c1057a15b8dedae757ff17c7037962212a9df8f5127e9e2e002e3ac58fbc24d178a399e30c57ed010335f5ef1625994eae17436dd8d4aa4b6c3ae6a235c0b69692ba564a9272d453", + "y": "0x639fbfb13eb9394a48ad293df061d96a49ae75a89e0ef997d06c92c5113a16f86a8ad537a0cd8f197eb81508d156744ae2ee802c8806932531bf686f14fca68e6928a75c270885278c9d879e305725bd385b7f189ca8d4f3d253ea04775af8" + }, + "scalar": "0x10b14c3e5e82f05c146bb456bdb53ea6c80e9e09f42ba9f0dbccf1e68f814a06563249c586925461804ce4aa14fa21", + "Q": { + "x": "0x7260ca99313ad686f58af25f49ec6d4fe0ba3b9d95ebe8fb35bff9f07e1e071c0c7923135949d083c1f20fc21b602964282eb59cf2708a8cd403e992cb30593a816eeded398b8a4809e8956560ae77f4ddae4e5a6282343af2edde7ca8c8e4", + "y": "0x8225ea2bea3c72341ccffd0a588e0f7c4c54389519cfcee454a8309e8330433b80318e2bfb9ee00583931a9c8f86c5a566f5139e10145c32988c514821bf25707c226aeec499747ebb78dd37f6d1e2c5a0fde9e57d3cc4b0d80d8c000aeca6" + } + }, + { + "id": 13, + "P": { + "x": "0x2b03d7c265b827693ac07e27e8b367e3041fd5497f3670975d37b405a4b364ed458079c402af6d5556a1c5e5dd76da504a2d443268798ed5df04067d9e8fea839dc044fce12952822e639ac715a76330192f4b01e15af4a704c372241c61d2", + "y": "0xa03dc31b5189609bde8b309ad2b688a9aae1f9c7ef475bff1429227fa2c5b92589b6b0ea5be9b8fdc5785009d2efb9a6261e1cf5925fcb22cfc0de7846f626f1fd54f04eb503c5a8cf847ee8853769d2d7759323ec08ed60f0843394ec1bc4" + }, + "scalar": "0x8232ec21e395273500e7bcf90fea66aeef49687e7f855567d0d4d42f4d60aea8eccf7bd6fe09e7fdc83d038d1c6bcb", + "Q": { + "x": "0x276105138b4531e049b3b60648937ea826345744fae675746b4f311ea675bacbad6a3b47650a62b41448c4d5829bf3d25e1525799756427fd831a3dfce6c9db9827710052c8a305bebf3d6c226951a4aa683b4622bb61f7c4b07517c85f282", + "y": "0x3ff4b92d617ac4c0a342d4440b59921875f199e56c325858660460e6a6fd420053e4725c151c0463c10c6120177895d427310317c0fffdb88bba19fc0ff4997517c7f5605a3ec5178be021e554582ea5608d8c6713b22e87afbdf7e9963ff0" + } + }, + { + "id": 14, + "P": { + "x": "0xf8933a5f3a54ea1f86cb35818cb92244f5a20f617086130d8a6d7e875e94a6eaad11c280a7a73db4ab4a556b22409774a56139f7d774b9bd78ed13454f0498feabb17164136da08b1b1b18667964d804824ee83813cd62d2de38ea8e126790", + "y": "0xc87a5d7b8837c513a63f6dcb17653d930e4932200abdb323c2da8e3db3ddc4b09a12c098a4522c33e5b64c564fbc92a34d7c9b0bcbeade9e790a51a652c3a27c0fd3d848ae8591623e334ab69c8216d6489db05af084ebc6a5bc4523d45471" + }, + "scalar": "0x11b1832364c17939ccf4ee4cb9eefc2293ea255080154c4c9507505f1016d16ad182a00d52673d6abdc59406f1c7274", + "Q": { + "x": "0x6c1caba8b68187111dfc351fb1b76656d27e49df8b0bac6dd0d038b104452a27d649fc7311966d671d55c8f72f1d493bf4ab976e79ae56fc7f894b35a6459b6e9e24fafeed3421eeea871fee9b770c284bf566710f0a01fbf071978e68143e", + "y": "0x48607f7479172b147662fb31a3b31ee42ef69d984adad5852d04eca5f0b6cb7ef571b2821310da07144e12852701242714a7e6c95f098e2ede93bcdcbfb1d16213194538449190971d2523a3b5206505a6ac5b5dff34c40a8ce0d5b8053a95" + } + }, + { + "id": 15, + "P": { + "x": "0xbb399b9046149d8a675b1324a2859bf3a6770581f9cd0c520e3d0e8eae2c6c67901377dd0404ab16c89a2d4719266bd05597dcc94089eeb03227a94db259173f00bc69ca9f5bf184226e11af635cfaf601b44a15b45c3dda4f8a88ee0ac70", + "y": "0xd6f07a312a30052f67b738ce24efa08ee46fac38c7e97eb5800523002aaf7e0fec725dc3e7ffdcdb3549b6031b839900c02199114963ad155f56fb2aa40c0fe64be27d3d9e4fdc7736dc9b084332e199f030de5bb1c7c282e531f89daeb6f0" + }, + "scalar": "0x33c0f4ab242f0e6d1cb2e44894eac39d847396d3cb5d8c2c90bb1a180b7a4cdac2c15c549746025b5a17e0d028efdd", + "Q": { + "x": "0xfe5f33aff9a2c2d92bd90c5d162f9bd0f4dc03eb0f9967b3224260e11069ca9cb537fd2fdf5aba5cb663b22d300e9f5b0602cd9017c2e2d4619451054bbaf3a412901daeef028c0fd98c4565c18263e23501f9e391e3f5788e3184fefc32d7", + "y": "0x10d970b79e54d3c8952b65ff5c453813abb7799506c36b53206a6cfb88df67a8a256f32c29585f81f1cdf5a9cac272e78929771f4e2b09cbca77451cb0c8f1a48c5454bfe421fc2c82430e1fbddcf2d7e4083d0e75c21953ec5320f18dec27e" + } + }, + { + "id": 16, + "P": { + "x": "0x1107904da7203f1e7239bdd297105bc4987c9b9d5bea8b5a0a1c6092e2a3ca5a524aa4264c3042ae2687e4eb8955bf5657930fcf7b9f258ae943ada0ec13e4fbbb8c0f283b73008337695b8bdc3032c51c9923783c4e331de655c4f8029b085", + "y": "0xccda560322a4a531a6f983d9e9c40018e7f0427dc6619e229d98d729f99a5fd2953edd42cfa7ca9e1f65efbb7beb78b9e4eb1ce4871ace2ac17e16c6e74a8948151a0cb746fb29a3dbc322643fc8cbfc2ab2445ffee64f29c1bb52d1403201" + }, + "scalar": "0x13852988844cfd5e7901051e9934e8704a4bdc7d815a29950a2f1a9fe95ddcf831e7f9fbbde5495c052b3a31791a88e", + "Q": { + "x": "0x5632f1c886f483ec6137dd19936a7a2bcb0614becf8958a81cb9ac11a070e057435ec17550debddaefa4b210a2c543ddf67223886449414b61502a0162c7eac10ce07c9b3f8bdd507a620a6d2350e1d68df7b1dfc7201f6f3e5c3ead922862", + "y": "0xb8af081a8fbdc1e93d6731405fdf3f58b11af7eb7a63469094cd67148318afff4677f0568c1f7ba4d4ddf26733bf46b558a2c57ca00ea9df10093b11691e94e913c23ffe4e50544db143b00527839197cf4fd7a54b7fd2920cbd77aee7b246" + } + }, + { + "id": 17, + "P": { + "x": "0x4552ddafa5505e6a4997360bd34716cd65cbf863982c0565a925b881f9a61972fa4e01d93258a5901f784708df5091c693c7521d8664b3cee234f75009a3ec52a0a34cd2b3508d3a017c406b98e72393520057d926b4046e48a9e3008b31bc", + "y": "0x339c0c75980440d5c8210bd6bdc34a5e8948ab4a15dce47bc8d0db818d024935b312dc07990c00427bfa942843bd81d94fe19c3165d7dafa5f55b79713a3599d35c39949e9746fc24b2a7ec8ccab2b8466241fa07b0e62646d1dcb69243745" + }, + "scalar": "0x9461c64ffcb02128f9b7d41593d72369430f19ad5e5ccb642fb4a6f06c883cb15c22076ac55e54e72844fd1db1cc3c", + "Q": { + "x": "0xdf81546f9a71617e02df5994fb4ce66637937a145bd10224a8bf2dab4b37337fc98e91cbaf38c230a055bd55d2885ff7f55bc1dde2d8934faed68eff47c3fac0e980d06e93eb534b2ba8cf3e2d5c34bdd01d410fff80440bbb0fe81443ae54", + "y": "0x88ee080aed9b3119b6a8cd9fab05a2bfabf72d7b7430aab4fba4645226eed7f0505313b6516a1be00f7f3a75d282d7a3653f4ef80e2c6233f6ca538d396976f0aa3a6ffd0e7ef552e161283412a681aca8f95e6a7af416ed72448eba7a74ab" + } + }, + { + "id": 18, + "P": { + "x": "0xf8e2c84f8c568ea6b657b15ecd77640c8cd5b5e3d36e13bd17274d587b5543fded2051ec7d77cbe27c07046fbfb2d4c512300fdfd4173e74b86333a002951eab78675d196c390d01951ec501c2377b2edef01d084b2c3419bff0af38e96034", + "y": "0xcb7cb10f806298ee53f1c7701c9935368a5565e5ad3336c18d61b6c5af98b7061dd5a7425b8874dd848412d85068d382ef7dca076e356f17f1754b813dcdc1eca4ee7bdca17989fce8221001654da5b22b78ddce75a335edc5725e7331104d" + }, + "scalar": "0x15c24b92513aeceabcc01ebb8d3716ad27d08c210fbef2571765989d2a997e72a76264bc1a06d71617d593a661c7400", + "Q": { + "x": "0x17a3a7716d0d783eb94dd119e314128c4ef5e6ea030d3fd5d9dd40bf0e7f4151e075c67464a60dd5fad80e7ca5cdbe1a99487f2c2878a4437cc3bbae619ec55ec15a2c6158104cddc008c8f087d3cc8a30355f803566a2cc396c900d7d16a2", + "y": "0x104a0269de9c40e37099188d332577ff32465a402ac225cce740a0b9344082c8fab935a59523a18f564591dd5c187a18076aaa08848e08d861d27e2cbb25979ee5d233f625e64d12ca3d53fa7ee9d10dd46133f099e50e7520ed4e4177a9a2a" + } + }, + { + "id": 19, + "P": { + "x": "0x8a265b90a54146d6988fb48cd40fc5ed498f9fedd2c91159e6b2ba0f050f067b7b4eb46df5159695437f61d61dc234a5b23d3507d86ab68710dc3592539d8541416b72ea58304d596b0055e758fcb2b9182fddb9e390d8e0fd870b10d01877", + "y": "0x30f39b82bb542ff5315295fefc6d865b0efa2c541139da721bfb8281e670682fac600ba53117536175813997ffb8028f54f82d1f4b54c3abe0a1931405de875822f7dc4d6d22083858f0b8e9fca68926784f18e240d2dd245f6db93742a8f5" + }, + "scalar": "0x18bfa7e290a9a4c302b7593953faea9aa53c6cf92302618423777d35e2297b5d155ee2e2838653ab8724efcd460b962", + "Q": { + "x": "0xf794363167f6605bd7c7c500814440f0a622e18be55b201599ef7406af39a9a68528fa9c7e2a39c5fe4e0945b547f5956773550595b4158aed82a23602f798b92b2aef7a3a4d51a461c3a4c1360c608abfc8d20e38f738882134dcb069af57", + "y": "0x6cd4349c25f202ca0e33c4377a861fc0930fd3eba9304be0e3c82b3b52ec8257e81d05480ed5dbaf39202543d6cb20436cadcd578f82e96c3483a534c5b320057038df1c82ab56f402a44d814bad2c65ceb3a69c000e7fdb2c699bfb855541" + } + }, + { + "id": 20, + "P": { + "x": "0xbaf7f0847742ce33ddc1d08434c05d8b9c7dc13aacd8ce37c6a68da0f3c47b8ae97d345d288c36131d61271b0ed1b298a48bf52a9cd7c9ea472520f0a6d9653b21a0ccdad7c13337677f1c43b707f4a80c83635947ff7ea4f69d5c91ec9f18", + "y": "0x3bb82c091b0e62347965472a0120b31e48753b40d154ab3d3d8c87aca7afef4ecc139c24e0cb738da2fec537e092df0c5ea2b58c4596f01276490845dcf21ec32a01abc953c44d0e0e281044e548581680a2a15aa50f7d01877746a814220a" + }, + "scalar": "0x1a815db7201a19e2e11c6d8396c27108e3e545df171b408de52318a7d5949126c686516ec527e7e1f2ce632e3d9da0e", + "Q": { + "x": "0xe3f5dddaf4a5bf49f3fbb3f39e8241873e17c1b7b962ee7508bb286dfe0380a6a011afce6f9db376ff77e7c6ce9d0c6a587a81382b51140d91c978de40352dbb4d15fa2cad801e20ac5805b773a7253fe736f8f7d25e75e58bf74ec30319c5", + "y": "0xfaa05e7669d9a5536b22b393acd01e6ae96cf8d9aa7597bfe9b95f0255e50a27b3c78264fd6d832a66034028d8fa1d69ed59085b9df7efad01fbae70063791f12c2af3d0a70c8c346a4481574234568f11abf4c9e6151faa23f6221813d8e0" + } + }, + { + "id": 21, + "P": { + "x": "0xe6f9604a4798679cd7a7eb9f80b31ba1b5a42d71d8392f81fa1a9723c48872b61c719a53e0812d90940aaf1d7e8bae4fe1674fd94daa1f4e3ebc3c3353fe7722cf270f145d6aae74b37e461ed6355d0891a443d68275b718b1190179c23c4d", + "y": "0x1c9fb235352adbe204773b7a5f6dde732124d2cc2909b5ca81cbbcdc2c5a04ecb53c9847b943a8fda37928ff89c82240f8c133445123a5e87ec4a02c367ad0d4ac4dd31b9c0d71c060ee510bf3e59320703ed8049b807163abc3f98e4a8220" + }, + "scalar": "0x19913626ccdab5199646eb19d31572fa7da86c87ed1daa34ba07768257226882d3d921105e4aa129b4c0d34493fc369", + "Q": { + "x": "0xbb702633a93f020f625cfcb9e5dbcfebc2cb014ab4b0bf32b27bfb653c9a42e61ca63b08e5e8035da0869d34b86333d556078ecfaf6f6afeff9952463e8795b523ae299930f799c3fc97a42dc2b0d4f6d2b28e716b8c8c9b0d39305bea24ed", + "y": "0xfe9c053cd10427a42f98c8495ce06c3fa3b1e71287471c179aadc78d22eee4eee0bfa96a35064351e7ace40e3b46e7c0c0802a22b9a7723baca231ff1d1d1ae75ab0c47156bbaa9e12c7b44454e3546cd64dde8e59ab87c0d8bf812a471334" + } + }, + { + "id": 22, + "P": { + "x": "0x6b42390c0c49c324aa729606a7661ada8a3d7805df981127cd582efad5da2a3698939608648ba3c6327efe70e45ae783a12c1f0f9e7bdf1cd1cbad02045e8c7cdad8bd9b65aa6474c90a5ae827bfd1e27baac25598ffe5d12ca487376b51ac", + "y": "0x7d41340e51c82c0c821af137510f2cc35884e52d20a6bc7ac9dd9de0faacffefd5caa04ea9e00826605013fce3f83b7da20d29d794ec44f1af19cf852c0ee125d18ff03cd43b86ee79988376f33ddfc785fce99cf7c30e0c3e7175c3929964" + }, + "scalar": "0x88d990fbc5bc4fe8a1eb96e0a09c4e8dcb965ca78deb4c55bc4a3845a87e918f79ed022d75c8c556c46e60c16a46ab", + "Q": { + "x": "0x1057d2575967a3d6bd6a06e3a678fc45e5cb7ac96fba491b8be9db4e99d9de3aa4b000befb83d66c2ef81b499745ec9be21a8e78f14c4d46e3b00fd1140eacb7d45b19932d8f91f919cd2d7910c03b8f71164dca83e7752c1b6b20b6866c256", + "y": "0x130c2cf572cff8f21a37693f22209493ee647a31553a102189d7bf166a38021264ab64124a0ed06c172dfc14542f4c7d40643f814fb0711f8ca3162b4fc0efecb02112a3d40ce8b1b21ac825a2ab6c632b7a11ca8117004551c5a67982f60b" + } + }, + { + "id": 23, + "P": { + "x": "0xf594afc8e1844b3c5b2d1cbdd933bf90f093653bb4d2a7b7d5d7f8e2e439052f4baa72822f7602ca074a888e0ad78bcc9aa184d29d8dc7a6fc936034ade7358bceb6e683496a2bf4b2dfeca61ecb78b7cb2f9a602c7aad5a185ce37eb15b26", + "y": "0xfb6e538e5ee5ff6cb09889e6dc85c34100d8c58b10f9e1cb7ceb5510595a2080c14c7aaa709521b1baaef701f13fc32964e43246088230b7f1efdc629d5733e7fc5ba46227a8650fa9ed72ec3a19edf9e3bf52d27dfe24a73e357691bd7679" + }, + "scalar": "0x19b3946436f9cc0df394180bf4d3597741f27971ddf23757cb80835cffcad70604e962cbdd8d391b6bf5af7537ad990", + "Q": { + "x": "0x10e2a7a13acf873672477c29dd3311f468aadfbbd0ace0d2f8378bd9b423287f93071007c3102e546b84eea50193b635cd58e8a53e29112f85860d539a147b4c6ccc52f85928454fa50cc6116bf2323e87914787118249f18f32c0fe2bca78e", + "y": "0x9fb7dd2dddd6d79cfc669d71c2d2ed7c17865fb4084df8525f23b6e542e8cb3765e2f5aa6f2a0c317157073ac8e585a213fb4d617198f75aefe9c868939c8b6a4a43cc96a76cac5b784d431445c680f64c55f284c4d8fc2c507a5b2999b8aa" + } + }, + { + "id": 24, + "P": { + "x": "0xcbff8ab17ab9013f53815f6d485f1eb217d7537a84c57ef03f644187e0ebf61858c3dfc71cef3fba78c653b12cf122a00d23936baead152776269f0ea9b00a12757cd54ae9f1210ef3f915c4b31667ff17c5fd5af7ac9849bc9ffaeffb6654", + "y": "0x7ecfe9fae750c0297918e392e0ada5dbddca49e63b80efb67cbdde413b700c6cd950eb44672d6a8d131aed642051d5fa97484a316186455ce328ef78005d548615631443139d0a3f9547185a5d954bc6917e2cd7c46e845679811d8aa7c567" + }, + "scalar": "0x51f3a4cceb1c28cd0444b7b6500e35fcf6e67af5bf13db2e5b8ecbf925ec553579552c805504415ca62b217d354f05", + "Q": { + "x": "0x83bbacf669930e5758b6db1797f88dc1754c993ccf902e4af1cd1ac7136710eba44c229327ea4790f988d2527ef4e5f8332370b2e38b4d3a80c52de81db34352dd1c5590a5c0b0590ff555bc288d04be8172a90a13f6fdd387ec07bda35e1d", + "y": "0xffa82032ad4e21f69e367eca5e62a4b57c0f786400131d53e32f153ab420cd9224ffb27299f4efb99e1f765e0ef0c2a46465356e1c61d01f4a75a7f0a0e96967753809f4db7773cfc22b9880e9cb776f90ca5f3820361971c895263afdab72" + } + }, + { + "id": 25, + "P": { + "x": "0x41667c709fbeb82ed0fdd10a61930f959acf556859daea3f5a705f649163c25912e0959e7f691b786aa7467aefc464746f5b24867475e20bfc3df49e3b701ff65d6ea20096d0b5e4b7fb12f4c0aaa21e860730617b79e84f3f7b7f4ac06f42", + "y": "0x167c81045e5049bc5f5ae5d3b198df184ae476fe9c37f45445968922abae7fddd0cd4b6ef4d0f0ca8db37b7bea4d71ce992dac1755edc36207390211b477c0cbd112c9c5bb3bf8824b0a1b4600b66c291a090b0dec34a616865bbe461f87e5" + }, + "scalar": "0x341986fabc76e3946dd702c57b0ec9584b1ea2d6c9a9efe102deaea772b8cce89933d8c1f06d8c1438845b76af828b", + "Q": { + "x": "0x308e5fae8b2374f3e5f4013f21a95194338289a11c685febcdf238517a816f6f27af836f5cf4ecb04c1f2652db7a66c041cd954ba1ff847e613a8cf4d7e6be4f6014878dd7a5555605758368742a9880b94d5abb49e516b98105e81d1ea1e4", + "y": "0x7580e9b5777d6d5ae2bb4997dea9aa1f52fe468535fd19767ae049990568f756a5643a0f4d7995a5260479f0a90763025aaefb8b48615f019f74746d626cc5a4573ceeb3a8b3970c9d5b1d35b68f38baaaae521f574176e8a334f576ef176c" + } + }, + { + "id": 26, + "P": { + "x": "0x3e70e04c34db72274d5d770fcfa211ce20aaf7b83c436a8457d83c19550dd148e789cf6e1aa3d07720f9e74c692203b65b67620337eb19fd44e4fa2ce0bf539ae670dc5540955a0a0e42be39f4dc4f57d6db8eafdc868fed2344cf2d34910a", + "y": "0xc7af52b2b56670460496dc261b232806c02d3067a5aa35df11d3d414e39cc268d2c07ac8e1a0abd5bed8e36c7de76c81a2528a0948268172331611a4afb3bf04695a56fab333c8cdbdd8c3fbd43f7464683981d8cbf904af211199282f23ff" + }, + "scalar": "0xfb69db02927653829d59afb5cc83cd35b38e16d80a23a5cce014206a4f4ac625cfff81dced81a03564e93ae2ee36df", + "Q": { + "x": "0x45ad4fa1a0ae18b65e999161c3b4283732affde935d1475bbc4faf93e4b94fecc1b107f12db4d8a1b7464a0f63e092bbd421570e6e674a01249e86deebb4bb2c66fd1ca8c59981a92856f631863154d92f74fa541220bca235c66875a80ec3", + "y": "0x14d9a14bf5b54860a7d734b6c6d21d5fc1cc52838b6a19916e0efdbb68933494bff2eaac23c606387301e314a010cbd311a81a3cca752cc44c56f4ab704c9ca746c8d4e9ee7023a6e016a8dfe3f8d0bc313cb4728c77474ef8fc3d26439936" + } + }, + { + "id": 27, + "P": { + "x": "0x17092c53168999936bd269c1a97d37d1de74b56fca434cec9c3fea2e2d599b2547523a52c537adb459633aba009e58d29a796995da9f6c7788e57cdebd17e307eb334874272d50f25d20fa7e5eba3a782f8390b8b8db2379e58a90419c3d8c", + "y": "0x107b9ccecf4701eda2fb425c5f3887bdfe356a3c1b4c8c9b86a7048890d1aaa0c4b2b4eb1631400ae2f6284e459cb8f080d520eee21ed8cc22e42a0d88f8917c7948e3df7517679627408d7d133a1bdf793757cba0eabe131c3bbbd8a39ab98" + }, + "scalar": "0x6ed467c90dff687fac8c7637d5feebcf8aa1c47bd33dd2eaabbc813811f1e970564b30dcd30e93775c8c711a41fddd", + "Q": { + "x": "0x79a732c8ac52dce3ce4a863c319ab34e789129b067852a070ed725e27187dc34c9e29372166f2d88154e0d96cae999a3be35d5f15240500fb6c8378731419c21e05457e7b3b0bced57086721a16b710223d2642d26a8bb208b315176994b0e", + "y": "0xccd356d3fc91296d4430f8a3ab872aaeb6770513d42cb9646f6dd42b9fead51b36037c6b1fb725bcc8e45758a2a7d30c7124d9a50bbc1fc04b704dff9ff8fe048f800ecfe4a28a97d49dbb51e2d25f7e556d3b2294194b07d83a1d9187f6e8" + } + }, + { + "id": 28, + "P": { + "x": "0x975ef56fe1fcd06122f5a4d793231dd7dd45d3618ccb96448d46329f952d50c3c8ff864e7ffee5b20d047f0244e2d8ab84d0a57ee4b94d3f777cecd16cb71f9c7dfe1a6567fac13fde114a977fca04496a6411dc9a59ce9a596b47ce2f84f5", + "y": "0x5b6038e0f3437d294329311da4a63738c57055ffd8dd115413fbb3af04ce40c8326197c48187f025414e35ff19735994ea66b690c98bcd4025e5fedf068a1fca2a6a578dffd905b0134749c07f2accf804691bad855d6634cfdec165553c2e" + }, + "scalar": "0x1a6584f789827b2b5560bd7f88fa106e62777af37d48ecf774b2cc7040609b19d04fb6eb4b65fc35b7a8f628df68cfd", + "Q": { + "x": "0x571339354899bf520c2e67ab81f69ee6f9bfba8cbb4337ff3b910c6cc1c540e8710bcb93f34879ffed4b5e7104be3d17851acfd7623606cf1855b4d21075b561ac21b9a80c347ef7965350ed4c926688dcfe39d37b32d3a2cfc53f9ae7d065", + "y": "0xa50142817c2f58b48d1c0ae11d93694c43ba0f2b7225d486dbce7f7a596a6ac211aebd231dcbe1e212b80a8ec14316866d2035c82e9deb82a5e3547ab87d65070399c1905021a42a07c1c8c4cd0bedb13581dcf230ebea9b801a232575b1e1" + } + }, + { + "id": 29, + "P": { + "x": "0xa78906f0ffe45e76ff9491356b12039765cc7bfb7c255a5300845cf53520de75bd72a349475ff10186b73f6281c8c65f9f210699eee271a0b83db1288bda058d5dfb7e16f25ee1459dc0011f4eb6d47c5464403e3022cb135cda58ce3e03a1", + "y": "0x5a65c7dd2110e22da5f6c0bfad43b127d8d98b87a1ef3aa0d8ec6c7ce01ff0d2d41e1430a13cd7f89c1af888bae84855b4f5ada873b2f08913980b6e9234543b82cae867ff3ef7bba577fe1b7517e9d6bb794592848ca4624cd26ed3fb1658" + }, + "scalar": "0x906443b3910f87a67ef765d5333e2e307a6776d9c2780d7752b316d4da125afafe37554881b31e2587e358a085b4cd", + "Q": { + "x": "0xfb257fdb7a8ef4e2b49718399164100d1500c6ce98fe287f49941add36ab0b93211ad6d8ffdce9ae75967d624695e62621a59b1dd0f6d26f50c9d6e6ceb2588d854d486a27d5ebf523c67f6ee763c0c03b3524472a0eb3204e1c22fd641173", + "y": "0xd242a113f35558132f8fbbde5353ed30f6cd2118c7c504c39d55978413cf06894fd2f7bf3910d71df2ceafa39fb97542a8210e966d279e433acf96e3aebfba36c81e023cc2208ff9d528ed446c43f7fa0adcf8a00c1f816410f4de3276fa65" + } + }, + { + "id": 30, + "P": { + "x": "0x11970a3ed27ff663fc7773ca56454f037fd702423ad97bab60f06ec6dc2874ffb9816345d65698f55b00b852a0b38209797c89992e238db1ec9344ef50adfe354b153bf9fd61397ce795c3fc83ef3d0b1134e48a9433d1882861732a45d4682", + "y": "0xd147cc98bd0cde43a1337c6e43b42362e66b86c5c793210117b06557cd5a93d2e0d4c4027ad74ef84914f74fb29e6bd546e3504b94baf853af97dd4ab3e5ca4bc87da94b94e423d168de6f3246262629933aa0ae9d5afe9b974c6d8e19cda1" + }, + "scalar": "0xaf6559a961f4be436ddbedfaaeb0965663e91e7c6ce03993870869530e404f314079f4cb9f7f79bf2a6d315c34bb36", + "Q": { + "x": "0xb9e0b889979dc3d1d2c7a9665463d71807930f96364e565e6a420f9609792fff7a1c18a8b9b7823f3aa84f64cbef9038a338bcc134dfa91b8c473e6b43edc6fdfeb229338c32b5e5f992fceb3b7421af0c40036e1a2b1e91b8ca609d4eaaec", + "y": "0xf4f0bb44180a2cf690f3656b2bcb75881c581504b4c1f90b8e3efa812c17d3fa50b8b146fc10257c1915a4492f04c3d31fc2c09dda0ba73dd996badbd5a930fe02405f41d247f3c233e6572cd35fe07b27cf1944d500acb51ce29ccc3f1c1e" + } + }, + { + "id": 31, + "P": { + "x": "0xc02aa02419c7d3f30baeb4cf69b12ff986b77ecb54ed5dcd201d5dd0efc786cc706fafb53d41fdac72f5b0412608256b206a38d44ba3a933e8fa9cc040275e18b396607b2d9ea35c9a5be3aa3ba2a85d989abc4b4619b4e0352968bc8d7395", + "y": "0xaed8d4db008bb6690ecdeb558ae6fc9f4c987ee733490a6ebee21d3f48b62b14556a934334fdca9d1473733d4ee5a881f69c4f2ee514689b6cb534410ee166f44d449c12577fdcc936c43774617abdb51593871c7f71ff1710ed931787e34e" + }, + "scalar": "0x1ac3bfb85a57fe343d841d603e95c5bab1896c1dc55a60702accc79c11d567cfec9b05f07ff4690e7fb007f51d85106", + "Q": { + "x": "0xa3b92a6d6813b8fce0284ef6e0247ac4fbeb33d4248a17eefe9b1e6b51c6bd57a19c1afee2a77b7b5e5e8cbd7e51f2fcf914b80f272d92c7ed5ebfa9dd6e04aa5bfded747e757230ec73c33f1579764b933d575b5335f92b98a9dd20e0aae9", + "y": "0x244a8ea7c6d3ef51d9935c5fd7135d8f48a30eb329edc5f3053ea298be69ba65d153672cd1d3d867b5ed12d3329ff973a1347c07671454fee71a9b347668a48f297c5eaad42408d7b1c4551cef9db9bd9058c94a24e675f9ce78907967c16e" + } + }, + { + "id": 32, + "P": { + "x": "0x9dbd698fd38d194b3221cfb357eeecd7db6b7321440894994e2bb0ce3891a31b2ad1f80e144ee69a02c41443616ea453f8061cd8a7a8944401b6073c6a4b9297d8ca99370c86ce43cbcbc103adf3aba388af611ee644d28fead236e718d80b", + "y": "0xd9eee4ca51af82bb0a696fcda7cbad26bdf1f5c9d534ff26ea886ab3872284c3728edddc24a2f5c1244351f57db10ea10835e353263dc120fe27a99406354b80fde2b05e9d0e69c4c3d08b30673af273c98ab4c3281def393a020dedcc95c5" + }, + "scalar": "0xf7965a0831fd4a659c9cfecb8eea5df564691df0379b925afe128548c90ad43f65af42b4a2a7135eb0b607db96fb71", + "Q": { + "x": "0x9067f23aa20942462889b9f1ace2390516a8fa6106bbc10159f404fcc442caa7d573222b70e5b6b6c8e2f1ac08b769696c3cb487ee41423633b58c46abf997a0e22ffe965156e30376d0dc57a93254c2cf3c9f3c85947549e4cb42754f2e34", + "y": "0x6f4ec8ff282061bbed74b63171631d87633fc9fa460411d67dd118d0d6abc340b8ab33883c4b5f4d41835b5c0a59dc9ae80259be51dc11bd2226e681a1d56f4c89ae63bf5821093c549773a97edc94e71e09853a33e48e1b61f737b77618c5" + } + }, + { + "id": 33, + "P": { + "x": "0x51b2018081f71ac073cc99fa172acef1cd63a7f9bb6a3c05c2095e5a17532371f6a573c65106cc91c527e1d3638aa0ad57629d9aaa07f06a1bc23065d1408bb75c604baf64c45768e34626dbca2c1612193d43691f3bb2e608857e693c6bd9", + "y": "0xfe2cdc1bc8f001fde9e27bae322f408f9f6c3456e7257d7c065cf6efd8a61cdf9d27d2d75c55ca2d007561c5d35cecc6b8a041f60f88f70bee7f8e92fccd65c1468b44a2ceb4ec75e63f53016328325048d48383d7e046e00dac9e13111cbd" + }, + "scalar": "0xca051cfa28ea3d1ab6942d60a2007a466da68b3c21bc24e6ace5de641532f65502263b3781cc115a6b3991ed84027", + "Q": { + "x": "0x7af096b8ee3d2985653e82a50549ff51d5fc197f68333c6eb2355de523398e0d21179c9dc8306b59c5a946e07fc981e955af1027c7ba522eb16f5c40a3b13424c6c30bc2ad0a6b01db1cf7f8b0e44312909f7e06b23fa506cd92f7be91c43d", + "y": "0x2b9a58c593812b7c804824d41b6f8709843f879c2f19bf017fe3f3bd80e7ecef9483ebfbd7aa1bcb3abb154d20e7a56f24a46ea87d8e525004956488290587f68d550aa051f869e431ef03526df1c091fde384d16c2cdb4aa48bdd0bc952b3" + } + }, + { + "id": 34, + "P": { + "x": "0xcdcc60726e3413c8a4c17cf7a29df3095c5630c24b53b30409ef9aa417c663a4d192666a6d3155038285c7a94f7a4794ada511a2acc4da3b6cc67f095185103ec1f7c537c411b7fe8bff2d2ed9c81b72c8d83894f2a3fb102a1006afa25666", + "y": "0x11a70417f4bf0684ea623f531163dfe69ce20d7ea5c22a031339eec62b0ae82ecdf034291f980b9ac8b950015988c777a5870989f23a2f8dba466312cbd1fdafbef5df24ec9ee74ae32301f417ca8c41ef20f0eac8c75089fb7ac011a744b0e" + }, + "scalar": "0xbbe30f2733979d9e0460ef722b4e388973ccea3f34cfca5ccdf0f666804e5181ee65bcdfd854cf57e91c8f79d029c5", + "Q": { + "x": "0x56f852808f242b646b4471df8e46242dea98e8f27351a0ceb491bb6db91423e79e90910ebd428eb7ffd967a9d50ae2d858ff872f3e9a880840c4d6b8c7fa3012917f4e746c7baa2ecf8342e445c899a7fc4c6cc37549556140f82161302a40", + "y": "0x10f5e0fb0240837e570913ddc845dfefe4c867b943829dd83841845d7cce30e036b7cee7d2c99042c764976f14fe9432758fc04e1cab78ba217c980d789b9e8f9d65fcafec3b064e111d28abd439071345ec9f8f8938848d61abac84b8ca7b4" + } + }, + { + "id": 35, + "P": { + "x": "0x945958e41e42d485a13f5f4c0d0b4c66c3228f1f65ea9aab509522ccc2338c93800961d52c60900ace778219efe1b7c2c2929866dc31b36c7cf8506c850ae15ca5e1fe1002d7286d1e7fd61f0a2dfe06937173e02de5ef66e23e9e05a2a1b7", + "y": "0xb6dcc5e85b9bf006979f652193954209661d06d93db56da783f4e8679532233842bbf63226fb3f5b790c4edeaf4854a6fa306e124dd782d8c9e2bee0dcbfaeb98b75c72c0d7d1a7dc6dee1f62b2929cffb7ad082d33447f9325b9ebbc70f2e" + }, + "scalar": "0x641a351325cdb90e024588ead0db65faed19fa218f49a16c45aa786a59210429d3a3ce6bc354576af81185f3d4ac01", + "Q": { + "x": "0xf91010a4e4f3bb7d53774751b96423d3ba8ca10d0e07b8a89916c6e344f2d8fd73346ea246f98799017c9edac2f7f5ef13c3396094a6aa8b1ba55a3b4cd91823ee7fa4d4fa8fc5d8ac120d50990c1ba27067bc41e6b9e5a38dde4d99160f5b", + "y": "0x4a732bf9a93c99963a752442c2b86b73f60bd61f70de2b1df150f1a52608f353ee7af1effc17b8a4a72336b31f669c19c4ecc7074fb7a37a7a90019b7b15b0dc8587cd15af354688e44ab6e0aeaa6d2c533ed6f3d6ed123ba8065b6bc041f7" + } + }, + { + "id": 36, + "P": { + "x": "0xb1f8d7f441bebb7707b652cc23459e9f2adc9cb24a9818efe923988898e3b6d83c0292502ce7a5ff48dc6b658f42bbb865c38b84530ec757063a1e4fdf822742b3f5c2deedc0d13cb129616b42e981714a4b59ce647c2476639a10500d4d24", + "y": "0xbac10c6aada96073ab68875771192dfdf74b3260e4e431f318e4098d597760b134f51752157ca8f4fd4535747ea450bde08ca8e9f6486a74273ee870f9de03913dfd907f84ea652bd94980e2082fc6d23ae928fb4fdedddb21a2048a7c42c9" + }, + "scalar": "0x14e5e12c7591f27289c71d2a174ad3eddb5970fd58e21a5f07874dd75fbfff4f7133476346cdd1bd6b14fbe3cb2e86", + "Q": { + "x": "0x620542fec79ddae8f63c20a27bd8725d95b61f2b56391bd1ebd643ea75e126382775598698c4147d3072a4275755bab09d4c37ae9148fe94c2c3158bc8976929706a1216bc453af5c4ad76721fb6afd9d2bd3cc1cd1d2df9487d2f2d22e0fc", + "y": "0xcda2c0872080764fc85d15d746120808ccf7d767a62f4a31fcbfcbb8a1f8c53d12d06aa6d85c62352c36ab20bcfce449e991e1c74f35a44d2013182a5208723fabe3f034fdcc762678d65e37a5c1c8b5c1ea0035fe7ad2c96271e484b0dacc" + } + }, + { + "id": 37, + "P": { + "x": "0x11a022a70fe8ceaaf62caa6ae6143f22ce71347b5b17508b2371f0ecc356cc54437f46156cf66a663ec78c6ab6c186a3537391bea668e7937c503e94e2d7897581b67e48816e5964ae465e478872e3381d306485f920d0b4910013a4978e088", + "y": "0x5f96897a6d2fddb66507b73c0849c4bab6a9d5d72662754f4390cb4a327e650b38e354cd67b50d82467cf6451dbdd67303e79c247059d6361594ab2e6443864bcce00a495a6641a0a90eddb83d5472658e03ee8d6b12f0d6180177badfb009" + }, + "scalar": "0x13f74c09216b0ee9b528bbc8cee1f5fbc9ac93668e0a1c3dfc56766660224cc1a9e70cd43460c1d03868b1b0cfeed80", + "Q": { + "x": "0xb1e156c00043feac278f52e7ad53cc57b7114ceb8f32591ef684e080fe34feadd5bfe8d6d195d79d7c8eac6b492ff0df47ba244a07446b0df53c8a6fdd735a8c1851cb749b637fa29b6689feb8eedaab71cae980a9a460de898fb4a4cf936f", + "y": "0x25f8d8fc66e7c6fd7cbb80a7f54ddd802e8fd3c81912f34ab2ca904d6f4fb5e81d4297a4e063efb59ec9d810192e7149a79cc8268e705aca9033a166e3849aee8add74ea5c8dd5247bc1cf035b7f5f10e3de0d4781bdf240525090f7e82e61" + } + }, + { + "id": 38, + "P": { + "x": "0xd82a8f756e8df249891faf0f4d6b9502cfa30404e4a578bc72612591e5b3d71f9026060b9c9da0efaedf95213a9b7e705a6b0911c0e8c524ee20d43c914e1739aa0fb77d1102eff55fd46910ebd800bda95fe4f2a5ab821b406c23adcc52a0", + "y": "0xa3dc5383a86ba82461221a838a620afe6c4abcdaec704b0059a860a9c82e905274902183d263e346e872005d7c28f29b5b33bd82327fb72f76110cc4b629136959ac3b281754c504115e07981d48d62ce64ba41878af2533c9853c3fa92729" + }, + "scalar": "0xb70e53dec30fa362ffbd21cfaf1255f1ac3b6dd1dd017e4d797716167e2f0ed7293389c7b584c36c968641f6e5b7e2", + "Q": { + "x": "0x4009a71eebfb58e4b462d409e6e7469a30d00555a24fba30bdbea409b2bcc7ae49e47a17b75b6862770aee09c218ecf45f72dbd317cf43568fb5015bc837a7b39fb5a2d9dd39228e9ddefc58928a980cd831fef110cd41fea9dd30f4e43fc3", + "y": "0x9061be0e5de1a48cb5c394c1b64eee57689f782b65892a5c5d69b02f1e0bf82a30db0a0bc3b323043251b30c286b94c328ea0326babade4ad87f79489ded1dd01094fcf58b408393101321c9042cc5d21cb7d38b52bbd912baac8fc036d857" + } + }, + { + "id": 39, + "P": { + "x": "0xe5c6a1bf81815f93b1ed316067959e48c319d849555a806e2463d04635570938aefa7c6e20df4625d84d73f6c77ba8132cb7f69ff983b4de4d79be02506a545dd873cc2398e6f33c0e70430dbff3a82147ecf8f36bd5f74a5f367a5612ac9d", + "y": "0xf0dc8c03c1bf8dd294e7182c73f2f73a83ecea22fac90e28aecd3a3d3c2a91f4c254777ba6bd83c30ef21d44f634b9daf520ede24d4ccb1fcdd1965404929607b90c45e08dded0fc1692bac1c34368ac7260584a6f011e2bba63fcf2e5e583" + }, + "scalar": "0x1a9a1969951675393e2a5bdf0ebe1e7ff35d6b67a636417481ef06a5c872eb1b0f911062b250d49c80ecdcebe467da1", + "Q": { + "x": "0x6672746bf5e23f004cd05466c36306f701bcab585b08a4c987d9a8855836fd2e0e4b351a5068d7cded0c898cc40a2dba62770cd5d597d03487013c0713a02d1ab92e63bfb4f48b311cad3047ccc4499c9b8a3179307cf1c9ced039c3a98d24", + "y": "0xb1640e2659ee7dc112fd65e06e869aced75ccca15de32a6d696cd479b323d574d9b2fce5bf829129bb4cfb0b856094848d8f9b1a21aef3c58dbacecec1fa65f5bd667cb0c04ed4050b9d05d48ac5f762432f411228299c6b46f1c35b371fad" + } + } + ] +} \ No newline at end of file diff --git a/tests/vectors/tv_BW6_761_scalar_mul_G2.json b/tests/vectors/tv_BW6_761_scalar_mul_G2.json new file mode 100644 index 0000000..d85de41 --- /dev/null +++ b/tests/vectors/tv_BW6_761_scalar_mul_G2.json @@ -0,0 +1,497 @@ +{ + "curve": "BW6_761", + "group": "G2", + "modulus": "0x122e824fb83ce0ad187c94004faff3eb926186a81d14688528275ef8087be41707ba638e584e91903cebaff25b423048689c8ed12f9fd9071dcd3dc73ebff2e98a116c25667a8f8160cf8aeeaf0a437e6913e6870000082f49d00000000008b", + "order": "0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001", + "cofactor": "0xad1972339049ce762c77d5ac34cb12efc856a0853c9db94cc61c554757551c0c832ba4061000003b3de5800000000075", + "form": "short_weierstrass", + "twist_degree": 6, + "twist": "M_Twist", + "non_residue_fp": -4, + "G2_field": "Fp", + "non_residue_twist": -4, + "a": "0x0", + "b": "0x-1", + "vectors": [ + { + "id": 0, + "P": { + "x": "0x390f5ca70bc0a36f30b0f8db9b844d682358490a23fd65f052a11566f082f31b6813462b7d65e82cff45490e77741a547222bfaabb41a490dd641aae6c5da17604e550301a1b45a1d25e375139168a7a491eb354dfa149ca82229857aa45e6", + "y": "0xeb29b1fbd522f4d96f61e60dab2800ad7218934414ed8efcfb6371e2b00e9e11c683fbc9a808c694eaf19e3342145d1a2a09eb182996040260fe5527dd3aa7619d444f1217d90b78f367f29f2850b60e6422ccfda316c98d68f024d0991783" + }, + "scalar": "0x100a331b6c086bd660eb2d2bca8f276e283a891b5c0615064d7886af625cf2e7f0b7ade0149796fb2286a707ecc699", + "Q": { + "x": "0x4620c3fdf54b9d33f6d625c651fd11642b53802491d1874b2956ebcfde0c46ac261ffb17ebdb0d9538c709b11e0d05deb6a9de2150c8b2392a0ac631c0ebfe3542d93ca5b71d2f2e4218a5dc3c8277fea45ee618970a6232b434d07fbb4847", + "y": "0x950992f02cab1edb96f68badf113a61ceff9b1e1ac7c97eb258caf2bf1911171c0d4284c5c48377ad6cf57682b2110a48859f3cdc05c9b98c0c83abed443c4f980c7112aec1584765d3252f15743a37966bb04d1716abb09fbe2332794e194" + } + }, + { + "id": 1, + "P": { + "x": "0xf1e120a34cec6dc230a399ca31d4e5371c9cd0f06caa830637f6a5d0447f488c9a61ce21c923409cb46acb699e1182e8c7ea7d5ae15acb9337a5856d37fed314c240dce05c22c031b197215e8d5c282d0421b828668e58028d0e9b1a3931", + "y": "0x11ead6a04bdc6726cb379cf0ba3d36696bb3c030f39e87c25b4e28fb255e515a8c19d0b7852d1b132fafe8320f2291ddd8604bd82b7fd1a9ff21637b681e4539978ac2a0e6de77da7ccec9f8caa0b38269987da963130cb1fdf8024302ed812" + }, + "scalar": "0x1810decd62e1f9904c3c1497243455c578a963e81b389f04e95ceafc4f47dc777579cdc82eca79bc50d2323ceb694b6", + "Q": { + "x": "0x8ce5b923cef4d4f1ec0e5808f4c7b2e02b3614a7fe79839038dabbddf0d26d13a84f6cff2da892d84afe657658470e90675b6fe32a6e380a4f66478d1d13d277cd74481a91511f352f2ba8522db59b913b649301ac1b07dbaf28947d0314b9", + "y": "0xd4b161f420f5c80319f37ffa4a151950c0f394d19ce345748912591937d08eef8d045dbd3279f77fa9e73020b6c5fd6f9f7efc6bbfe64202ee15c66675757ccf0ee3979fd17d075ac1ff9b094769bcbe7bc825ff148c03b56baaa19fbc8fed" + } + }, + { + "id": 2, + "P": { + "x": "0x2561b56dd064993454c0d658d2c3afba18e07c520f733f32c2f5c3f8b2cbc0fc6dc4919465c62378194d1749d8e512fc006a6bc0903c6a2de2b0009e0d2e6b24b266a1bf5ce4291740bb2a1b1229f960dc6c7928d745bbab0f3e46dee73d46", + "y": "0x79573c425c2e1f91eaa818229828489542eeaba8a132f8808fbf7bcdd0bf65fd4a2c6ef98352d64318edc2b85d457b96eb112ca420998b8552cdab7deccfeb4d5cdbacc409c651dfbf8a9ada3a9000ec9e9337515d88b9ac3602c5839bdcad" + }, + "scalar": "0x2254aebe904792d43dfec443d86beb27bd5f377ac462bb25c04b7824026208d2f9dcd4bada63c40825e57c5c5c90d", + "Q": { + "x": "0x5961709e6f3779a26801095f3161c554b6382b6518c9edf7f2c6a8df1848fae014e6b6bc98338195b8b15f1c6849165b7c978c1d0e48c2d76b1d36751d986410fff36e4d68440450993c97eae762e1be0224f59f8ea828b88b4f47bc1ceedf", + "y": "0x57befd39e6c91ff9bacd0c1c57bafcb3f7e8c4c177ec7fff0476d0b2d711dfe995a547cf72c6ebfb9a4f713e31eeccca507d81dafa12ea0a238d2333e2d6465f9d11afbfe4a8363456c989f66f01a97192728e3079ab078fae715d3b15df72" + } + }, + { + "id": 3, + "P": { + "x": "0xfc714d4638a339575d8597da9c04a896e3a8a1891267dd9e4817acba920c6b966339ddd566264a1640f4e5eaac078b2fb587bdf6bc3250764ba0d08088681934bf2266d8b59f60f9629066d7dba5ab9fc185b24a48762177bbfdfe2feacdbb", + "y": "0x4b48f2cc28d8778113ed87a4089776ffdedd735f1d1ae9a0fe870b1ed5bf8ac449d944b8b6781fe43dc7a8d960e1807506f98cd64771f7b4cda9003d744f88d54fca26fb80c592f17c9a04d08de4d32b028a1f63c491e0483e39990997ec06" + }, + "scalar": "0x557cf069b1239bd35a22c905315b8a074e1fe776f14c5543cb1cbab5973cc0605f5bb1b045deac6f5820cf045842ed", + "Q": { + "x": "0x10d9b485e39d7e54b9ed629218f02f6d5a650787e122ee8a388dabcd462940c84cd2fadd8321088fb027cb4d0b745bb4318bdc20cc21d6665d91af467c71298320df2a33ccd21c45fed4dbf6cb5e55bd0ab52566bb387352a24d0ab28b50463", + "y": "0xd0e0d9d779caee77b6cc2292127fce6824c089457c4c88554c0ecef0f663b4554006031d767debd20065dfac25a2ee4e5935290e96aa615ebf07f5621a007045c53136f647c7773dccfa24ff4492cef27d5fa1916390a30006946500c9c0d6" + } + }, + { + "id": 4, + "P": { + "x": "0xfc3f9c827d83a18f06a2445137b8ad01ae61f9f1797a3d038f9cfb710900c0487f6ee2fa9c9c3345eb0a79bc29513b539955312c62dab7c7ec6b904adfcebc63e06cd4f545c14a1f0a08848e7f06d0b6ff27f05a80ae2a39e40197dc72966a", + "y": "0x71709bb7418a25576973f9d778b621a38d25e63b1103104eab605d9e132925d5de3b301b49f2ecb25bd0e732a11691de59ab036d2232746dff9008b3c9645152cd81534d4b2c7e861afc0b53e98735d5ef470558b47c5310f92fcdaf12c202" + }, + "scalar": "0x1656931ba49c3036bf5e127d7a7a609b093f5fca57a6d8f2dd64b0bc11bb33d8f60ca1af2b149e991f1e8035fc86ae1", + "Q": { + "x": "0xf486e4593cdde160b9a6beff8d9167eda70d228079197037266dea37c93d3a88023eb67bf1a234620a626ffbf2fefcd6d42abac14eff80da3607d1e38426e58eafd164a0b30b5b1fc0f0cbccbd0aaf818e33a395254704dd6a755473bc63c0", + "y": "0x632d3cc5205f5af41b4840d96bc41ac3ebe3381d36b53f43f4e9543e57e4693a59e55731ef91bebfe4cda4b8840a498f68309229d994e39b89795bba81c27ff9888e12c40fe3afdeca672182d1555714925c48d27c5f1056faa9258fe987dc" + } + }, + { + "id": 5, + "P": { + "x": "0x79970240516bc00793f147acb795ef46207e15f4c296c205c0a69854b83744e03de512d8089a90719a39f3ed33d1ad7059ce9961e0e21fbe8989e018e104b48bbd3438af07af6f3c27e13cd374f26b46f8d462637316224405a3e5e7e2eeee", + "y": "0x301535bc0dd7719bfe93adb3bae92fb886d1db3e981e46aeee520996855e1c6be293439dea472985af3d9eb666688b137f027e479e93649c49aff96ceead1c1887a5fe91b172c4995a3f1c5b4e3ee0f0cab273d7517c9557dbb28bc3618151" + }, + "scalar": "0x59afb2d4389bf7a8c0cea573380eac05f2ec5609c22a9cf5b40e34635a4cdc57c217ff73b58602eb7bc4ffe71446ac", + "Q": { + "x": "0x9307a46c9a69976de4757814badae0982d07ea52fa04d63ab0bf4e9416998a7fb5e517df7dcd4ddf351fab18681d0671e01d85d88ebf9a8207bac5921d8f32be532d13d3978fd52fa8ab3cb3d86eb302574a62be0c565ea60e8a4b5d8b7f8", + "y": "0xb64dba50b10c800843f4e8ab117b5c1b63bce9773bb3993f43f09feae96dedafe007c83c8140851f3f073f56c8693e9f5f2e0e662a3578e466e77baf0e5a4146ee46f7a7d35acb76799a992b8475d1e219bc226dc49dbf094c31cfeefbd18c" + } + }, + { + "id": 6, + "P": { + "x": "0x2daebe748cf4e0e9253bf350a952fcf71b7186beb26dba322ef57b6c12026eb51ec882ca70f04fad99c3b854487cb0f85d03d59289a28d7f7d06c6634b80a0646196b1781dc151956fc02f26b60370682583af0521d7e1ec7035c0d7c65fe1", + "y": "0x11448b98be2c67e0f51c456ce24f91e374df08842ea6ac6d66374eb67a8d8d64f2598f79986c8bd346fcfe9344703120c2fa4a6f837803e3ad0efa6743197ce3f8f1211d7ed64d4399e7e81d4fb9438124994bfa3d3d3c7aa81dc67875cb24" + }, + "scalar": "0x12a45d924853f6cd3b7882d08153c88a7cd979e911b7ff5e8ba474a72ce4394ec3706dd1b0eb4012f99db511cb3d002", + "Q": { + "x": "0x8f6d6737c4a04848ce286bb87a1a2735416084896f330f3d69593a38e1a53462a5d294b01b6324a74c3a385c32219ef9f11f1193418e95f3ec477842446b10c11f219b7a6cada1785ac1e607c7f5b862956391a29f60dfd7f2bb85917c8e1d", + "y": "0x3281007e9d77cf73b5e8981886306531a99e0ee51ccdb5cef4b15d46d8c5b5f272ec429653b9633b42993e938835f58dd86dff471f0227bd434c2a11c6f44bfe34ff213c8f4b111502b90231a478704a82c12a156811d8853e158dc15d70da" + } + }, + { + "id": 7, + "P": { + "x": "0x31d108961c9944426a53671ab4fe71dd18e05fcd2105317365a5264d9f4e7e340b79cbc004740873a081c354ec058981e2843f67dd858c43db973be276c4acbbeba257cae2af16f83130ca4813bdd01b3e21f5e9a12ec15bcf77b2ebf6956b", + "y": "0x8949b06441977876e3f7b0bdfea0aeb8efa6a8c363a222bf3787602b1ca8534fac20182cd9c89359ef460a0e0f5e7c29b7d07001ccc50958bb33d8c7b8f726dd8ced91976ab7417a408789216570435fb8b5f71629fe406a5e5046060705f0" + }, + "scalar": "0xb185643d2b1b856373ac0d7077306885d4689575b48dcb9d3d53fb90454558f76233c46bd3381e6217ede0462d45a", + "Q": { + "x": "0xdeea8733c42fee969797fa4d0d5fd638ceae4e31379dc200149d506e467c3d18039c5c6529abadb85b235c24bca35518da74544f0ff8b225e158f69a93bb74b3fdd478716118c2bac133f0148a2a147bfd89cfa0d677a87213b4fd7b82126f", + "y": "0x3b0b82ddad23a1ce50c833b3f8a8a2088040ee0c146027b4e733e0df1daeafb1a1fc435b11a368b0cc27bfc8600cc56567875977e449a1155276076db3718247dbe85c4c3bbe534dcfe477cd9824c0935af70eca7f298d2084185fa77639f0" + } + }, + { + "id": 8, + "P": { + "x": "0xeb982190130ad87bd1ecd572728b6946d246123dbf00421ce35afd922771478da319827b4ebd0895da6b46e27ae41eb82027b7cefc8aa7d8449194a5e0ab1367177781120ea71c06ba38e758fb84555a8ecdb43a247db3ad33786062d70ebc", + "y": "0xecf73535b511e47cc2d79c32013e70be6434341e2a5e2d6a5cdb325d82e7cba82e12f003557876d2f2ec3ee0940999dc85be1368951a7be2154ed3df7c7bd614fc4700c78429cc5ed9cfb33388b82254f3bc6cb2fe3fa523964729607955af" + }, + "scalar": "0x975eee0db6a5dca707a0bd313b1f0b1b20d5b776f9ec6a285b66cacafd66c6cc21b8fc69f89f57b2202d83248c16cc", + "Q": { + "x": "0xaaab758d17e370110dbb04c93f09a83656d00f03e7fbb814bab68183955396fbaa1be04bd60f58eeaad94859424910ebad63ece6ed467a0c3b41db4a5a7b4fa87286ddec03d5a0b387cc5265fbf3d0c745115a1c2339a7ed509b65f83de5e4", + "y": "0xb98f4fc9fe3cd10d37ba473593ccb3b470e7367a73180b59a22e0fabfa48b94c7d2fb9d67caed9b74025d6dec76714c747b3894875dc310dbf44d5934e6fb3d1ed13f55237c1502e08968b5ad221d31ff449ab8c9eea59debe5e9bf3164b92" + } + }, + { + "id": 9, + "P": { + "x": "0x2afee4ee63c14152642f4eb0a8ee9fa085390175e868538094d31cb8c384b083b88d5636272bbb750e661b9eeaa04dc0baa1252308ce08c66ca12d37487a41d1929d679a62b139fded0b7a758be1aa70ed96a872302b372eb021976a75dfe3", + "y": "0x10ef5621cec841b4dc795e76219a6f24fa1d08227b8a2c608f2c48ae3b44fb14942e26aba54b6a79df78bbdb31699409c2cf7b0bf6ed45c442a703808f37675778309f935f2357b8fbb6bc0599f4b585b1cd2f58469b1dc9a0817e31b713f97" + }, + "scalar": "0x11cf9d9827d2f48b081e9fc69ad98cc665a657a00a8006d7699836444c0f7fe43a9c147c692af5040ab1092e6846b26", + "Q": { + "x": "0x6e2d0d2f89d2a34065b5b79d67bd0d8dcef4e56481d6ce3b2d5465667224bc6fab600441ac5e3fb108ff5edd3ed5263f6d63647f9ff6e19acd31afb7464d9eb1f852e48e9a45e3ba2932a295d51d4efd85b1143ecd26369371fa17a2cfd83d", + "y": "0xa2e6336b40d6ca6e6a6cabe67632f1bed6ad88cf4ca4121606c7604a54dc5b0dd4c919a4934aa372caf485e3f58bbe4a9c53d6188bee161758726a212e6e5a572394d2cb563e9e25c37c08db4ecbdb83315383c1c2bf49b54f7ce348d08d7e" + } + }, + { + "id": 10, + "P": { + "x": "0xb6028faa2e1f5be2659512ccd6fcc0e716cce7bdc50b7dee9b4ce06ba3b010af976de58a51179200b3f856e09aba51a8681f918fde43a478fd268c7644bb5a475ab7e79c4fd7a92a8ca48357735304861c4aef88c74703a93c3f46ff40f21f", + "y": "0xd487695a509decacf9b345520ec560d225fe74c1a3a8013b9bfd4e15f9e485bf8f738566655d0c8f80af2aee654a60184da3c41ebd3157a2f0c6c2c47ead60a87d0a6cf1ee77d26dbe9155d24e3462b7ea41bbb97c8d23b22e76c64594519f" + }, + "scalar": "0x15ebbb124d78bccbba5e9c01544f17ea95e67721dcdde9b48b6cb5c75f148c056c35aba2a0f7d64e2f0b4870a4ca924", + "Q": { + "x": "0xda1df45a4354e55f7560b3e28ddfeb06300b2d272f000742aff2292806257bcb9ee45ed7914dc1d25da202f34a4e6ba8380412f8c85d804720827d4b0ab40d3e27108bd86e232b29970c4b01041674cdb10ec6e8f75e67f1d7c6a54c400ca1", + "y": "0x7856feda73165739ace26423d4cd0a4d7f1a524e7525f4b25344d81c06c0b753f4562d7589ee50a63b42d3e486a97b8786167077e2473d5c5e802ef960ec3cdcbf5763da4251128b8d6102aeced03ce6a5348e5e08b77e916b15207c6019f3" + } + }, + { + "id": 11, + "P": { + "x": "0x112cfafd6c4ac185ccd683498956af6c2ee20329a0e2dbf3b94c12f5bc749dc8feb8d8b44f2d3552e4814e575df9c87cac3cc375d68a47a94e0e044fc20334d9ef5e5db4a58d17c606f7aced7717c4e46bae609d03e1578ec7308963eafcb7e", + "y": "0x7522cb62c176b06e4a2ca359106e2e26363a0cc275cb8eacda79987d7673bf859e546a9150d1faf355262602ddc81c2c4ce7365a2495c40f3d5a58f871e618ceb82c64436d40eceaa3114588db46fe0ecb42b4c9357efa06a7fe5309d51ed2" + }, + "scalar": "0x33c0f4ab242f0e6d1cb2e44894eac39d847396d3cb5d8c2c90bb1a180b7a4cdac2c15c549746025b5a17e0d028efdd", + "Q": { + "x": "0x81e375c02b429105ea7813d17cf06bec0c809d19e8efad10253c2c4839065072e356c2c50e153c8363f2aec56bfc89107e37af96095150e66f69eaf7f3a66e3f89b4fa419de3eab06d7ec67fc4b488d81273570b4e89dd33a36426e8a613ad", + "y": "0xc8481062c92b2f2da00f56176480fa7fb5408dc61f6e271d7704d7b00412d8a7bfa3603bf5a291932e30a3eb2495c055407a5edb289a07b077df46e0e6c1645bf3d87828de72c1c6173c00523c8db131e97b8750070b5aa560f2121c12b34b" + } + }, + { + "id": 12, + "P": { + "x": "0x4485268717a7a311819777b7f5cc096fd7a04250b68fd4cfcd1fb55148e80dc2cdcd2ecb9a735f491672a4f265b4db01efae22adb5be3c3056c54566d162e57a17376873674907d3925d61f59709c12d34acb1af0ce756480bea44cc4a0ef9", + "y": "0x9dfe31f14a8a32c10d34af428718bf680dc6e6ea9a2799e9a1e3e7992394f9096c878e1872870d9adb173576e8fbc8281d773b3e8b2610de771596ec99d4a38a8b6562782922b27b05c42c95e0ca7ed345a55030b0d90fbaa41a7a6d65c1e4" + }, + "scalar": "0x118647caeb4d810ce0ad8072d23e8a24ccf26d91d15207a38c8481dda0e8e4b26ae60ee93558056535732379831d5a", + "Q": { + "x": "0x318f0634c137e3c0328d8ee2fc679767f12a75f6d3e51a4e8fe9cc5759e4d8572b137f891391441e22180525b81e74f31da8f6a8f98bdd2a9542142963bb5e1174fd3b9a05f171c9da3ad249c30939502050053092992eea76b2c7df63ac93", + "y": "0xcaf181433fd1bf4c321d2ba714d81995d1bd24e5356df87165f4426aa773c0d076ea9beeec17569cc74b09feaafedca79795b7c23ffc944c4031d177125976c4bb18b203cfa3d2afb4ec41631267bf7458284d74c29912d150481635eb2217" + } + }, + { + "id": 13, + "P": { + "x": "0x7742d1c3e01d9f4b9e35bfd27ba2316afe46356b00bb40de023b751e5c917b0914ba48e0e413db0a0f577bf23dba80dd3a813cbe4d046c5fb9954f90c1e58481e3f758126efebc15115946009783bea24452ac7c9085123360c96deea41cf", + "y": "0x6ec827631c0d173efef84873368cefdd681c2acf383667a81c56ad8f33b18fc571eaac594220fc721fcb51750cdd32aed54ca6d168ec018f32dd0bc825570366b5788fe80f84d294f331c95c30b93e4634a1a1e64ba244b794edf4ac78ad1e" + }, + "scalar": "0x9461c64ffcb02128f9b7d41593d72369430f19ad5e5ccb642fb4a6f06c883cb15c22076ac55e54e72844fd1db1cc3c", + "Q": { + "x": "0x62fc12205205938033c3693b4b17e3ada8902a97c149a31ee4f5d47703c74f010b0eb69cfde693f0686df3bf4c8835d4c707b71f5a11896040006776c4091bf6a5d2cf3d7ab19ecb7e79b8a38b7a25dbf4afca644e543ebd431dd7c03242cc", + "y": "0xf00aeb3e03fdc7f9785dcc2eaf8bbf9a48fe9865e564976be454a0defe59363fc646a24248e11f3355a0043ea460621450577e677786041c8b950b59dabdf43b14aef137e7416e91bc7b9a2faf6399d64b78ff37dc681593e41e6900aa5eb8" + } + }, + { + "id": 14, + "P": { + "x": "0x87f699f7bbc52e536c1b16d1ab1c0395ffb81a0aa42e3cdd08a068f0b3bb3d65ee6f0a6ed4fcfb2db10acf37911158979707ff183a34e0f3c6955c45055964baa353ed7e24be775740dcc3d31fbd24737156fc19acb858e2cc1836f637b925", + "y": "0xff54cc166ad89bbf53c1156fda8f7c6762b01cdd5e11d1c12133865efe04dfdfe16ba7f8392be13d57fc642109389326fade1575ddcb3175cf41f82e71728299b953fda9c6a008a5bf3e8fdcbe6568ee9e016eb0d6dfdf48a3b9cde327cf22" + }, + "scalar": "0x10f54f0229c23b67b5784be267a56f33e69c8f62408f318e5e22e57ba2bb77771551001bc9d694f4ae3866129a6063e", + "Q": { + "x": "0x2620f3c2bada54c85cd33f165ec2a8f638f43468b24af7a21ce504d02565add32734c93a6910170e03ccc792d5598029c726a79d54c539c64742268e3c560fb3680fc75c044e1f9152755ac343caa7506430631b521ed663b5e68824f8ede1", + "y": "0x7a26d176e9dee4e2abd01734f18e2cafe1c106d88bf005d15b8ce492cfbfd85349a07a4e244f8e6fdbf151c59424dc2f7b55336ff8339781e5553b052dab65180d7ecdfb31a19c9db2b29e2496b50aa48219a569162d7427222e76f6cfd233" + } + }, + { + "id": 15, + "P": { + "x": "0x1a621b075f8348381eb6a259ed5b3eb1e19dedeeb5f497aa24c20f9df33af1177eb3501c2db984737355709c9da6c76732eb8e5ef8777b6fbd429d935dd70b23d5413f9922d7b5f121f6a1fd6c39702133d601b9d0754d8a6c74df14922fcd", + "y": "0x99e1ac01fa36be6340e2a133238c25dd7aed328d5e98cf98c29f19756262e2e031570679dcfffffcb0ae21eacade092bc67ef2a5a59e5dfd36872c593dc0328c0d3b0062e29e66f8486031b17ce88e62afe00e732ac0de3fc2032dac659f15" + }, + "scalar": "0x18bfa7e290a9a4c302b7593953faea9aa53c6cf92302618423777d35e2297b5d155ee2e2838653ab8724efcd460b962", + "Q": { + "x": "0xf3a77b9b231769b599a69f56ac7644b81ceddbdffe93fffbd8bbd6edd2a4a10f371e4eafeadebcfd1bae1b142f11861ff799b514b43ea6522bd6f35c1083a72d9464a8014e125bbf8601c0ead399c63098778efa5a851c00661425fb422a6f", + "y": "0xa391ff2c856f8d2a231660e52eca3b1b4fa046fdf894f07340903470f2adeac991eee8cf14bedd759ce4f40c6cf7b991220f3711329c6bc9f2f402f9d7226efb6ce1afacd157744d1bf1a300962aa9ebbc42543d4ddb6aee365fdd132490ba" + } + }, + { + "id": 16, + "P": { + "x": "0x1b34033bc2f102216b5f253fe8a80f89901f1ac4e157a4cfbe723a8b06832b3ed425cf6f8a7a78e69a253bfd9286242a08c609251ad4c150bcb8d553cb79f0c37c8e3b2560873032af381cee9f050aa8dc62eefcb31c11c7193ea236e8fdf", + "y": "0x11a9b1df116ffee7f90274ee60e5303c8f40ec640f79c7442b8d54951ea786d9edb99649b9bdd25cb45ff2ebb8e4cefa445c8d993283887882b3d95cf40df91b8e841431e5add8c16cfcbf573bb62ea14749a88af1b2b49d3c2a664f6026430" + }, + "scalar": "0x1a815db7201a19e2e11c6d8396c27108e3e545df171b408de52318a7d5949126c686516ec527e7e1f2ce632e3d9da0e", + "Q": { + "x": "0x7296e008492ea8792568cda95db37843831c1e5d683d0358770b1159f0103586ed5f53f42842d19739ca3561a513b62b1f5270f6f80c7feed0fd84b7250e463afeedce18efb8e751e25307685f602ec72b9e18da43b06efa223340b5235504", + "y": "0xc51e95313ac136ab909460d042aadd1367df2fe5e102a64fc69adb75f56b4cb81ba53a7bcae7ee7ead5a6e5f85cdfdae797420a03fa3626b6d93e9a31f48792e93ec6302925f1863ce7e0877dc03a090b872d81b2c5f530818f9826073e53d" + } + }, + { + "id": 17, + "P": { + "x": "0x325af61a4448ebed6401c4161005fcde5f700b0b06a8390a7191eee7e5969dc918b12c5fb6f31470058f437721110a899fc58f9c8f7f7b27e849c6de954fe828d05077ea4b0e2b924401172527b84155ff00c768f21e037aa77b972b4ca18a", + "y": "0xda1655f2810c00eb66e4c6f5cc33f52686232c224ff6f8ced3d686c178cd1d354b84ffbb0d4c0946be113c32baa901f406d6a40e09073a8242a92a2426d42a00597d1699911140c546112a17b367980a813a6d1d6973bf6db8a694a7228c1d" + }, + "scalar": "0x87f0e6732a9ee33c1735f8c92e8a356c1c377edf4c372d2fe7e37eb37b8b1f9bc5a12dca538f23e7216aa90be015f3", + "Q": { + "x": "0xdd1648265e917af93afe35f4dbd9553d7c2698b03b725c922efc25c2b87ed0fe58798394d5565c12a28419c2ef3cd015baafff9660bdf3c93ba604537b9206493485722b63f4dda3d750ed998bfb2f2ea5459d3eb71a5bb83d78f508a78750", + "y": "0x2fef3fb3c5ca92dc388b7b6f480b44b18daf9d0392d8c864ba7de970a151cd8c3e187589b442d78b938d5be258e2a2bfd72b2ae31b5ee5ee65cb644e57edf549c27714d8fe93ca05cba3aaab5ab1a590a0c452ebf3b5fd673a07f9f97d948b" + } + }, + { + "id": 18, + "P": { + "x": "0xcfc2fbf349e49b575c988fb08a436db7394d02bad94ac8ecff6ceb2a01a9dd00db634636a43e52827a2d39ab085195a71d0b00183d9195ded1fd1cb6d461bef50ab461bf141a9c3a65a7844bdf98ff590bda8e364358cf34381d60ec93b899", + "y": "0x10e5f0685feef04e49128f4983eff16fda79f9f61ae8ebfa980f59ea51f46c3c9e54088523bb0363d0ba3b97f2bf260c4beb9598dd35021254929d7bce010fd048f374a66723192a8a530b2a087720b4df28927f2c9cc0a0b67a1f4dc7953fe" + }, + "scalar": "0x98f59db3a463084258ca815f09b097fc43f7df414ee1a2529c495e967162c47726092286fca39c3a7023dfee552b37", + "Q": { + "x": "0x1003664ae19a140e8d5571405c0f3db41f7f0c1256bd72df8f80aa6d5e27b2bc24e95b4c4cc168e8be4a8967346cff065433c41872b6fd3429019e1972d9873966ce0c61a939f3c43f6c96d38d316ceda26dab205be31be528c09c60356ffd7", + "y": "0x7e31541d549efd70aeb014da300749e153f772a05b092710ac7315bfb1eb706f0c9a97003fae10791317e11bf8e55d7cb3a1c5dccb675a6b6995284125d2cda01da2eae72df73fd1c2594c493d8eb85a536fb52fa3c7756e57ee7221ac1879" + } + }, + { + "id": 19, + "P": { + "x": "0x82aa7bad3d8f7399295ee41a66a4a568e8abba46238ce7caac96a5fc99d8e4db41af0d967837b7cc288684c89267d4d0fae0008596e8e6dbffa2191816b403e6e21e4939d24bfe46ca8c69b2fa6231f786212ee76fee72fddc7374c4c6232f", + "y": "0xa15684b2a33d3fa25655c18c7b72b83b7212cd47f4c8f3d9b49a028324126ace885f67365b7c56f1572275f29dd3e13866344a33b82dc15266a59d88a131ddbed3744d9a3682f761971b75293c522aa468d451b7fe3fe6a1b19d42d8af0e98" + }, + "scalar": "0xa55a5328457b26c0177c97aa827cf439be416b0d453cbb3d2b765870d0d58ccb3040313c10716cfbc28e8b0f0da617", + "Q": { + "x": "0xddceadbbcb52a6bc2aae010ee0f31ee1eb880034ad457645fe23dec4dabbcb581322880a31c0f1d1093df0b9f3716ccf35a4430f9d317c387875e5993bab8d44e1b2a34ec7676b645ab99ca239ebc39dacbd0ff096275711013f4461ad1b33", + "y": "0xf0fd3ff2f507e7926356d23472d3ec75a8d049193b4b61acc01c6f40f9b491a8b02437a565bf878b1d3e0857ecb5f40815b0ce9103936f3e288760cc0cbf5d9883078fad1fe466f0f7bbb7f3441f46788d9f6abf7b6370c0c793c8be9c06eb" + } + }, + { + "id": 20, + "P": { + "x": "0xeb6aa969dd6687db499a1f2d07cb87ee0632e64d3b8a6d3e563b7005351a7e1182145611d5c85918e8fa3cdc57ac7796697fd4f533ebecc1c102917c58c17eae978ca727b85172b7d171604a00a9d64fbd936f76b6d8f9500465eafdf1fcde", + "y": "0xe64bb21e0241fd63961900476152816f4749a4f3d1bb98bc5f43de36d8724e3b477ee7089868e7f73ff66318c5fd0894e409195af6965b5696d1d1d5c2052d5ec650afc71c87e3e43ddd6fcd67cfde996c5f604a971dfdf6f6fa35c8764c85" + }, + "scalar": "0xf35ee1965c92b03144c958da29ee67550da5d8ee8c4289d9917b5957b9b189ac23166f8c124320b7594bb813e20120", + "Q": { + "x": "0xa791b6c179d884e6ee9b311e4c81ebcaec28de4e4c8434246c64b4a6a24117641db794f038bd011090555e07a750f44059cb2c050b527da4d4fac915c5ec88e8c7b1059f01d57363b38c440a7f60d3e44e0908e7142ca43d46776e15570d86", + "y": "0xe99ead963be9c28818d3a6dc5600842b2a1abc35366277cfcbfdfb3996c044054af4a7ccd5c607e258b9b69f3dfa50ba6ad57d08abab98ca6ecc27f21a5824d1388697e8f36bfcc113e3ba89b174480a560f516aa3ecd32f8ac4b8e0a0859" + } + }, + { + "id": 21, + "P": { + "x": "0xf002c90119bd2b351855ac7310692c3f5565d76fa44360797cfbbc56a7bbe625d483269f1385c9f1d1e1a904668a5858d9f460f7fb9185bbc8669cb346ebdf4ddc8cc413369d04cd3b248361b3cd5450255ef45a09cba0a11e59cbf67e8c34", + "y": "0x25bb32b037a51322a5790939cdf064ca27feff8c53dbc9a9ec9800abbd420f4231570d76f50b09d9fc173334e175982032c594b6f9ab5633f61efc8ec7abb899761576a68c9e649a339f39ab26846a8e9844838a0ad821728643864cd354f3" + }, + "scalar": "0x1a30ae1a088b1a4ff413926abeba594e9c6194b4abecaaa9be786b2e9b1a487de6aba81d47818a8facf1a716d463173", + "Q": { + "x": "0x420f4484d6f509b54c1767a20acbb481bab1f78a82011a4e113b40823114bbae4c5938c6f1f5ebd807e01735d549d5710057dcc7e2037baed17b62b5af742fa51c98a379becd1b0a0d84550531401a32d8fc57d9a0c40b88be4732626a3395", + "y": "0xeabfbb6aa4cb8ec33f5bf6b466e9e08e509e2b0fa9bcc3128bff4a7a49b71dc8daff68e800d8d3e83a8da59b71c7a6c0d7f5f09ca15610c1840f1d81e66f5b9aa384c14be5f1e3db146b450d1943133979c22e26885129facc385aba11cd66" + } + }, + { + "id": 22, + "P": { + "x": "0x5a6f12252b61763f042b8a806901a59daf430b11753cb6d8580393877c26fa63110587da5345336d7cedbb7538d27247a1070fcc8e9fe1b95f12d9a0f471a400dda3ef7bea499f6ef42fd4ba35f7b39be7d66e103c64205069d3e8e6163894", + "y": "0x8719216b9c1132e320ca3df24f21d59b80a4e7254883c4383657725db0bc6d3c63e82f32f45a3b8b0c917c354203bd93e2bb64bf41c7c42d3393d224bd6c0dde019c9abad8fd47bc4048e03ce652551053d67bf32d15f83be3e2bd1d5fb5eb" + }, + "scalar": "0x4d52f9709fae42736d304cad0791cb6af665fe4bd777eedfa49eef0b1a314e58871de882a93d7a00e6c6c57f66535a", + "Q": { + "x": "0xd118a3b5bda5477449809e96b31838b956a30438895d22c4d41e1ca4c1d658a4d5c2a25dc80b01ab8844f930e9b28b724f31e9fa7999c200dc9a6b0483211e4ea3f1cd2d222163aac57eba46d8d9dd2dd20f88b63a53ccde74cde7627845b2", + "y": "0xe53ee684db44fb5487cb51ed5aa4e212a0abf6b2b77662b1aef727d396a4a78d0f762b684af23d339039cd090d77319ceb555ce313081b7b6b8f091632b798cdf76ec2d1b160f70ca261b6205e633990ae1dc6d92706066439751fe90e5376" + } + }, + { + "id": 23, + "P": { + "x": "0x1092a20751b0364520204bea0c469003360e1e8df67106325028ee937e3b5c299e035482042680f0921363d4200322960413b3a719c6982e08e423d44a70863e80ff0fa3d885eabae7f5c194cb6ec52187364382f89b894a41bf58e367bf559", + "y": "0x9e95d52a786bebe38c2cfbb490aa5bbf6caa12c06cdb77a9e151bf7af2202a5d3a8ca9e5f95013235f6e430fcc6aac01dc933f19403c540ff0ce22526532b608c68b1672fb0789ccf72dea585d7244762e9b03e987e26154d3000ae2624bf5" + }, + "scalar": "0x1800ea2940e1feb9f93155326cd135e8a1802e2df9d1b37bc0bb53fdf5ce0228463be0bddbb6884e25f3c97d66fc7e5", + "Q": { + "x": "0xce9fd299d5dbc321be86f520fe1fdcf91e08e32d0988ef5be8f9c282dc3602e71291c80cf1fb43f9ea0493980c0cf98a801961a80d087479330c44de53c58f36d085d15e28c6fe149331d277b1811b03f345030d5746d57425d3d5469f862", + "y": "0x6091993296a9a5a99f6cacfd8168d8a1e1d45475c8f87d6a2e2f68659b98d5ade66c50db02f34f28055c01ccad157b2cadaba9d1379412a6950f9259dba0b31caedf1a052a2cb1bb509cd0fc86477a4855c9480afbb5c5fa1fb24e71b8c41c" + } + }, + { + "id": 24, + "P": { + "x": "0x853648f7910267d2f65a6973d9349fe0ac64d2cf6e060288458bd5743f8c9469025ef7b67012c99f80b1117be087f24fc630481f45ab7f9fb8b565fa719a9f86daa801a5ab813f5a605892cc9cc01dabf81e33447ab4851b985c5ac754dbff", + "y": "0x11d0d0a3a7827413488f6e22f012b6dfacd15d6fa76973e9cef3fb28a3fddb2d67c11d4b3f9426e7a515a345ba57d77e5bdfa64856bccfc41c77308fd0e39633449225bd876f1de286ccf2ab38364174ef5c76c0b436e55bf705e979c3514b6" + }, + "scalar": "0x96278b116b1d748d799bd67e1ff8bf6604ebe96d4e7a68ab55cd9db254ea77310ec9ee5779b355bd32e3c381cfd371", + "Q": { + "x": "0x9cfed0f6f3481d39ef07d7ff1eb3b9ac14953c7d82ecb327eb98a1d1e7ce6fbd55edc45e1d3630bc5793568b4a05aa3508f78700da3859912d64cbd49190dbda1891f6afc5d5333a85a8f94ac13d98b79eb968761dc3cbeb15702f80e2ea37", + "y": "0xb603f0e065333aaf4235e0b28b6005fe07bb3c8a55b67ac597278ccfd0c383fd5ec65bff3158afd21cfeaddf002e761c7142c5c3cf77762056e171f99d80571d1b110239282b6a565f1de94085ae8271335a844e0ec2a0c5ce2f5efd22949a" + } + }, + { + "id": 25, + "P": { + "x": "0x2bc097ff5fbcd10d1a247b5ed4ff7b47645721d3cba06c92975802eb465c26ce151c0ac947db29d4848ae6ccd8dbccd3188ce6f62293bd3b10db72ab29016a7005e88c214a712f162e7ecda6ad78b451b30d2b5bd3382f0f2b289759963900", + "y": "0xc878cf1cfac097bbc84aa5445c083febb4da4365073c98b30a67f0c89c2187168849cbd61de920d61f6c6717cb454fba79d8576f77eb3dba2b871048919ccdb4b7c5263fbd755b87a2b9fa4df51be554ba27e38fc2675ec9e5fbcb425204bb" + }, + "scalar": "0x172a23bc1dede10a35d922930fcc492c0b334f5f738bafb18be34dd34a34237dbe729488184e91c2176e46e8ef3d592", + "Q": { + "x": "0x2b8c4fa14ff82ebe9b00c0314c3f2db2fd76ff0b6c61bd6d70e687a4efeaf73ed554546ae08a7f36175efef76065263aadc4a2678546d0384ffbf5fe8665be43237ad865c8c9db9ebe656e726231d89619365510ffac79be02b783964e68c", + "y": "0x2dcec2cf2e0e0c09f2bf1790fb619fa87f9bc3ff245cfa2b0cc4190dcf8d5b04ea21e7195c0130d3012ca2428123a78a7d85155fe9fc59931a9ea3a7216331cc7fa87811eedddcdbe94c2967751724ebfc6bf24d24e22489665389f7da0b4d" + } + }, + { + "id": 26, + "P": { + "x": "0xfe8426e2cb385e86078c6eb3b426c82d5adb3d76d8a2b4364326e9c7b25f8dc28f0dd92d3689296fdacbcdffecc19420982c9d9cb7e16697c9915bbf33cce664647e556169268a56b815a9a22d9c08a221a645cc1c2259586d3de40e28d161", + "y": "0xbc64ce948d87b11faa0b810932c0aeb11c9b93f16e5f462cadc5bac36be8ab1018baf4eb35d70b93f20ed991b1b11a861a4f81f839f55f0228baa0cb5bcfa2e2c79a96f7bfe6cf2825a70f07004c0242fe75f18210d237bf3c3a2b9456c49d" + }, + "scalar": "0xeefd4cc0f631b5070f6a104e01532d00ff7abacae3b7bf06ac47147e018be511a2d9da23050000359647641926fd54", + "Q": { + "x": "0x28d4ef5fd4fdf609073ec91d48c3df0567c4e96f7447a624df5d1d66bc0d0492c4a30dd80965a5494026988989e3856f754877864cf4476f86de4c0a53918064f68023cb2d4c949c01845d0840215717dad08959c77bb3b5ab236799da06a", + "y": "0x7b6777f400be3cccb99be9ea2a6559e7bcc4cba283d11c1822c1a30497f21778bb4e19a6dfa09c2366a94885bbf7725908e535be9ecd7db40393875c9f90494d559e3f0e9f0b56cae38a5561f7e10f4dc64a003d8e313371579dc3468bf67d" + } + }, + { + "id": 27, + "P": { + "x": "0x264c12bb54c2b26f57df64cf5a802f0cb1fb273742606f6914ddb244415194fc07723486041b3d786a8c0cfec8fdb232adfe671f8102379fb279aacc1995f910506205dd983e8fd1a9ee26fb84c745a23399ff546460cb62ad73c8c243e0fa", + "y": "0x1020c32905905c7edc3c66e0eecbddbeb59fd07a35419fccb2e90d0067f0cf25093badf35d497ce7889df26ec8a801b1ef46417a1c8c49826d786180d068e092e82b0739ddfe3fa5328761ac0291a9fdcf921af98a63d86ed953e3ea364c05a" + }, + "scalar": "0x10eb3c0a4ec174f5bcd734139b16bc0eebc44ecbd8273d892b9ce9ee7f648a53a97c57a60582a44b2aaf28432c9577a", + "Q": { + "x": "0x7c018a6be1fe305753496c0041489517fdb3381690c6c786855965958534d5ded5230fb6c79aa28b80004aadd81925e8f1f7c3eaea32ec8c0bf6814fa515048b8a02349ca518b54e4af6a8ed91ec56ecc6a703b146eecd1d58410c6da87bff", + "y": "0xd8c0fffab8ee5da2aaf2f1531cd595c821fda42d377eb5367c8317b795e2078672f4ed620b97e4752e4db590466ceb0b0d7f94036287b9057ed2a22eef9265ae8bef337c1b30ff2a074aa028d0ed28443a40ba8cef4f8231e894424e28cbb4" + } + }, + { + "id": 28, + "P": { + "x": "0xaeae0af1a62b42386d949eb0530d0905bee22548c8fdcb46ea2e3defded5e0dc8c07a3ad0423bf2820860b6e7dd9497f0764767d994c338a2f2002d69c56d5a3fb26dd3cead70b6ffd0fdfd1aca6a09e26ee1d26fec266220bf8ca963f0e31", + "y": "0xa3e274b4e774a15b70bf8ab2385dbafb6dccb177971fe45172123ede44fc678e66f94726ed3c426a5217dafce095c252ee97d70d6b26160d8f138bff39c60dd6a8d7c2f2f21c610e221b2229ca5247d6d2069a838560c5627dfd5693abc0a6" + }, + "scalar": "0x537ddfa23aee7312c44e5505cea7c2716ec9cd58a783019c26cef869a34698b57d707ad8eb2866581b710518e4c2e", + "Q": { + "x": "0x8906bc4c3f3859bde45bcf2874b25a24782d23669caf44c0296d5977c0862fc553f45ee542fc123d9769d7806ed9b6a1275108ce4a3f5d1d0f84d373de2ef97d09d4362cdfe1852abffcf93cec0bb84740dee52291fcf5d5687cb4a65afd02", + "y": "0x30ca324b66256c7596a180cf7c6d80fcf084ab7f39aeb7009956f51bca29080bdefc08fb22bc191075b2013f057eb234f8cf66fbc13d6738fb1c816539d5ad53bcc493f4ef52582ed8f2ea44e16bb73da1dda48ce432d29f5a3fb71412ba1e" + } + }, + { + "id": 29, + "P": { + "x": "0x8e19bff4c15516e3e70600dd731b431362a3d79b3fb1ccee6e6816901b70854e70435442d6587fbc231e9db188fc74ab29b09d9b0c8e1f747e1309c43d971ea9b776b654deb47a9c333f0afb0449f9985a46549fa9ad5e24c258e1de605a31", + "y": "0xd8d43c0af4a7a1324a0d774ca4a17d9b4cfc95c62e9ee474ec40fa04185fd2817e392eda8366eedf9618b282f9e2b52ec168b659d526e8e643f35f6d759269eabbefc919e45da42c9a101d40b5d1952727af0f69ca3c2e1947dab7d8b586c0" + }, + "scalar": "0x86e1cd852f2696195634c18c60fc483dcdadeec4eb9a7264b5abbea75b0bc310806ef765e856e9b167c6f4972e7150", + "Q": { + "x": "0x3c9e6031acf32ea11ecd0df9f7289e2a65e4df32c0e2a2386edeb8f3eadf1c6d2d19672a3d13ff2815d458024f4c1db6bfda656eee512aac1d7c2e94c0089a1e8a82fe0d5dcbae09e3a1c590cf38cf7c22a3ef85dfe5be1cea01da46c1737f", + "y": "0xaea96747cc3d3a8a4ca42525fe1bd25ab93e2298d6ac7107b76840fca9f20351e34ac75d9a5b7080c8f7d605d55a08bdb41907194a2acb9d5263c2a2e8ca82103781560cb1aa1458557ac08ffb0b01af5ef895ffbd85d65c044c512d583c0" + } + }, + { + "id": 30, + "P": { + "x": "0xcde547fa0f2e91895e46d4b0d2e68901f9d510eea91a1211bf3095da6d582333cbaa9fcbc638a1e1d11e7bf61a2e7b8fd29bec05ada7c0cd0bfbcaa9572686ccc3ec2b23f71e89137a3910222823d24d3046c2cc741125743b8390b3bb4c4e", + "y": "0x497c939f755f3526b20e75abb4958aa666f268e879cb7eba3066f9b26c8be822437d2d75caec11ae06e00b4c7c2ba2b9cca8c4db5c320f4bb5e1a8b39004cd304e1dff0ee2a0d690299d5f026e2226f9e8bc7948c041835d853caef732f02d" + }, + "scalar": "0x1902f583a7a8174ebd1bd0060d32c572f167bd0507ff3b13e7d6f6bebcc768e5f401310c951f8d451d6bc755573ff39", + "Q": { + "x": "0x2183beff6110322b9873c09150cefeca0dc2479d95fc42061b1593de5f6fd3cfa34359a64f4428420573533b3b1538d635f82177816d06c292d5dd70b096ba8c462aeef6db18487c35b7807cbbf06364316840b5030d13aec63079a6a6f126", + "y": "0x3183fc2b160afcc3a842663039c6bede7b0edbcf7dfef14973c2e4dc444da857d4ac57aa58091db926fb6ae1e05601d251414972e0e0cc39b7978c8ec7d6378dd3026a401cbed57c8e5c215bda0e3f0c79b3584f5f63e9c4762bd76068d412" + } + }, + { + "id": 31, + "P": { + "x": "0x1e0384f6cb173344f0c6766a1c7ea55eaf713e1dfa5b80c940b98c0fcd5259d6760ef03f05086958564b66c4381a1b5fd095ecf9a33ef96c82b11056b2cf7ebdbd36244983ce15271055a1caee2ccad3bcc29be1ee661c92d1108c1c4182f6", + "y": "0xe44d5719e6f91c2d581695aea92ee86249f9c895129ff2d84833a29f571357df451f40b75b7b7ed5e4920f9dac1a1ce3b29ba05bfdc24a82b433502e9bcedf88ebee95a3add1f9768150177b8d121678a0c270cfa25b9fe17da601fc5c5e49" + }, + "scalar": "0xbbe30f2733979d9e0460ef722b4e388973ccea3f34cfca5ccdf0f666804e5181ee65bcdfd854cf57e91c8f79d029c5", + "Q": { + "x": "0x45c48ac10e518546a948039b8dd7307adc50d4f9e254204f543c3078195ea291fb9079737590eba7f622701fff1d2f7d17d3ce758c413e741b2c5c4dd5ab4815aa7f251e1a21646f7833c487972227bf8bc00ec125850175f4a4ba5b5d10ad", + "y": "0x8ba3130d722adff3818bb38a8206f4de9a54c7fc25635b3ea37c1ce370feff96212603549e2186e44e03a4b88f3c9d95b95512eaf2c29a5be7c073c7c32d6b4e7de7ae4a182ddfecfe1e56a2b70a345e1775e4ac6a1fd080f24352f303a3ab" + } + }, + { + "id": 32, + "P": { + "x": "0x520f96c358920d1ff21b29261a02f0069956778975d490038f66f3f11a5c83df13277beacaadb5b8e56e3bca38715d1e8fe328076e78032c24a6450839ba30e60207e8b8d7d89921a45f513eda61253587ff273fdc7b558e79511a222e2c96", + "y": "0xc40ce36547c31844d916c68f7d08c88d6fa97af17cb2e0722f02a554a25b8818d5afcabd34c7956ef9ea7e097080952e0fd82ecf9a7a8dd1613b2b08fc1337a7b251aa50a53e80885c2c64c73775eaccc1effb684eddad841567128a54a8de" + }, + "scalar": "0xfea339aa381b1b64af440ada010031f2171ea60cfc33b8bc80c210e464bd9668f3c620f14889dec8e26c3d561f5129", + "Q": { + "x": "0xbd3276413f5fcfa6d517def13017c5c662a4a81dd2d9acede174c4b25121292347a5dd6c6206d4606548594f85a68641863236768476030c143d2a578b562ad52837b0df3d1100eef08a815efbc5be35628855498e275e3a85d3f7c4075479", + "y": "0xc5a82c1b1f66eab411803ebbd97d086941a3e9111aae2d8cf9f887e3acc3ab40a13a7069a869c6438e63df278aa26ef3d72aac7f148d36ed7bc4c0151215a21607956964f0dfe6e0ab47297a2d203682c4dbe777757ce828955a4d53ecd2c1" + } + }, + { + "id": 33, + "P": { + "x": "0x47784e91851f3a90679f213084daad6f7175216db2c78cd4bfc42277c3382d9d48838639241a84d30309ff24ecd09e9fde7453cc0560f5cbe2b9fc1cfa17eb28c3000ed49bfb9106d2c8f53ca56d7a54d174731bfe8174f0b2c198319180f2", + "y": "0x4561e9f3f956334b6f1bf2bb8a2ab951d60d1961646e144b8a29916bdf9b9e1d0c07a1f58f544776f06cfbfada04e084dad968cbd647432d10e94e35ada3ab738eb2991db145d236bb4a7247374a04fb5e6ee7bdd543d2f057c3e8bc773360" + }, + "scalar": "0xd530c10fd9449913c19a52956c5002489acd09ece67cd2f1cde7bf3fa0ddcc9d03b1388e7a2a89e5393c468be2877e", + "Q": { + "x": "0x11eb0350fd391ad89c27478218403f10b6d5c96bd6dc474b6f5e3676f998b61df9e00842e8390496d6d3303140cf3c0b8d5dde99a50fe7b328669af3bad05d13a9c664cddef5185128d47d49b3e0188c5dc202dd95bdc29c3c4203b12d77cbb", + "y": "0xfa32aeb6b42259a3e9c9c1aabb0a1bc9a39e26a812926f875159a35e4078a24a35d104aa93724725dc264935af2cf47d0e25c202e499605843d9e3d1aa0d0a1b79659f5ead99f37cfc7c47c55381c058e04e9d31ea71e85c8dfa072ef03c7e" + } + }, + { + "id": 34, + "P": { + "x": "0x809943c8d93c6db72538927b2a7c1cc427835b4ea952ff994ecc8aa9c4fd4b3b3708ee828c3112d8704a3dce72dd96a1181a624afdedb7a6e33ad7e48e2e6404d33375b42674a9eec1a7c90931a1cb9a973e59fac85a56e20a30c37032b449", + "y": "0x12245f2022de09660f609a4caf20a1c7818f46752d317b7f995c1770a56c3172e6d4923dcada28c0bbea0087acc2b8e2a839e985a669d579206dc19ba9afe1745456b2e6232642ab8b6e29e8420426e333362fb818c36ba3d20498f505d15f4" + }, + "scalar": "0x1a66bcfa5a6c9ba9bd74ee4f50f7c1dfb8ab477ad9e45826c9f3d70043ab990069b282a76b20492a382af89d492f935", + "Q": { + "x": "0xec5ad71fdd54108204c80230c29dac7d5b0becd26223ea4c130c6e0207f31200e657737cc3a3bd6bcd8dced7a693b5242a8c7e09c8bff8836d8c1feb1eb86cf6ff2624b8711ffd0655bfc759062c1b9d765f167b779e122fe6ebbf8857a188", + "y": "0x10fcce0c708c73f23f637fa8b1d3db3745df4e0cdae8fbbe76c2a9d81f8204f647b70da15491e21609b5d00cf349d5f9281d3766bf43ca6c80e2dba1d549c85db8cee4c9cc28cd40590fe5450efd3ad77e73891e366e03404f066d2a5cf8113" + } + }, + { + "id": 35, + "P": { + "x": "0xb6cdae305129bdb24e248231c12eeedb244182ed49f847a307af869b61b633481c6713ecd9819a6f6a2726c768e92d848833ab54e14dd00adb93f9646a17ae8df67a213324f519401ae44a4f30c9d8bff543b9ed1f59dcae3c03fc36ed2b98", + "y": "0xdc2b9886b4b43756c3a6064b38433919314146dd2fae73cc34bf76576994459420b55725ce51668771020827517292a0274b2736b6cb99beed841f1f075be579efa5a4faced18587a68c82bcbf7dd8f4c70dd625873b1e8c5d0da727a2d0a9" + }, + "scalar": "0xb70e53dec30fa362ffbd21cfaf1255f1ac3b6dd1dd017e4d797716167e2f0ed7293389c7b584c36c968641f6e5b7e2", + "Q": { + "x": "0x8ede2e7e6d167f554e14377bae219cc58ccb26e346ef347b636ddd013bdbf27d9d0120b45a442b103dd9a8d330890aeb3545c086919e6adbb106eb36232411386e12af3ebe665faa3e2dd579b53a327421c09ae61e1829ff3d8da9d80f243e", + "y": "0x8ae445ae8299d70e2b96e0cf2cac27e77a5723a26502c71ef307eb4f6bf56cc2453723dd42636c78f33193d490a5dfd093967bd721c42fc9e8d54b1811e21013ecf6e2dd0948344121cd7e58dc4022d77a178505b4fdb6326df9dc6d7027f0" + } + }, + { + "id": 36, + "P": { + "x": "0x69a1e973c7eaab0ef3381d4c99eaaa4b6dfbd2fa103f01f0418d8d8ed878c2dbd4a2d840f6e600dc0bdfb419597f4a731d21859d530e58c8f2e3dc96731ddd2bc44c244cade09fdddccc936b1655b1f84b7d0dbc5bc129693d85ab17e50727", + "y": "0x3074120782010de499cd11c88d4721cd8e4af55531546065d4a8cce042ebcf5f06ba2ce378e088e798ceb616bc9bdaee7ad508edbe4e29b063647c164951aeca6cf16d6725ecc6ce13e7d6e4d49a05a030ca1ced500aed2c2cd46b6a3a59a" + }, + "scalar": "0x1887572daf2f7334820384013f053c899f17be8aa297e130523e8de5a10a70389efaddd2beae128b4daa2f201553bb9", + "Q": { + "x": "0x11bf0a6f66ae924feab4e7cc7d545b5e7d1959db756aa93dacde7174fbd813653cc092caaec90b0fa3e683efab64454079d3c4b24d8484a400faf67778445bc808c27eea96691211c35e289adf606fbc4982fb1468be9bba15d015c5d37616a", + "y": "0x88beebccc6a0eb83044627f41d38343e65f8233f929e3384780c991bb4c88667459b16e92faf3b679ac700377eb46db136dbe6c93c7a76a333fb1a9a48486adce216e91bd16381f85fbf528dc73dad567822c9d5bf763a97ee157bb3adcaaf" + } + }, + { + "id": 37, + "P": { + "x": "0x6ee26a654c1583032b2695a745d350491b3fa1dfd4d96f56e8bb7fd46e91c9dba40bdab76fa370e118238472459eb651caf3c4a6fe4b484853276dc843e73653e8b95049824f49b2ed60bada770c0fe516890248c852dbf33eb519bac17fdd", + "y": "0x4b7a3c45af1e754945165027120eba1099624705f15db1c5dcfb7354ba26fc6cb7661bc4a50a1392edc5332453abf131341e7492f21a77a03134d33c63a7de2c93b865b4a851df667493518af30dff9f6a1e8eddb491d7877e3a15b7e5adda" + }, + "scalar": "0x1206176ca811d9c2ecd9e34bf8a1acb212960ab20daef573113d404b7a4f8cc2fb2cdf97ab07a356256ff38848b6faf", + "Q": { + "x": "0x5a6a163fe464eae57c819e74abb083abb4c6d6b0ff3edee63f6a121d5b9cfbf7d82e50fc17f2dd9a3951a27ffd636a3850497735697be8f7cc5a4ac87b4d09c06094f8adc25511b50cade67cedf359869344e17598a17d041274d682723624", + "y": "0x27c82de803d72fa20e2cfe83366ff5ff6325f8ff056d7839550db387a1c3ee9d18db3e66a162ce6336f3a127abfb38c8b517c6f5a1328cf3d4e1e8e6bae0e70a7504a5b524dc2d2e2cf3b4a702f4d67203a05cb058dcbfbab2a25e5a1f66e1" + } + }, + { + "id": 38, + "P": { + "x": "0x12b7e9c103da8136143aee7ecb7947b52e8fad1ce35f061953727d11509cd6f80deb487ec5e31595616d1b8892c676ee0f2d280ea674ead2a1254ace5808559076a7530e8b960a6c69bcf24d36254b02133d1edd38d421c3d9e7ffabc34068", + "y": "0x1a03a1f6b82f669524eff54cbef0ac9d08dd6652bd4971097604ceb8213dd1b078e77fe6160321d10e33b6979c5b113656004ae40f97f2a1c51b9d46870086385e1d935e9e7d385413b50dd39fb9a8b1b96cffd736b319c338b7de6356b698" + }, + "scalar": "0x12544b86d259ee660584d11f8c143e0edb5b17e001d63a45dcf1ddede122e91f21a1a42d2334d8c97e1c19e00109d34", + "Q": { + "x": "0xf208afc0527e9c777113a63c8a7fd437e30366a48fd98061d633b62fb36bfb2c4deac5ac20cd1c43f8a2bdd84be37b234b4029dbe5857ddbf064d0543de1636dd53204e1c3345a18537698740277515a5b606e43d62a52fba8314872b1a314", + "y": "0x836871d27e959035bdddda26e66dfd8586485d1a7774a0a4c502d517ba5bbe690a023456ade36ae6d1c0558f849e8e5f3b67c95d44f5f3612e13f8dd5e592b6057677fa0cc94977812244223d5e630763fba37b2e586ed0d9c29d3ef651197" + } + }, + { + "id": 39, + "P": { + "x": "0x10f3313a585a0de35b9993ab1172d041feceef3ee87747be872af04035d6038f9fbe1a6c184fcae3b9baa40af96e3007464aa62d44b477720c7cec7e6642f83a1ca4f8a9f676992da423770851663aef03effafbfbaf3ed0351bf79572bfb5b", + "y": "0xa2bb47a7dd0fe83557b8448f078dde0e756c0bb12421ad3b7326f3d39dd07f113cbf45dcdb4492458f43f054f14ae95e7f20024863a04d223ab5b8f6e02c3efd6c50dbbd4fc4b180558f1a13fcff8c708ebd6e8167fb8585c5565c483f8e18" + }, + "scalar": "0x39d2b243507d8a840674119541c34a72a217bc74b669db31aa8f9f67949f1635b41b2d11e4704199b5ea2fbfd2c1e2", + "Q": { + "x": "0x4eca58459b8b74bef8c254c2e0780968f7804f3b67a744cf0b4a3605bb41335cf83232835468ab970a52511c3d8468e7baf2552d8d1f4ed02d1f0bad2d9da0ef2b13069d5113f3b8bda757bb0a5f5a11973fb2004e8e3f6ea474fcd7b56f0d", + "y": "0x56a76b579fc882820d4a298ad2cd43b0f6f637f97d79ff2669ab1e57aede5a92700b0906a49f6b15050e0c74439cd429aec907df1cb95ebfcbe08e08db7b6df7645319bbb939c655f6fb382d8b963bfb2ae97d2bd94f0d45a13f9ca0932a61" + } + } + ] +} \ No newline at end of file