Skip to content

Commit

Permalink
WIP plonk verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
ivokub committed Oct 25, 2023
1 parent 9946a2f commit 7dba1bd
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 31 deletions.
11 changes: 0 additions & 11 deletions std/recursion/plonk/temp.go

This file was deleted.

205 changes: 187 additions & 18 deletions std/recursion/plonk/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,30 @@ package plonk
import (
"fmt"

fr_bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
fr_bls12381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
fr_bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315/fr"
fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
backend_plonk "github.com/consensys/gnark/backend/plonk"
plonkbackend_bls12377 "github.com/consensys/gnark/backend/plonk/bls12-377"
"github.com/consensys/gnark/backend/witness"
"github.com/consensys/gnark/constraint"
"github.com/consensys/gnark/frontend"
"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/native/sw_bls12377"
"github.com/consensys/gnark/std/algebra/native/sw_bls24315"
"github.com/consensys/gnark/std/commitments/kzg"
fiatshamir "github.com/consensys/gnark/std/fiat-shamir"
"github.com/consensys/gnark/std/hash"
"github.com/consensys/gnark/std/math/emulated"
"github.com/consensys/gnark/std/math/emulated/emparams"
)

type Proof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct {
// Commitments to the solution vectors
L, R, O kzg.Commitment[G1El]
LRO [3]kzg.Commitment[G1El]
// Commitment to Z, the permutation polynomial
Z kzg.Commitment[G1El]
// Commitments to h1, h2, h3 such that h = h1 + Xh2 + X**2h3 is the quotient polynomial
Expand All @@ -24,17 +35,68 @@ type Proof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT]
Bsb22Commitments []kzg.Commitment[G1El]

// Batch opening proof of h1 + zeta*h2 + zeta**2h3, linearizedPolynomial, l, r, o, s1, s2, qCPrime
BatchedProof []kzg.OpeningProof[S, G1El] // actually batch opening proof
BatchedProof kzg.BatchOpeningProof[S, G1El]

// Opening proof of Z at zeta*mu
ZShiftedOpening kzg.OpeningProof[S, G1El]
}

func ValueOfProof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](proof backend_plonk.Proof) (Proof[S, G1El, G2El], error) {
var ret Proof[S, G1El, G2El]
var err error
switch r := any(&ret).(type) {
case *Proof[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine]:
tProof, ok := proof.(*plonkbackend_bls12377.Proof)
if !ok {
return ret, fmt.Errorf("expected sw_bls12377.Proof, got %T", proof)
}
for i := range r.LRO {
r.LRO[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.LRO[i])
if err != nil {
return ret, fmt.Errorf("commitment LRO[%d] value assignment: %w", i, err)
}
}
r.Z, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.Z)
if err != nil {
return ret, fmt.Errorf("commitment Z value assignment: %w", err)
}
for i := range r.H {
r.H[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.H[i])
if err != nil {
return ret, fmt.Errorf("commitment H[%d] value assignment: %w", i, err)
}
}
r.Bsb22Commitments = make([]kzg.Commitment[sw_bls12377.G1Affine], len(tProof.Bsb22Commitments))
for i := range r.Bsb22Commitments {
r.Bsb22Commitments[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tProof.Bsb22Commitments[i])
if err != nil {
return ret, fmt.Errorf("bsb22 commitment %d value assignment: %w", i, err)
}
}
// TODO: actually we compute the opening point later. Maybe we can precompute it here and later assert its correctness?
r.BatchedProof, err = kzg.ValueOfBatchOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine]([]fr_bls12377.Element{}, tProof.BatchedProof)
if err != nil {
return ret, fmt.Errorf("batch opening proof value assignment: %w", err)
}
r.ZShiftedOpening, err = kzg.ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](fr_bls12377.One(), tProof.ZShiftedOpening)
if err != nil {
return ret, fmt.Errorf("z shifted opening proof value assignment: %w", err)
}
default:
return ret, fmt.Errorf("unknown parametric type combination")
}
return ret, nil
}

func PlaceholderProof[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) Proof[S, G1El, G2El] {
return Proof[S, G1El, G2El]{
BatchedProof: kzg.BatchOpeningProof[S, G1El]{
ClaimedValues: make([]S, 7),
Points: []S{},
},
}
}

type VerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct {
// Size circuit
Size S
Expand All @@ -61,11 +123,68 @@ type VerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele
}

func ValueOfVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk backend_plonk.VerifyingKey) (VerifyingKey[S, G1El, G2El], error) {
panic("TODO")
var ret VerifyingKey[S, G1El, G2El]
var err error
switch r := any(&ret).(type) {
case *VerifyingKey[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine]:
tVk, ok := vk.(*plonkbackend_bls12377.VerifyingKey)
if !ok {
return ret, fmt.Errorf("expected bls12377.VerifyingKey, got %T", vk)
}
r.Size = tVk.Size
r.SizeInv = sw_bls12377.NewScalar(tVk.SizeInv)
r.Generator = sw_bls12377.NewScalar(tVk.Generator)
r.NbPublicVariables = tVk.NbPublicVariables
r.Kzg, err = kzg.ValueOfVerifyingKey[sw_bls12377.G2Affine](tVk.Kzg)
if err != nil {
return ret, fmt.Errorf("verifying key witness assignment: %w", err)
}
r.CosetShift = sw_bls12377.NewScalar(tVk.CosetShift)
for i := range r.S {
r.S[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.S[i])
if err != nil {
return ret, fmt.Errorf("commitment S[%d] witness assignment: %w", i, err)
}
}
r.Ql, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Ql)
if err != nil {
return ret, fmt.Errorf("commitment Ql witness assignment: %w", err)
}
r.Qr, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qr)
if err != nil {
return ret, fmt.Errorf("commitment Qr witness assignment: %w", err)
}
r.Qm, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qm)
if err != nil {
return ret, fmt.Errorf("commitment Qm witness assignment: %w", err)
}
r.Qo, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qo)
if err != nil {
return ret, fmt.Errorf("commitment Qo witness assignment: %w", err)
}
r.Qk, err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qk)
if err != nil {
return ret, fmt.Errorf("commitment Qk witness assignment: %w", err)
}
r.Qcp = make([]kzg.Commitment[sw_bls12377.G1Affine], len(tVk.Qcp))
for i := range r.Qcp {
r.Qcp[i], err = kzg.ValueOfCommitment[sw_bls12377.G1Affine](tVk.Qcp[i])
if err != nil {
return ret, fmt.Errorf("commitment Qcp[%d] witness assignment: %w", i, err)
}
}
r.CommitmentConstraintIndexes = make([]uint64, len(tVk.CommitmentConstraintIndexes))
copy(r.CommitmentConstraintIndexes, tVk.CommitmentConstraintIndexes)
default:
return ret, fmt.Errorf("unknown parametric type combination")
}
return ret, nil
}

func PlaceholderVerifyingKey[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT](ccs constraint.ConstraintSystem) VerifyingKey[S, G1El, G2El] {
panic("TODO")
// TODO: we're not considering the commitments right now
var ret VerifyingKey[S, G1El, G2El]
return ret
}

// Witness is a public witness to verify the SNARK proof against. For assigning
Expand All @@ -78,15 +197,60 @@ type Witness[S algebra.ScalarT] struct {
}

func ValueOfWitness[S algebra.ScalarT, G1 algebra.G1ElementT](w witness.Witness) (Witness[S], error) {
panic("TODO")
type dbwtiness[S algebra.ScalarT, G1 algebra.G1ElementT] struct {
W Witness[S]
}
var ret dbwtiness[S, G1]
pubw, err := w.Public()
if err != nil {
return ret.W, fmt.Errorf("get public witness: %w", err)
}
vec := pubw.Vector()
switch s := any(&ret).(type) {
case *dbwtiness[emulated.Element[emparams.BN254Fr], sw_bn254.G1Affine]:
vect, ok := vec.(fr_bn254.Vector)
if !ok {
return ret.W, fmt.Errorf("expected fr_bn254.Vector, got %T", vec)
}
for i := range vect {
s.W.Public = append(s.W.Public, emulated.ValueOf[emparams.BN254Fr](vect[i]))
}
case *dbwtiness[sw_bls12377.Scalar, sw_bls12377.G1Affine]:
vect, ok := vec.(fr_bls12377.Vector)
if !ok {
return ret.W, fmt.Errorf("expected fr_bls12377.Vector, got %T", vec)
}
for i := range vect {
s.W.Public = append(s.W.Public, vect[i].String())
}
case *dbwtiness[emulated.Element[emparams.BLS12381Fr], sw_bls12381.G1Affine]:
vect, ok := vec.(fr_bls12381.Vector)
if !ok {
return ret.W, fmt.Errorf("expected fr_bls12381.Vector, got %T", vec)
}
for i := range vect {
s.W.Public = append(s.W.Public, emulated.ValueOf[emparams.BLS12381Fr](vect[i]))
}
case *dbwtiness[sw_bls24315.Scalar, sw_bls24315.G1Affine]:
vect, ok := vec.(fr_bls24315.Vector)
if !ok {
return ret.W, fmt.Errorf("expected fr_bls24315.Vector, got %T", vec)
}
for i := range vect {
s.W.Public = append(s.W.Public, vect[i].String())
}
default:
return ret.W, fmt.Errorf("unknown parametric type combination")
}
return ret.W, nil
}

// PlaceholderWitness creates a stub witness which can be used to allocate the
// variables in the circuit if the actual witness is not yet known. It takes
// into account the number of public inputs and number of used commitments.
func PlaceholderWitness[S algebra.ScalarT](ccs constraint.ConstraintSystem) Witness[S] {
return Witness[S]{
Public: make([]S, ccs.GetNbPublicVariables()-1),
Public: make([]S, ccs.GetNbPublicVariables()),
}
}

Expand All @@ -99,10 +263,15 @@ type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Element
htfHash hash.FieldHasher
}

func NewVerifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT](api frontend.API, curve algebra.Curve[S, G1El], pairing algebra.Pairing[G1El, G2El, GtEl]) *Verifier[S, G1El, G2El, GtEl] {
func NewVerifier[
S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.GtElementT](
api frontend.API, curve algebra.Curve[S, G1El], pairing algebra.Pairing[G1El, G2El, GtEl],
fsHash hash.FieldHasher) *Verifier[S, G1El, G2El, GtEl] {
return &Verifier[S, G1El, G2El, GtEl]{
api: api,
curve: curve,
pairing: pairing,
fsHash: fsHash,
}
}

Expand All @@ -121,43 +290,43 @@ func (v *Verifier[S, G1El, G2El, GtEl]) AssertProof(vk VerifyingKey[S, G1El, G2E
}

func (v *Verifier[S, G1El, G2El, GtEl]) bindPublicData(fs *fiatshamir.Transcript, challenge string, vk VerifyingKey[S, G1El, G2El], witness Witness[S]) error {

nbBits := v.api.Compiler().FieldBitLen()
// permutation
if err := fs.Bind(challenge, marshalG1(v.api, vk.S[0])); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[0].G1El, nbBits)); err != nil {
return err
}
if err := fs.Bind(challenge, marshalG1(v.api, vk.S[1])); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[1].G1El, nbBits)); err != nil {
return err
}
if err := fs.Bind(challenge, marshalG1(v.api, vk.S[2])); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.S[2].G1El, nbBits)); err != nil {
return err
}

// coefficients
if err := fs.Bind(challenge, marshalG1(v.api, vk.Ql)); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Ql.G1El, nbBits)); err != nil {
return err
}
if err := fs.Bind(challenge, marshalG1(v.api, vk.Qr)); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qr.G1El, nbBits)); err != nil {
return err
}
if err := fs.Bind(challenge, marshalG1(v.api, vk.Qm)); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qm.G1El, nbBits)); err != nil {
return err
}
if err := fs.Bind(challenge, marshalG1(v.api, vk.Qo)); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qo.G1El, nbBits)); err != nil {
return err
}
if err := fs.Bind(challenge, marshalG1(v.api, vk.Qk)); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qk.G1El, nbBits)); err != nil {
return err
}
for i := range vk.Qcp {
if err := fs.Bind(challenge, marshalG1(v.api, vk.Qcp[i])); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalG1(vk.Qcp[i].G1El, nbBits)); err != nil {
return err
}
}

// public inputs
for i := 0; i < len(witness.Public); i++ {
if err := fs.Bind(challenge, marshalG1(v.api, witness.Public[i])); err != nil {
if err := fs.Bind(challenge, v.curve.MarshalScalar(witness.Public[i], nbBits)); err != nil {
return err
}
}
Expand Down
15 changes: 13 additions & 2 deletions std/recursion/plonk/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type OuterCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Ele
Proof Proof[S, G1El, G2El]
VerifyingKey VerifyingKey[S, G1El, G2El]
InnerWitness Witness[S]

target *big.Int // TODO: remove later
}

func (c *OuterCircuit[S, G1El, G2El, GtEl]) Define(api frontend.API) error {
Expand All @@ -73,7 +75,12 @@ func (c *OuterCircuit[S, G1El, G2El, GtEl]) Define(api frontend.API) error {
if err != nil {
return fmt.Errorf("get pairing: %w", err)
}
verifier := NewVerifier(api, curve, pairing)
// TODO: should do automatically but we need modulus. Hopefully Arithmetization returns it.
fsHhash, err := recursion.NewHash(api, c.target)
if err != nil {
return fmt.Errorf("get hash: %w", err)
}
verifier := NewVerifier(api, curve, pairing, fsHhash)
err = verifier.AssertProof(c.VerifyingKey, c.Proof, c.InnerWitness)
return err
}
Expand All @@ -92,12 +99,16 @@ func TestBLS12InBW6(t *testing.T) {

outerCircuit := &OuterCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{
InnerWitness: PlaceholderWitness[sw_bls12377.Scalar](innerCcs),
Proof: PlaceholderProof[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs),
VerifyingKey: PlaceholderVerifyingKey[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine](innerCcs),
target: ecc.BLS12_377.ScalarField(),
}
outerAssignment := &OuterCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{
InnerWitness: circuitWitness,
Proof: circuitProof,
VerifyingKey: circuitVk,
target: ecc.BLS12_377.ScalarField(),
}
assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BW6_761))
assert.CheckCircuit(outerCircuit, test.WithValidAssignment(outerAssignment), test.WithCurves(ecc.BW6_761),
test.NoFuzzing(), test.NoSerializationChecks(), test.NoSolidityChecks())
}

0 comments on commit 7dba1bd

Please sign in to comment.