Skip to content

Commit

Permalink
feat: add fixed Groth16 verification
Browse files Browse the repository at this point in the history
  • Loading branch information
ivokub committed Nov 22, 2023
1 parent 5a92eb0 commit a413c27
Show file tree
Hide file tree
Showing 2 changed files with 265 additions and 0 deletions.
173 changes: 173 additions & 0 deletions std/recursion/groth16/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,20 @@ import (
fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr"
"github.com/consensys/gnark-crypto/ecc/bn254"
fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761"
fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr"
"github.com/consensys/gnark/backend/groth16"
groth16backend_bls12377 "github.com/consensys/gnark/backend/groth16/bls12-377"
groth16backend_bls12381 "github.com/consensys/gnark/backend/groth16/bls12-381"
groth16backend_bls24315 "github.com/consensys/gnark/backend/groth16/bls24-315"
groth16backend_bn254 "github.com/consensys/gnark/backend/groth16/bn254"
groth16backend_bw6761 "github.com/consensys/gnark/backend/groth16/bw6-761"
"github.com/consensys/gnark/backend/witness"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/std/algebra"
"github.com/consensys/gnark/std/algebra/emulated/sw_bls12381"
"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
"github.com/consensys/gnark/std/algebra/emulated/sw_bw6761"
"github.com/consensys/gnark/std/algebra/native/sw_bls12377"
"github.com/consensys/gnark/std/algebra/native/sw_bls24315"
"github.com/consensys/gnark/std/math/emulated"
Expand Down Expand Up @@ -72,6 +76,14 @@ func ValueOfProof[G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof groth1
ar.Ar = sw_bls24315.NewG1Affine(tProof.Ar)
ar.Krs = sw_bls24315.NewG1Affine(tProof.Krs)
ar.Bs = sw_bls24315.NewG2Affine(tProof.Bs)
case *Proof[sw_bw6761.G1Affine, sw_bw6761.G2Affine]:
tProof, ok := proof.(*groth16backend_bw6761.Proof)
if !ok {
return ret, fmt.Errorf("expected bls24315.Proof, got %T", proof)
}
ar.Ar = sw_bw6761.NewG1Affine(tProof.Ar)
ar.Krs = sw_bw6761.NewG1Affine(tProof.Krs)
ar.Bs = sw_bw6761.NewG2Affine(tProof.Bs)
default:
return ret, fmt.Errorf("unknown parametric type combination")
}
Expand Down Expand Up @@ -99,6 +111,27 @@ func PlaceholderVerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT, G
}
}

func PlaceholderVerifyingKeyFixed[G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT](ccs constraint.ConstraintSystem) VerifyingKey[G1El, G2El, GtEl] {
vk := VerifyingKey[G1El, G2El, GtEl]{
G1: struct{ K []G1El }{
K: make([]G1El, ccs.GetNbPublicVariables()),
},
}
switch s := any(&vk).(type) {
case *VerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]:
s.G2 = struct {
GammaNeg sw_bw6761.G2Affine
DeltaNeg sw_bw6761.G2Affine
}{
GammaNeg: sw_bw6761.NewG2AffineFixedPlaceholder(),
DeltaNeg: sw_bw6761.NewG2AffineFixedPlaceholder(),
}
default:
panic("precomputation not supported")
}
return vk
}

// ValueOfVerifyingKey initializes witness from the given Groth16 verifying key.
// It returns an error if there is a mismatch between the type parameters and
// the provided native verifying key.
Expand Down Expand Up @@ -185,6 +218,138 @@ func ValueOfVerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl
gammaNeg.Neg(&tVk.G2.Gamma)
s.G2.DeltaNeg = sw_bls24315.NewG2Affine(deltaNeg)
s.G2.GammaNeg = sw_bls24315.NewG2Affine(gammaNeg)
case *VerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]:
tVk, ok := vk.(*groth16backend_bw6761.VerifyingKey)
if !ok {
return ret, fmt.Errorf("expected bw6761.VerifyingKey, got %T", vk)
}
// compute E
e, err := bw6761.Pair([]bw6761.G1Affine{tVk.G1.Alpha}, []bw6761.G2Affine{tVk.G2.Beta})
if err != nil {
return ret, fmt.Errorf("precompute pairing: %w", err)
}
s.E = sw_bw6761.NewGTEl(e)
s.G1.K = make([]sw_bw6761.G1Affine, len(tVk.G1.K))
for i := range s.G1.K {
s.G1.K[i] = sw_bw6761.NewG1Affine(tVk.G1.K[i])
}
var deltaNeg, gammaNeg bw6761.G2Affine
deltaNeg.Neg(&tVk.G2.Delta)
gammaNeg.Neg(&tVk.G2.Gamma)
s.G2.DeltaNeg = sw_bw6761.NewG2Affine(deltaNeg)
s.G2.GammaNeg = sw_bw6761.NewG2Affine(gammaNeg)
default:
return ret, fmt.Errorf("unknown parametric type combination")
}
return ret, nil
}

// ValueOfVerifyingKey initializes witness from the given Groth16 verifying key.
// It returns an error if there is a mismatch between the type parameters and
// the provided native verifying key.
func ValueOfVerifyingKeyFixed[G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT](vk groth16.VerifyingKey) (VerifyingKey[G1El, G2El, GtEl], error) {
var ret VerifyingKey[G1El, G2El, GtEl]
switch s := any(&ret).(type) {
// case *VerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]:
// tVk, ok := vk.(*groth16backend_bn254.VerifyingKey)
// if !ok {
// return ret, fmt.Errorf("expected bn254.VerifyingKey, got %T", vk)
// }
// // compute E
// e, err := bn254.Pair([]bn254.G1Affine{tVk.G1.Alpha}, []bn254.G2Affine{tVk.G2.Beta})
// if err != nil {
// return ret, fmt.Errorf("precompute pairing: %w", err)
// }
// s.E = sw_bn254.NewGTEl(e)
// s.G1.K = make([]sw_bn254.G1Affine, len(tVk.G1.K))
// for i := range s.G1.K {
// s.G1.K[i] = sw_bn254.NewG1Affine(tVk.G1.K[i])
// }
// var deltaNeg, gammaNeg bn254.G2Affine
// deltaNeg.Neg(&tVk.G2.Delta)
// gammaNeg.Neg(&tVk.G2.Gamma)
// s.G2.DeltaNeg = sw_bn254.NewG2Affine(deltaNeg)
// s.G2.GammaNeg = sw_bn254.NewG2Affine(gammaNeg)
// case *VerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]:
// tVk, ok := vk.(*groth16backend_bls12377.VerifyingKey)
// if !ok {
// return ret, fmt.Errorf("expected bn254.VerifyingKey, got %T", vk)
// }
// // compute E
// e, err := bls12377.Pair([]bls12377.G1Affine{tVk.G1.Alpha}, []bls12377.G2Affine{tVk.G2.Beta})
// if err != nil {
// return ret, fmt.Errorf("precompute pairing: %w", err)
// }
// s.E = sw_bls12377.NewGTEl(e)
// s.G1.K = make([]sw_bls12377.G1Affine, len(tVk.G1.K))
// for i := range s.G1.K {
// s.G1.K[i] = sw_bls12377.NewG1Affine(tVk.G1.K[i])
// }
// var deltaNeg, gammaNeg bls12377.G2Affine
// deltaNeg.Neg(&tVk.G2.Delta)
// gammaNeg.Neg(&tVk.G2.Gamma)
// s.G2.DeltaNeg = sw_bls12377.NewG2Affine(deltaNeg)
// s.G2.GammaNeg = sw_bls12377.NewG2Affine(gammaNeg)
// case *VerifyingKey[sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl]:
// tVk, ok := vk.(*groth16backend_bls12381.VerifyingKey)
// if !ok {
// return ret, fmt.Errorf("expected bls12381.VerifyingKey, got %T", vk)
// }
// // compute E
// e, err := bls12381.Pair([]bls12381.G1Affine{tVk.G1.Alpha}, []bls12381.G2Affine{tVk.G2.Beta})
// if err != nil {
// return ret, fmt.Errorf("precompute pairing: %w", err)
// }
// s.E = sw_bls12381.NewGTEl(e)
// s.G1.K = make([]sw_bls12381.G1Affine, len(tVk.G1.K))
// for i := range s.G1.K {
// s.G1.K[i] = sw_bls12381.NewG1Affine(tVk.G1.K[i])
// }
// var deltaNeg, gammaNeg bls12381.G2Affine
// deltaNeg.Neg(&tVk.G2.Delta)
// gammaNeg.Neg(&tVk.G2.Gamma)
// s.G2.DeltaNeg = sw_bls12381.NewG2Affine(deltaNeg)
// s.G2.GammaNeg = sw_bls12381.NewG2Affine(gammaNeg)
// case *VerifyingKey[sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT]:
// tVk, ok := vk.(*groth16backend_bls24315.VerifyingKey)
// if !ok {
// return ret, fmt.Errorf("expected bls12381.VerifyingKey, got %T", vk)
// }
// // compute E
// e, err := bls24315.Pair([]bls24315.G1Affine{tVk.G1.Alpha}, []bls24315.G2Affine{tVk.G2.Beta})
// if err != nil {
// return ret, fmt.Errorf("precompute pairing: %w", err)
// }
// s.E = sw_bls24315.NewGTEl(e)
// s.G1.K = make([]sw_bls24315.G1Affine, len(tVk.G1.K))
// for i := range s.G1.K {
// s.G1.K[i] = sw_bls24315.NewG1Affine(tVk.G1.K[i])
// }
// var deltaNeg, gammaNeg bls24315.G2Affine
// deltaNeg.Neg(&tVk.G2.Delta)
// gammaNeg.Neg(&tVk.G2.Gamma)
// s.G2.DeltaNeg = sw_bls24315.NewG2Affine(deltaNeg)
// s.G2.GammaNeg = sw_bls24315.NewG2Affine(gammaNeg)
case *VerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]:
tVk, ok := vk.(*groth16backend_bw6761.VerifyingKey)
if !ok {
return ret, fmt.Errorf("expected bw6761.VerifyingKey, got %T", vk)
}
// compute E
e, err := bw6761.Pair([]bw6761.G1Affine{tVk.G1.Alpha}, []bw6761.G2Affine{tVk.G2.Beta})
if err != nil {
return ret, fmt.Errorf("precompute pairing: %w", err)
}
s.E = sw_bw6761.NewGTEl(e)
s.G1.K = make([]sw_bw6761.G1Affine, len(tVk.G1.K))
for i := range s.G1.K {
s.G1.K[i] = sw_bw6761.NewG1Affine(tVk.G1.K[i])
}
var deltaNeg, gammaNeg bw6761.G2Affine
deltaNeg.Neg(&tVk.G2.Delta)
gammaNeg.Neg(&tVk.G2.Gamma)
s.G2.DeltaNeg = sw_bw6761.NewG2AffineFixed(deltaNeg)
s.G2.GammaNeg = sw_bw6761.NewG2AffineFixed(gammaNeg)
default:
return ret, fmt.Errorf("unknown parametric type combination")
}
Expand Down Expand Up @@ -253,6 +418,14 @@ func ValueOfWitness[FR emulated.FieldParams](w witness.Witness) (Witness[FR], er
for i := range vect {
s.Public = append(s.Public, sw_bls24315.NewScalar(vect[i]))
}
case *Witness[sw_bw6761.ScalarField]:
vect, ok := vec.(fr_bw6761.Vector)
if !ok {
return ret, fmt.Errorf("expected fr_bls24315.Vector, got %T", vec)
}
for i := range vect {
s.Public = append(s.Public, sw_bw6761.NewScalar(vect[i]))
}
default:
return ret, fmt.Errorf("unknown parametric type combination")
}
Expand Down
92 changes: 92 additions & 0 deletions std/recursion/groth16/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/consensys/gnark/std/algebra"
"github.com/consensys/gnark/std/algebra/emulated/sw_bls12381"
"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
"github.com/consensys/gnark/std/algebra/emulated/sw_bw6761"
"github.com/consensys/gnark/std/algebra/native/sw_bls12377"
"github.com/consensys/gnark/std/algebra/native/sw_bls24315"
"github.com/consensys/gnark/std/hash/sha2"
Expand Down Expand Up @@ -302,3 +303,94 @@ func TestValueOfVerifyingKey(t *testing.T) {
_ = vvk
}, "bls24315")
}

func TestBW6InBN254(t *testing.T) {
assert := test.NewAssert(t)
innerCcs, innerVK, innerWitness, innerProof := getInner(assert, ecc.BW6_761.ScalarField())

// outer proof
circuitVk, err := ValueOfVerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerVK)
assert.NoError(err)
circuitWitness, err := ValueOfWitness[sw_bw6761.ScalarField](innerWitness)
assert.NoError(err)
circuitProof, err := ValueOfProof[sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof)
assert.NoError(err)

outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{
InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs),
VerifyingKey: PlaceholderVerifyingKey[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerCcs),
}
outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{
InnerWitness: circuitWitness,
Proof: circuitProof,
VerifyingKey: circuitVk,
}
assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BN254))
}

func TestBW6InBN254Precomputed(t *testing.T) {
assert := test.NewAssert(t)
innerCcs, innerVK, innerWitness, innerProof := getInner(assert, ecc.BW6_761.ScalarField())

// outer proof
circuitVk, err := ValueOfVerifyingKeyFixed[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerVK)
assert.NoError(err)
circuitWitness, err := ValueOfWitness[sw_bw6761.ScalarField](innerWitness)
assert.NoError(err)
circuitProof, err := ValueOfProof[sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof)
assert.NoError(err)

outerCircuit := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{
InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs),
VerifyingKey: PlaceholderVerifyingKeyFixed[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerCcs),
}
outerAssignment := &OuterCircuit[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{
InnerWitness: circuitWitness,
Proof: circuitProof,
VerifyingKey: circuitVk,
}
assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BN254))
}

type OuterCircuitConstant[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT] struct {
Proof Proof[G1El, G2El]
vk VerifyingKey[G1El, G2El, GtEl] `gnark:"-"`
InnerWitness Witness[FR]
}

func (c *OuterCircuitConstant[FR, G1El, G2El, GtEl]) Define(api frontend.API) error {
curve, err := algebra.GetCurve[FR, G1El](api)
if err != nil {
return fmt.Errorf("new curve: %w", err)
}
pairing, err := algebra.GetPairing[G1El, G2El, GtEl](api)
if err != nil {
return fmt.Errorf("get pairing: %w", err)
}
verifier := NewVerifier(curve, pairing)
err = verifier.AssertProof(c.vk, c.Proof, c.InnerWitness)
return err
}

func TestBW6InBN254Constant(t *testing.T) {
assert := test.NewAssert(t)
innerCcs, innerVK, innerWitness, innerProof := getInner(assert, ecc.BW6_761.ScalarField())

// outer proof
circuitVk, err := ValueOfVerifyingKeyFixed[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl](innerVK)
assert.NoError(err)
circuitWitness, err := ValueOfWitness[sw_bw6761.ScalarField](innerWitness)
assert.NoError(err)
circuitProof, err := ValueOfProof[sw_bw6761.G1Affine, sw_bw6761.G2Affine](innerProof)
assert.NoError(err)

outerCircuit := &OuterCircuitConstant[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{
InnerWitness: PlaceholderWitness[sw_bw6761.ScalarField](innerCcs),
vk: circuitVk,
}
outerAssignment := &OuterCircuitConstant[sw_bw6761.ScalarField, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl]{
InnerWitness: circuitWitness,
Proof: circuitProof,
}
assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BN254))
}

0 comments on commit a413c27

Please sign in to comment.