Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Feature: compute the fingerprint of a Plonk verification key for recursive verification #1062

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
840a867
added circuit implementation of ExpandMsgXmd
weijiguo Jan 8, 2024
7fb1b95
implemented HashToG2 for bls12-381
weijiguo Jan 27, 2024
620585f
Merge branch 'Consensys:master' into feat/Hash2G2
weijiguo Jan 27, 2024
b0b11d2
revised G2.addUnified function based on the Brier and Joye algorithm
weijiguo Jan 28, 2024
3cf48fd
Merge pull request #2 from lightec-xyz/feat/Hash2G2
weijiguo Jan 28, 2024
b4da768
fixed G2.sgn0 function and associated unit tests for BLS12-381
weijiguo Jan 29, 2024
b6574fc
Merge pull request #4 from lightec-xyz/feat/Hash2G2
weijiguo Jan 29, 2024
86d12ce
implemented BLS signature verification for BLS12-381/G2
weijiguo Jan 29, 2024
78bdcf6
added benchmarks for HashToG2/BLS12-381
weijiguo Jan 30, 2024
04c1677
Merge branch 'master' into feat/BLSSigAndHashToG2
weijiguo Feb 10, 2024
8e2fc0e
gofmt
weijiguo Feb 10, 2024
bae5ff4
Merge branch 'master' into feat/BLSSigAndHashToG2
weijiguo Feb 14, 2024
9afd6f2
vkey fingerprint
weijiguo Feb 15, 2024
57759d6
Merge branch 'feat/BLSSigAndHashToG2' into feat/vkey_fp
weijiguo Feb 19, 2024
be6e233
veky fingerprint -- furhter tests
weijiguo Feb 19, 2024
4a2f9b0
golangci-lint
weijiguo Feb 19, 2024
26c53df
Merge branch 'feat/BLSSigAndHashToG2' into feat/vkey_fp
weijiguo Feb 19, 2024
de5536a
golangci-lint
weijiguo Feb 19, 2024
4f3ae1d
typo
weijiguo Feb 19, 2024
b954b35
Merge branch 'master' into feat/vkey_fp
weijiguo Feb 20, 2024
ab22e33
Merge branch 'master' into feat/vkey_fp
weijiguo Feb 23, 2024
9480d57
added type conversion from frontend.Variable to []U8
weijiguo Feb 29, 2024
982d654
fixed array out of bound issue
weijiguo Feb 29, 2024
8125613
modify ByteArrayValueOf implementation and add testcase
readygo67 Mar 1, 2024
0c21435
Merge branch 'master' into feat/vkey_fp
weijiguo Mar 10, 2024
7802205
Merge branch 'master' into feat/vkey_fp
weijiguo Mar 12, 2024
ebea47c
Merge branch 'master' into feat/vkey_fp
weijiguo Mar 14, 2024
a200efa
reactivated Field.Cmp
weijiguo Mar 14, 2024
46e5ac6
Merge branch 'master' into feat/vkey_fp
weijiguo Mar 24, 2024
83cddfc
Merge branch 'master' into feat/vkey_fp
weijiguo May 4, 2024
3a82ad5
Merge branch 'master' into feat/vkey_fp
weijiguo May 20, 2024
4ee8d3d
Merge branch 'master' into feat/vkey_fp
weijiguo Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions std/algebra/emulated/sw_bls12381/bls_sig.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package sw_bls12381

import (
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/uints"
)

const g2_dst = "BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_"

func BlsAssertG2Verification(api frontend.API, pub G1Affine, sig G2Affine, msg []uints.U8) error {
pairing, e := NewPairing(api)
if e != nil {
return e
}

// public key cannot be infinity
xtest := pairing.g1.curveF.IsZero(&pub.X)
ytest := pairing.g1.curveF.IsZero(&pub.Y)
pubTest := api.Or(xtest, ytest)
api.AssertIsEqual(pubTest, 0)

// prime order subgroup checks
pairing.AssertIsOnG1(&pub)
pairing.AssertIsOnG2(&sig)

var g1GNeg bls12381.G1Affine
_, _, g1Gen, _ := bls12381.Generators()
g1GNeg.Neg(&g1Gen)
g1GN := NewG1Affine(g1GNeg)

h, e := HashToG2(api, msg, []byte(g2_dst))
if e != nil {
return e
}

return pairing.PairingCheck([]*G1Affine{&g1GN, &pub}, []*G2Affine{&sig, h})
}
83 changes: 83 additions & 0 deletions std/algebra/emulated/sw_bls12381/bls_sig_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package sw_bls12381

import (
"encoding/hex"
"testing"

"github.com/consensys/gnark-crypto/ecc"
bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/uints"
"github.com/consensys/gnark/test"
)

type blsG2SigCircuit struct {
Pub bls12381.G1Affine
msg []byte
Sig bls12381.G2Affine
}

func (c *blsG2SigCircuit) Define(api frontend.API) error {
msg := uints.NewU8Array(c.msg)
return BlsAssertG2Verification(api, NewG1Affine(c.Pub), NewG2Affine(c.Sig), msg)
}

// "pubkey": "0xa491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a",
// "message": "0x5656565656565656565656565656565656565656565656565656565656565656",
// "signature": "0x882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972503a43eb"},
// "output": true}
func TestBlsSigTestSolve(t *testing.T) {
assert := test.NewAssert(t)

msgHex := "5656565656565656565656565656565656565656565656565656565656565656"
pubHex := "a491d1b0ecd9bb917989f0e74f0dea0422eac4a873e5e2644f368dffb9a6e20fd6e10c1b77654d067c0618f6e5a7f79a"
sigHex := "882730e5d03f6b42c3abc26d3372625034e1d871b65a8a6b900a56dae22da98abbe1b68f85e49fe7652a55ec3d0591c20767677e33e5cbb1207315c41a9ac03be39c2e7668edc043d6cb1d9fd93033caa8a1c5b0e84bedaeb6c64972503a43eb"

msgBytes := make([]byte, len(msgHex)>>1)
hex.Decode(msgBytes, []byte(msgHex))
pubBytes := make([]byte, len(pubHex)>>1)
hex.Decode(pubBytes, []byte(pubHex))
sigBytes := make([]byte, len(sigHex)>>1)
hex.Decode(sigBytes, []byte(sigHex))

var pub bls12381.G1Affine
_, e := pub.SetBytes(pubBytes)
if e != nil {
t.Fail()
}
var sig bls12381.G2Affine
_, e = sig.SetBytes(sigBytes)
if e != nil {
t.Fail()
}

var g1GNeg bls12381.G1Affine
_, _, g1Gen, _ := bls12381.Generators()
g1GNeg.Neg(&g1Gen)

h, e := bls12381.HashToG2(msgBytes, []byte(g2_dst))
if e != nil {
t.Fail()
}

b, e := bls12381.PairingCheck([]bls12381.G1Affine{g1GNeg, pub}, []bls12381.G2Affine{sig, h})
if e != nil {
t.Fail()
}
if !b {
t.Fail() // invalid inputs, won't verify
}

circuit := blsG2SigCircuit{
Pub: pub,
msg: msgBytes,
Sig: sig,
}
witness := blsG2SigCircuit{
Pub: pub,
msg: msgBytes,
Sig: sig,
}
err := test.IsSolved(&circuit, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}
68 changes: 68 additions & 0 deletions std/algebra/emulated/sw_bls12381/g2.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type G2 struct {
*fields_bls12381.Ext2
u1, w *emulated.Element[BaseField]
v *fields_bls12381.E2
api frontend.API
}

type g2AffP struct {
Expand Down Expand Up @@ -50,6 +51,7 @@ func NewG2(api frontend.API) *G2 {
w: &w,
u1: &u1,
v: &v,
api: api,
}
}

Expand Down Expand Up @@ -96,6 +98,18 @@ func (g2 *G2) psi(q *G2Affine) *G2Affine {
}
}

func (g2 *G2) psi2(q *G2Affine) *G2Affine {
x := g2.Ext2.MulByElement(&q.P.X, g2.w)
y := g2.Ext2.Neg(&q.P.Y)

return &G2Affine{
P: g2AffP{
X: *x,
Y: *y,
},
}
}

func (g2 *G2) scalarMulBySeed(q *G2Affine) *G2Affine {

z := g2.triple(q)
Expand Down Expand Up @@ -136,6 +150,60 @@ func (g2 G2) add(p, q *G2Affine) *G2Affine {
}
}

// Follow sw_emulated.Curve.AddUnified to implement the Brier and Joye algorithm
// to handle edge cases, i.e., p == q, p == 0 or/and q == 0
func (g2 G2) addUnified(p, q *G2Affine) *G2Affine {

// selector1 = 1 when p is (0,0) and 0 otherwise
selector1 := g2.api.And(g2.Ext2.IsZero(&p.P.X), g2.Ext2.IsZero(&p.P.Y))
// selector2 = 1 when q is (0,0) and 0 otherwise
selector2 := g2.api.And(g2.Ext2.IsZero(&q.P.X), g2.Ext2.IsZero(&q.P.Y))

// λ = ((p.x+q.x)² - p.x*q.x + a)/(p.y + q.y)
pxqx := g2.Ext2.Mul(&p.P.X, &q.P.X)
pxplusqx := g2.Ext2.Add(&p.P.X, &q.P.X)
num := g2.Ext2.Mul(pxplusqx, pxplusqx)
num = g2.Ext2.Sub(num, pxqx)
denum := g2.Ext2.Add(&p.P.Y, &q.P.Y)
// if p.y + q.y = 0, assign dummy 1 to denum and continue
selector3 := g2.Ext2.IsZero(denum)
denum = g2.Ext2.Select(selector3, g2.Ext2.One(), denum)
λ := g2.Ext2.DivUnchecked(num, denum) // we already know that denum won't be zero

// x = λ^2 - p.x - q.x
xr := g2.Ext2.Mul(λ, λ)
xr = g2.Ext2.Sub(xr, pxplusqx)

// y = λ(p.x - xr) - p.y
yr := g2.Ext2.Sub(&p.P.X, xr)
yr = g2.Ext2.Mul(yr, λ)
yr = g2.Ext2.Sub(yr, &p.P.Y)
result := &G2Affine{
P: g2AffP{
X: *xr,
Y: *yr,
},
}

zero := g2.Ext2.Zero()
// if p=(0,0) return q
resultX := *g2.Select(selector1, &q.P.X, &result.P.X)
resultY := *g2.Select(selector1, &q.P.Y, &result.P.Y)
// if q=(0,0) return p
resultX = *g2.Select(selector2, &p.P.X, &resultX)
resultY = *g2.Select(selector2, &p.P.Y, &resultY)
// if p.y + q.y = 0, return (0, 0)
resultX = *g2.Select(selector3, zero, &resultX)
resultY = *g2.Select(selector3, zero, &resultY)

return &G2Affine{
P: g2AffP{
X: resultX,
Y: resultY,
},
}
}

func (g2 G2) neg(p *G2Affine) *G2Affine {
xr := &p.P.X
yr := g2.Ext2.Neg(&p.P.Y)
Expand Down
110 changes: 110 additions & 0 deletions std/algebra/emulated/sw_bls12381/g2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,116 @@ func TestAddG2TestSolve(t *testing.T) {
assert.NoError(err)
}

func TestAddG2FailureCaseTestSolve(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines()
var res bls12381.G2Affine
res.Double(&in1)
witness := addG2Circuit{
In1: NewG2Affine(in1),
In2: NewG2Affine(in1),
Res: NewG2Affine(res),
}
err := test.IsSolved(&addG2Circuit{}, &witness, ecc.BN254.ScalarField())
// the add() function cannot handle identical inputs
assert.Error(err)
}

type addG2UnifiedCircuit struct {
In1, In2 G2Affine
Res G2Affine
}

func (c *addG2UnifiedCircuit) Define(api frontend.API) error {
g2 := NewG2(api)
res := g2.addUnified(&c.In1, &c.In2)
g2.AssertIsEqual(res, &c.Res)
return nil
}

func TestAddG2UnifiedTestSolveAdd(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines()
_, in2 := randomG1G2Affines()
var res bls12381.G2Affine
res.Add(&in1, &in2)
witness := addG2UnifiedCircuit{
In1: NewG2Affine(in1),
In2: NewG2Affine(in2),
Res: NewG2Affine(res),
}
err := test.IsSolved(&addG2UnifiedCircuit{}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

func TestAddG2UnifiedTestSolveDbl(t *testing.T) {
assert := test.NewAssert(t)
_, in1 := randomG1G2Affines()
var res bls12381.G2Affine
res.Double(&in1)
witness := addG2UnifiedCircuit{
In1: NewG2Affine(in1),
In2: NewG2Affine(in1),
Res: NewG2Affine(res),
}
err := test.IsSolved(&addG2UnifiedCircuit{}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)
}

func TestAddG2UnifiedTestSolveEdgeCases(t *testing.T) {
assert := test.NewAssert(t)
_, p := randomG1G2Affines()
var np, zero bls12381.G2Affine
np.Neg(&p)
zero.Sub(&p, &p)

// p + (-p) == (0, 0)
witness := addG2UnifiedCircuit{
In1: NewG2Affine(p),
In2: NewG2Affine(np),
Res: NewG2Affine(zero),
}
err := test.IsSolved(&addG2UnifiedCircuit{}, &witness, ecc.BN254.ScalarField())
assert.NoError(err)

// (-p) + p == (0, 0)
witness2 := addG2UnifiedCircuit{
In1: NewG2Affine(np),
In2: NewG2Affine(p),
Res: NewG2Affine(zero),
}
err2 := test.IsSolved(&addG2UnifiedCircuit{}, &witness2, ecc.BN254.ScalarField())
assert.NoError(err2)

// p + (0, 0) == p
witness3 := addG2UnifiedCircuit{
In1: NewG2Affine(p),
In2: NewG2Affine(zero),
Res: NewG2Affine(p),
}
err3 := test.IsSolved(&addG2UnifiedCircuit{}, &witness3, ecc.BN254.ScalarField())
assert.NoError(err3)

// (0, 0) + p == p
witness4 := addG2UnifiedCircuit{
In1: NewG2Affine(zero),
In2: NewG2Affine(p),
Res: NewG2Affine(p),
}
err4 := test.IsSolved(&addG2UnifiedCircuit{}, &witness4, ecc.BN254.ScalarField())
assert.NoError(err4)

// (0, 0) + (0, 0) == (0, 0)
witness5 := addG2UnifiedCircuit{
In1: NewG2Affine(zero),
In2: NewG2Affine(zero),
Res: NewG2Affine(zero),
}
err5 := test.IsSolved(&addG2UnifiedCircuit{}, &witness5, ecc.BN254.ScalarField())
assert.NoError(err5)

}

type doubleG2Circuit struct {
In1 G2Affine
Res G2Affine
Expand Down
Loading