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

[feat] KZG verifier gadget #307

Merged
merged 15 commits into from
Jun 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions std/algebra/sw_bls12377/g1.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func (P *G1Affine) ScalarMul(api frontend.API, Q G1Affine, s interface{}) *G1Aff
}
}

var DecomposeScalar = func(scalarField *big.Int, inputs []*big.Int, res []*big.Int) error {
var DecomposeScalarG1 = func(scalarField *big.Int, inputs []*big.Int, res []*big.Int) error {
cc := getInnerCurveConfig(scalarField)
sp := ecc.SplitScalar(inputs[0], cc.glvBasis)
res[0].Set(&(sp[0]))
Expand All @@ -228,7 +228,7 @@ var DecomposeScalar = func(scalarField *big.Int, inputs []*big.Int, res []*big.I
}

func init() {
hint.Register(DecomposeScalar)
hint.Register(DecomposeScalarG1)
}

// varScalarMul sets P = [s] Q and returns P.
Expand All @@ -254,7 +254,7 @@ func (P *G1Affine) varScalarMul(api frontend.API, Q G1Affine, s frontend.Variabl
// the hints allow to decompose the scalar s into s1 and s2 such that
// s1 + λ * s2 == s mod r,
// where λ is third root of one in 𝔽_r.
sd, err := api.Compiler().NewHint(DecomposeScalar, 3, s)
sd, err := api.Compiler().NewHint(DecomposeScalarG1, 3, s)
if err != nil {
// err is non-nil only for invalid number of inputs
panic(err)
Expand Down
3 changes: 1 addition & 2 deletions std/algebra/sw_bls12377/pairing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/consensys/gnark-crypto/ecc"
bls12377 "github.com/consensys/gnark-crypto/ecc/bls12-377"
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/std/algebra/fields_bls12377"
Expand Down Expand Up @@ -54,7 +53,7 @@ func TestFinalExp(t *testing.T) {
circuit.R = pairingRes

assert := test.NewAssert(t)
assert.SolvingSucceeded(&circuit, &witness, test.WithBackends(backend.PLONK), test.WithCurves(ecc.BW6_761))
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761))
}

type pairingBLS377 struct {
Expand Down
6 changes: 3 additions & 3 deletions std/algebra/sw_bls24315/g1.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func (P *G1Affine) ScalarMul(api frontend.API, Q G1Affine, s interface{}) *G1Aff
}
}

var DecomposeScalar = func(scalarField *big.Int, inputs []*big.Int, res []*big.Int) error {
var DecomposeScalarG1 = func(scalarField *big.Int, inputs []*big.Int, res []*big.Int) error {
cc := getInnerCurveConfig(scalarField)
sp := ecc.SplitScalar(inputs[0], cc.glvBasis)
res[0].Set(&(sp[0]))
Expand All @@ -228,7 +228,7 @@ var DecomposeScalar = func(scalarField *big.Int, inputs []*big.Int, res []*big.I
}

func init() {
hint.Register(DecomposeScalar)
hint.Register(DecomposeScalarG1)
}

// varScalarMul sets P = [s] Q and returns P.
Expand All @@ -254,7 +254,7 @@ func (P *G1Affine) varScalarMul(api frontend.API, Q G1Affine, s frontend.Variabl
// the hints allow to decompose the scalar s into s1 and s2 such that
// s1 + λ * s2 == s mod r,
// where λ is third root of one in 𝔽_r.
sd, err := api.Compiler().NewHint(DecomposeScalar, 3, s)
sd, err := api.Compiler().NewHint(DecomposeScalarG1, 3, s)
if err != nil {
// err is non-nil only for invalid number of inputs
panic(err)
Expand Down
5 changes: 2 additions & 3 deletions std/algebra/sw_bls24315/pairing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/consensys/gnark-crypto/ecc"
bls24315 "github.com/consensys/gnark-crypto/ecc/bls24-315"
"github.com/consensys/gnark-crypto/ecc/bls24-315/fr"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/std/algebra/fields_bls24315"
Expand Down Expand Up @@ -87,7 +86,7 @@ func TestPairingBLS24315(t *testing.T) {
witness.Q.Assign(&Q)

assert := test.NewAssert(t)
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633), test.WithBackends(backend.GROTH16))
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633))

}

Expand Down Expand Up @@ -124,7 +123,7 @@ func TestTriplePairingBLS24315(t *testing.T) {
witness.Q3.Assign(&Q[2])

assert := test.NewAssert(t)
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633), test.WithBackends(backend.GROTH16))
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_633))

}

Expand Down
84 changes: 84 additions & 0 deletions std/commitments/kzg_bls12377/verifier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
Copyright © 2020 ConsenSys

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package kzg_bls12377 provides a ZKP-circuit function to verify BLS12_377 KZG inside a BW6_761 circuit.
package kzg_bls12377

import (
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/algebra/fields_bls12377"
"github.com/consensys/gnark/std/algebra/sw_bls12377"
)

// Digest commitment of a polynomial.
type Digest = sw_bls12377.G1Affine

// VK verification key (G2 part of SRS)
type VK struct {
G1 sw_bls12377.G1Affine // G₁
G2 [2]sw_bls12377.G2Affine // [G₂, [α]G₂]
}

// OpeningProof KZG proof for opening at a single point.
type OpeningProof struct {
// H quotient polynomial (f - f(z))/(x-z)
H sw_bls12377.G1Affine

// ClaimedValue purported value
ClaimedValue frontend.Variable
}

// Verify verifies a KZG opening proof at a single point
func Verify(api frontend.API, commitment Digest, proof OpeningProof, point frontend.Variable, srs VK) {
// We take the ClaimedValue and point to be frontend.Variable wich
// are elements in 𝔽_p, i.e. the BW6-761 scalar field.
// This is different from 𝔽_r, i.e. the BLS12-377 scalar field
// but r << p (p-r ≈ 377-bit) so when adding two 𝔽_r elements
// as 𝔽_p there is no reduction mod p.
// However, we should be cautious about negative elements and take
// the negative of points instead (-[f(a)]G₁ and -[a]G₂).

// [f(a)]G₁
var claimedValueG1Aff sw_bls12377.G1Affine
claimedValueG1Aff.ScalarMul(api, srs.G1, proof.ClaimedValue)

// [f(α) - f(a)]G₁
var fminusfaG1 sw_bls12377.G1Affine
fminusfaG1.Neg(api, claimedValueG1Aff)
fminusfaG1.AddAssign(api, commitment)

// [-H(α)]G₁
var negH sw_bls12377.G1Affine
negH.Neg(api, proof.H)

// [α-a]G₂
var alphaMinusaG2 sw_bls12377.G2Affine
alphaMinusaG2.ScalarMul(api, srs.G2[0], point).
Neg(api, alphaMinusaG2).
AddAssign(api, srs.G2[1])

// e([f(α) - f(a)]G₁, G₂).e([-H(α)]G₁, [α-a]G₂) ==? 1
resPairing, _ := sw_bls12377.Pair(
api,
[]sw_bls12377.G1Affine{fminusfaG1, negH},
[]sw_bls12377.G2Affine{srs.G2[0], alphaMinusaG2},
)

var one fields_bls12377.E12
one.SetOne()
resPairing.AssertIsEqual(api, one)

}
169 changes: 169 additions & 0 deletions std/commitments/kzg_bls12377/verifier_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
/*
Copyright © 2020 ConsenSys

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kzg_bls12377

import (
"crypto/rand"
"testing"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr"
"github.com/consensys/gnark-crypto/ecc/bls12-377/fr/kzg"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/test"
)

type verifierCircuit struct {
VerifKey VK
Proof OpeningProof
Com Digest
S frontend.Variable
}

func (circuit *verifierCircuit) Define(api frontend.API) error {

// create the verifier cs
Verify(api, circuit.Com, circuit.Proof, circuit.S, circuit.VerifKey)

return nil
}

//-------------------------------------------------------
// proof generated using gnark-crypto

func TestVerifierDynamic(t *testing.T) {

assert := test.NewAssert(t)

// sizes of polynomials, kzg
const kzgSize = 128
const polynomialSize = 100

// trusted setup
alpha, err := rand.Int(rand.Reader, ecc.BLS12_377.ScalarField())
assert.NoError(err)
srs, err := kzg.NewSRS(kzgSize, alpha)
assert.NoError(err)

// random polynomial
f := make([]fr.Element, polynomialSize)
for i := 0; i < 60; i++ {
f[i].SetRandom()
}

// commit to the polynomial
com, err := kzg.Commit(f, srs)
assert.NoError(err)

// create opening proof
var point fr.Element
point.SetRandom()
proof, err := kzg.Open(f, point, srs)
assert.NoError(err)

// check that the proof is correct
err = kzg.Verify(&com, &proof, point, srs)
if err != nil {
t.Fatal(err)
}

// verify the proof in circuit
var witness verifierCircuit

// populate the witness
witness.Com.X = com.X.String()
witness.Com.Y = com.Y.String()

witness.Proof.H.X = proof.H.X.String()
witness.Proof.H.Y = proof.H.Y.String()

witness.Proof.ClaimedValue = proof.ClaimedValue.String()

witness.S = point.String()

witness.VerifKey.G1.X = srs.G1[0].X.String()
witness.VerifKey.G1.Y = srs.G1[0].Y.String()

witness.VerifKey.G2[0].X.A0 = srs.G2[0].X.A0.String()
witness.VerifKey.G2[0].X.A1 = srs.G2[0].X.A1.String()
witness.VerifKey.G2[0].Y.A0 = srs.G2[0].Y.A0.String()
witness.VerifKey.G2[0].Y.A1 = srs.G2[0].Y.A1.String()
witness.VerifKey.G2[1].X.A0 = srs.G2[1].X.A0.String()
witness.VerifKey.G2[1].X.A1 = srs.G2[1].X.A1.String()
witness.VerifKey.G2[1].Y.A0 = srs.G2[1].Y.A0.String()
witness.VerifKey.G2[1].Y.A1 = srs.G2[1].Y.A1.String()

// check if the circuit is solved
var circuit verifierCircuit
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761))

}

//-------------------------------------------------------
// harcoded values

func TestVerifier(t *testing.T) {

var circuit, witness verifierCircuit

// static witness
witness.Com.X = "145429059828629443506099208441019164249918805265766585069511130101715300037889375544644493566733059056337445574142"
witness.Com.Y = "7748648670212409231552941907406345586179813940682493172078407968203200311849395869785335293628955566021478572791"

witness.Proof.H.X = "142546216630759857020142552653688574597188212934274836451979072858880695115513802425442488457664742720974070355453"
witness.Proof.H.Y = "51742728231756961100409716107519203689800988928890924645730616869717553365749083029986151526811552917856555146906"

witness.Proof.ClaimedValue = "7211341386127354417397285211336133449231039596179023429378585109196698597268"
witness.S = "4321"
witness.VerifKey.G1.X = "81937999373150964239938255573465948239988671502647976594219695644855304257327692006745978603320413799295628339695"
witness.VerifKey.G1.Y = "241266749859715473739788878240585681733927191168601896383759122102112907357779751001206799952863815012735208165030"
witness.VerifKey.G2[0].X.A0 = "233578398248691099356572568220835526895379068987715365179118596935057653620464273615301663571204657964920925606294"
witness.VerifKey.G2[0].X.A1 = "140913150380207355837477652521042157274541796891053068589147167627541651775299824604154852141315666357241556069118"
witness.VerifKey.G2[0].Y.A0 = "63160294768292073209381361943935198908131692476676907196754037919244929611450776219210369229519898517858833747423"
witness.VerifKey.G2[0].Y.A1 = "149157405641012693445398062341192467754805999074082136895788947234480009303640899064710353187729182149407503257491"
witness.VerifKey.G2[1].X.A0 = "123747009012703414871739433259892117784672459657097139998749475279099125411579029748101735145753812822027512995199"
witness.VerifKey.G2[1].X.A1 = "62735868045337090199933301723513128455431585854943778977190757050206710789139082141526891028732261537358701287808"
witness.VerifKey.G2[1].Y.A0 = "212548833831227473592895134150456464278558858278752454560645447355770538424096804613692943525553353783189853308160"
witness.VerifKey.G2[1].Y.A1 = "123051654588413991319606911619099872563646143639520520553172600449178549047186983142138529976243874838154671706124"

// cs values
assert := test.NewAssert(t)
assert.SolvingSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761))

}

// bench
var ccsBench frontend.CompiledConstraintSystem

func BenchmarkVerifyKZG(b *testing.B) {
var c verifierCircuit
b.ResetTimer()
b.Run("groth16", func(b *testing.B) {
for i := 0; i < b.N; i++ {
ccsBench, _ = frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &c)
}
})
b.Log("groth16", ccsBench.GetNbConstraints())
b.Run("plonk", func(b *testing.B) {
for i := 0; i < b.N; i++ {
ccsBench, _ = frontend.Compile(ecc.BW6_761.ScalarField(), scs.NewBuilder, &c)
}
})
b.Log("plonk", ccsBench.GetNbConstraints())
}