hopefully fixes #10

This commit is contained in:
Balazs Komuves 2026-04-23 17:29:31 +02:00
parent 5003f16e49
commit 1ba5c4a263
No known key found for this signature in database
GPG Key ID: F63B7AEF18435562
7 changed files with 149 additions and 19 deletions

View File

@ -8,6 +8,7 @@ binDir = "build"
namedBin = {"cli/cli_main": "nim-groth16"}.toTable()
installExt = @["nim"]
requires "nim >= 2.0.0"
requires "nim >= 2.2.0"
requires "https://github.com/status-im/nim-taskpools >= 0.0.5"
requires "https://github.com/mratsim/constantine#bc3845aa492b52f7fef047503b1592e830d1a774"
requires "https://github.com/mratsim/constantine"
# requires "https://github.com/mratsim/constantine#bc3845aa492b52f7fef047503b1592e830d1a774"

View File

@ -1,5 +1,5 @@
#
# the `alt-bn128` elliptic curve
# the `BN254` (aka `alt-bn128`) elliptic curve
#
# See for example <https://hackmd.io/@jpw/bn254>
#
@ -53,8 +53,14 @@ func unsafeMkG2* ( X, Y: Fp2[BN254_Snarks] ) : G2 =
#-------------------------------------------------------------------------------
const infG1* : G1 = unsafeMkG1( zeroFp , zeroFp )
const infG2* : G2 = unsafeMkG2( zeroFp2 , zeroFp2 )
const infG1* : G1 = unsafeMkG1( zeroFp , zeroFp )
const infG2* : G2 = unsafeMkG2( zeroFp2 , zeroFp2 )
func isInfG1*(pt : G1): bool = bool(isNeutral(pt))
func isInfG2*(pt : G2): bool = bool(isNeutral(pt))
func isInfProjG1*(pt : ProjG1): bool = bool(isNeutral(pt))
func isInfProjG2*(pt : ProjG2): bool = bool(isNeutral(pt))
#-------------------------------------------------------------------------------
@ -73,6 +79,10 @@ func checkCurveEqG1*( x, y: Fp[BN254_Snarks] ) : bool =
# echo("eq = ",toDecimalFp(eq))
return (bool(isZero(eq)))
# note: for BN254, the G1 is the whole curve. This is however not true for other curves like BLS12-381!
func checkSubgroupG1*( x, y: Fp[BN254_Snarks] ) : bool =
return checkCurveEqG1(x,y)
#---------------------------------------
# y^2 = x^3 + B
@ -97,20 +107,48 @@ func checkCurveEqG2*( x, y: Fp2[BN254_Snarks] ) : bool =
eq -= y2
return isZeroFp2(eq)
# both just fits into 254 bits
const G2_cofactor: BigInt[254] = fromHex( BigInt[254] , "0x30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d" , bigEndian )
const GroupOrder : BigInt[254] = fromHex( BigInt[254] , "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001" , bigEndian )
# checks that the point is in the right subgroup
func checkSubgroupG2*( x, y: Fp2[BN254_Snarks] ) : bool =
if not checkCurveEqG2(x,y):
# reject if not on the curve
return false
else:
# multiply by the order. Note: this is slow
# TODO: implement <https://hackmd.io/@jpw/bn254#mathbb-G_2-membership-check-using-efficient-endomorphism>
let point = unsafeMkG2(x,y)
var q : ProjG2
prj.fromAffine( q , point )
scl.scalarMul_vartime( q , GroupOrder )
return bool(isNeutral(q))
# var r : G2
# prj.affine( r, q )
#-------------------------------------------------------------------------------
func mkG1*( x, y: Fp[BN254_Snarks] ) : G1 =
if isZeroFp(x) and isZeroFp(y):
return infG1
else:
assert( checkCurveEqG1(x,y) , "mkG1: not a G1 curve point" )
assert( checkCurveEqG1(x,y) , "mkG1: not a G1 group point (in case of BN254, this is the same a curve point)" )
return unsafeMkG1(x,y)
func mkCurve2*( x, y: Fp2[BN254_Snarks] ) : G2 =
if isZeroFp2(x) and isZeroFp2(y):
return infG2
else:
assert( checkCurveEqG2(x,y) , "mkCurve2: not a curve point on the curve over the extended field" )
return unsafeMkG2(x,y)
func mkG2*( x, y: Fp2[BN254_Snarks] ) : G2 =
if isZeroFp2(x) and isZeroFp2(y):
return infG2
else:
assert( checkCurveEqG2(x,y) , "mkG2: not a G2 curve point" )
assert( checkSubgroupG2(x,y) , "mkG2: not a G2 group point" )
return unsafeMkG2(x,y)
#-------------------------------------------------------------------------------
@ -132,12 +170,18 @@ const gen2* : G2 = unsafeMkG2( gen2_x, gen2_y )
#-------------------------------------------------------------------------------
func isOnCurveG1* ( p: G1 ) : bool =
func isOnCurve1* ( p: G1 ) : bool =
return checkCurveEqG1( p.x, p.y )
func isOnCurveG2* ( p: G2 ) : bool =
func isOnCurve2* ( p: G2 ) : bool =
return checkCurveEqG2( p.x, p.y )
func isInSubgroupG1* ( p: G1 ) : bool =
return checkSubgroupG1( p.x, p.y )
func isInSubgroupG2* ( p: G2 ) : bool =
return checkSubgroupG2( p.x, p.y )
#===============================================================================
func addG1*(p,q: G1): G1 =
@ -229,11 +273,33 @@ func pairing* (p: G1, q: G2) : Fp12[BN254_Snarks] =
#-------------------------------------------------------------------------------
proc sanityCheckGroupGen*() =
echo( "gen1 on the curve = ", checkCurveEqG1(gen1.x,gen1.y) )
echo( "gen2 on the curve = ", checkCurveEqG2(gen2.x,gen2.y) )
# TODO: fix compilation error with Constantine 0.2.0:
# echo( "order of gen1 is R = ", (not bool(isNeutral(gen1))) and bool(isNeutral(primeR ** gen1)) )
# echo( "order of gen2 is R = ", (not bool(isNeutral(gen2))) and bool(isNeutral(primeR ** gen2)) )
#[
proc sanityCheckGroupGens*() =
echo( "gen1 on the curve = ", checkCurveEqG1(gen1.x,gen1.y) )
echo( "gen2 on the curve = ", checkCurveEqG2(gen2.x,gen2.y) )
echo( "gen2 is in the subgroup = ", checkSubgroupG2(gen2.x,gen2.y) )
let primeR : BigInt[254] = fromHex( BigInt[254], "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", bigEndian )
echo( "order of gen1 is R = ", (not bool(isNeutral(gen1))) and bool(isNeutral(primeR ** gen1)) )
echo( "order of gen2 is R = ", (not bool(isNeutral(gen2))) and bool(isNeutral(primeR ** gen2)) )
#
# the point (computed via Sage)
#
# (2 : 2237046587054574173616397632856518880513033439888792180868262182050662989363*u + 10894412225134874879786325788974416805327887441035008073952212076423500941133 : 1)
#
# should be on the curve but not in the subgroup
#
proc sanityCheckInSubgroupG2*() =
let pt2_x1 = fromHex(Fp[BN254_Snarks], "0x2")
let pt2_xu = fromHex(Fp[BN254_Snarks], "0x0")
let pt2_y1 = fromHex(Fp[BN254_Snarks], "0x181604d0560080401c08b557815482553e278257d98100d193a011c42782474d")
let pt2_yu = fromHex(Fp[BN254_Snarks], "0x04f21f9d99cc25f694cf22ff70dc0ac4692e7a721b725dc454a217f04bd03e33")
let pt2_x = mkFp2( pt2_x1, pt2_xu )
let pt2_y = mkFp2( pt2_y1, pt2_yu )
echo("pt2 is on the curve (should be true ) = " , checkCurveEqG2(pt2_x, pt2_y) )
echo("pt2 is in the subgroup (should be false) = " , checkSubgroupG2(pt2_x, pt2_y) )
]#
#-------------------------------------------------------------------------------

View File

@ -7,7 +7,7 @@ import system
import taskpools
import constantine/platforms/abstractions except Subgroup
import constantine/math/endomorphisms/frobenius except Subgroup
# import constantine/math/endomorphisms/frobenius except Subgroup
import constantine/math/io/io_bigints
import constantine/named/properties_fields except Subgroup

View File

@ -33,9 +33,9 @@ proc verifyProof* (vkey: VKey, prf: Proof): bool =
assert( prf.curve == "bn128" )
assert( isOnCurveG1(prf.pi_a) , "pi_a is not in G1" )
assert( isOnCurveG2(prf.pi_b) , "pi_b is not in G2" )
assert( isOnCurveG1(prf.pi_c) , "pi_c is not in G1" )
assert( isInSubgroupG1(prf.pi_a) , "pi_a is not in G1" )
assert( isInSubgroupG2(prf.pi_b) , "pi_b is not in G2" )
assert( isInSubgroupG1(prf.pi_c) , "pi_c is not in G1" )
var pubG1 : G1 = msmG1( prf.publicIO , vkey.vpoints.pointsIC )

View File

@ -0,0 +1,60 @@
{.used.}
import std/unittest
import constantine/math/io/io_bigints
import constantine/math/arithmetic
import constantine/math/io/io_fields
import constantine/named/properties_fields
import constantine/math/extension_fields/towers
import groth16/bn128/fields
import groth16/bn128/curves
#-------------------------------------------------------------------------------
#
# the point (computed via Sage)
#
# pt2 = (2 : 2237046587054574173616397632856518880513033439888792180868262182050662989363*u + 10894412225134874879786325788974416805327887441035008073952212076423500941133 : 1)
#
# should be on the curve but not in the subgroup
#
const pt2_x1 = fromHex(Fp[BN254_Snarks], "0x2")
const pt2_xu = fromHex(Fp[BN254_Snarks], "0x0")
const pt2_y1 = fromHex(Fp[BN254_Snarks], "0x181604d0560080401c08b557815482553e278257d98100d193a011c42782474d")
const pt2_yu = fromHex(Fp[BN254_Snarks], "0x04f21f9d99cc25f694cf22ff70dc0ac4692e7a721b725dc454a217f04bd03e33")
const pt2_x = mkFp2( pt2_x1, pt2_xu )
const pt2_y = mkFp2( pt2_y1, pt2_yu )
suite "curves":
test "gen1 is on the curve":
check checkCurveEqG1(gen1.x,gen1.y)
test "gen1 is in the subgroup G1":
check checkSubgroupG1(gen1.x,gen1.y)
test "gen2 is on the curve over Fp2":
check checkCurveEqG2(gen2.x,gen2.y)
test "gen2 is in the subgroup G2":
check checkSubgroupG2(gen2.x,gen2.y)
let prime254 : BigInt[254] = fromHex( BigInt[254], "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", bigEndian )
test "order of gen1 equals to R":
check ( (not bool(isInfG1(gen1))) and bool(isInfG1(prime254 ** gen1)) )
test "order of gen2 equals to R":
check ( (not bool(isInfG2(gen2))) and bool(isInfG2(prime254 ** gen2)) )
test "pt2 is on the curve over Fp2":
check checkCurveEqG2(pt2_x, pt2_y)
test "pt2 is NOT in the subgroup G2":
check (not checkSubgroupG2(pt2_x, pt2_y))
#-------------------------------------------------------------------------------

View File

@ -1,4 +1,6 @@
{.used.}
import std/unittest
import std/sequtils

View File

@ -1,3 +1,4 @@
import ./groth16/testCurve
import ./groth16/testProver