Documentation
¶
Overview ¶
Package kzg implements KZG polynomial commitment verification.
KZG polynomial commitment allows for the prover to commit to a polynomial and then selectively prove evaluations of the said polynomial. The size of the commitment is a single G1 element and the size of the evaluation proof is also a single G1 element. However, KZG polynomial commitment scheme requires a trusted SRS.
This package supersedes previous type-specific implementations and allows to use any implemented pairing-friendly curve implementation, being defined over a 2-chain (native implementation) or using field emulation.
Example (Emulated) ¶
Example of using KZG verifier using emulated pairing implementation.
package main
import (
"crypto/rand"
"fmt"
"github.com/consensys/gnark-crypto/ecc"
fr_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr"
kzg_bn254 "github.com/consensys/gnark-crypto/ecc/bn254/kzg"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/std/algebra"
"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
"github.com/consensys/gnark/std/commitments/kzg"
)
type KZGVerificationCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GTEl algebra.GtElementT] struct {
kzg.VerifyingKey[G2El]
kzg.Commitment[G1El]
kzg.OpeningProof[S, G1El]
}
func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error {
curve, err := algebra.GetCurve[S, G1El](api)
if err != nil {
return fmt.Errorf("get curve: %w", err)
}
pairing, err := algebra.GetPairing[G1El, G2El, GTEl](api)
if err != nil {
return fmt.Errorf("get pairing: %w", err)
}
verifier := kzg.NewVerifier(c.VerifyingKey, curve, pairing)
if err := verifier.AssertProof(c.Commitment, c.OpeningProof); err != nil {
return fmt.Errorf("assert proof: %w", err)
}
return nil
}
// Example of using KZG verifier using emulated pairing implementation.
func main() {
// !!! UNSAFE SRS. FOR EXAMPLE PURPOSES ONLY. We create a trusted SRS for
// KZG polynomial commitment scheme. In practice this must be prepared using
// MPC or by reusing existing SRS. !!!
const (
// size of the SRS. Defines the maximum degree of the polynomial which can be committed to
kzgSize = 128
// degree of the random polynomial in the example
polynomialSize = 100
)
// create new SRS for example purposes (NB! UNSAFE!)
alpha, err := rand.Int(rand.Reader, ecc.BN254.ScalarField())
if err != nil {
panic("sampling alpha failed: " + err.Error())
}
srs, err := kzg_bn254.NewSRS(kzgSize, alpha) // UNSAFE!
if err != nil {
panic("new SRS failed: " + err.Error())
}
// sample the random polynomial by sampling the coefficients.
f := make([]fr_bn254.Element, polynomialSize)
for i := range f {
f[i].SetRandom()
}
// natively commit to the polynomial using SRS
com, err := kzg_bn254.Commit(f, srs.Pk)
if err != nil {
panic("commitment failed: " + err.Error())
}
// sample random evaluation point
var point fr_bn254.Element
point.SetRandom()
// construct a proof of correct opening. The evaluation value is proof.ClaimedValue
proof, err := kzg_bn254.Open(f, point, srs.Pk)
if err != nil {
panic("test opening failed: " + err.Error())
}
// test opening proof natively
if err = kzg_bn254.Verify(&com, &proof, point, srs.Vk); err != nil {
panic("test verify failed: " + err.Error())
}
// create a witness element of the commitment
wCmt, err := kzg.ValueOfCommitment[sw_bn254.G1Affine](com)
if err != nil {
panic("commitment witness failed: " + err.Error())
}
// create a witness element of the opening proof and the evaluation point
wProof, err := kzg.ValueOfOpeningProof[sw_bn254.Scalar, sw_bn254.G1Affine](point, proof)
if err != nil {
panic("opening proof witness failed: " + err.Error())
}
// create a witness element of the SRS
wVk, err := kzg.ValueOfVerifyingKey[sw_bn254.G2Affine](srs.Vk)
if err != nil {
panic("verifying key witness failed: " + err.Error())
}
assignment := KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{
VerifyingKey: wVk,
Commitment: wCmt,
OpeningProof: wProof,
}
circuit := KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}
// as we are currently using the emulated implementation of BN254
// in-circuit, then we can compile to any curve. For example purposes, here
// we use BN254.
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
panic("compile failed: " + err.Error())
}
// create Groth16 setup. NB! UNSAFE
pk, vk, err := groth16.Setup(ccs) // UNSAFE! Use MPC
if err != nil {
panic("setup failed: " + err.Error())
}
// create prover witness from the assignment
secretWitness, err := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
if err != nil {
panic("secret witness failed: " + err.Error())
}
// create public witness from the assignment
publicWitness, err := secretWitness.Public()
if err != nil {
panic("public witness failed: " + err.Error())
}
// construct the groth16 proof of verifying KZG commitment opening in-circuit
circuitProof, err := groth16.Prove(ccs, pk, secretWitness)
if err != nil {
panic("proving failed: " + err.Error())
}
// verify the Groth16 proof
err = groth16.Verify(circuitProof, vk, publicWitness)
if err != nil {
panic("circuit verification failed: " + err.Error())
}
fmt.Println("done")
}
Output: done
Example (Native) ¶
Example of using KZG verifier using 2-chains of curves. It is significantly more efficient than using field emulation, but requires a specific chain of inner and outer curves.
// !!! UNSAFE SRS. FOR EXAMPLE PURPOSES ONLY. We create a trusted SRS for
// KZG polynomial commitment scheme. In practice this must be prepared using
// MPC or by reusing existing SRS. !!!
const (
// size of the SRS. Defines the maximum degree of the polynomial which can be committed to
kzgSize = 128
// degree of the random polynomial in the example
polynomialSize = 100
)
// create new SRS for example purposes (NB! UNSAFE!)
alpha, err := rand.Int(rand.Reader, ecc.BLS12_377.ScalarField())
if err != nil {
panic("sampling alpha failed: " + err.Error())
}
srs, err := kzg_bls12377.NewSRS(kzgSize, alpha) // UNSAFE!
if err != nil {
panic("new SRS failed: " + err.Error())
}
// sample the random polynomial by sampling the coefficients.
f := make([]fr_bls12377.Element, polynomialSize)
for i := range f {
f[i].SetRandom()
}
// natively commit to the polynomial using SRS
com, err := kzg_bls12377.Commit(f, srs.Pk)
if err != nil {
panic("commitment failed: " + err.Error())
}
// sample random evaluation point
var point fr_bls12377.Element
point.SetRandom()
// construct a proof of correct opening. The evaluation value is proof.ClaimedValue
proof, err := kzg_bls12377.Open(f, point, srs.Pk)
if err != nil {
panic("test opening failed: " + err.Error())
}
// test opening proof natively
if err = kzg_bls12377.Verify(&com, &proof, point, srs.Vk); err != nil {
panic("test verify failed: " + err.Error())
}
// create a witness element of the commitment
wCmt, err := kzg.ValueOfCommitment[sw_bls12377.G1Affine](com)
if err != nil {
panic("commitment witness failed: " + err.Error())
}
// create a witness element of the opening proof and the evaluation point
wProof, err := kzg.ValueOfOpeningProof[sw_bls12377.Scalar, sw_bls12377.G1Affine](point, proof)
if err != nil {
panic("opening proof witness failed: " + err.Error())
}
// create a witness element of the SRS
wVk, err := kzg.ValueOfVerifyingKey[sw_bls12377.G2Affine](srs.Vk)
if err != nil {
panic("verifying key witness failed: " + err.Error())
}
assignment := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{
VerifyingKey: wVk,
Commitment: wCmt,
OpeningProof: wProof,
}
circuit := KZGVerificationCircuit[sw_bls12377.Scalar, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{}
// because we are using 2-chains then the outer curve must correspond to the
// inner curve. For inner BLS12-377 the outer curve is BW6-761.
ccs, err := frontend.Compile(ecc.BW6_761.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
panic("compile failed: " + err.Error())
}
// create Groth16 setup. NB! UNSAFE
pk, vk, err := groth16.Setup(ccs) // UNSAFE! Use MPC
if err != nil {
panic("setup failed: " + err.Error())
}
// create prover witness from the assignment
secretWitness, err := frontend.NewWitness(&assignment, ecc.BW6_761.ScalarField())
if err != nil {
panic("secret witness failed: " + err.Error())
}
// create public witness from the assignment
publicWitness, err := secretWitness.Public()
if err != nil {
panic("public witness failed: " + err.Error())
}
// construct the groth16 proof of verifying KZG commitment opening in-circuit
circuitProof, err := groth16.Prove(ccs, pk, secretWitness)
if err != nil {
panic("proving failed: " + err.Error())
}
// verify the Groth16 proof
err = groth16.Verify(circuitProof, vk, publicWitness)
if err != nil {
panic("circuit verification failed: " + err.Error())
}
fmt.Println("done")
Output: done
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Commitment ¶
type Commitment[G1El algebra.G1ElementT] struct { G1El G1El }
Commitment is an KZG commitment to a polynomial. Use ValueOfCommitment to initialize a witness from the native commitment.
func ValueOfCommitment ¶
func ValueOfCommitment[G1El algebra.G1ElementT](cmt any) (Commitment[G1El], error)
ValueOfCommitment initializes a KZG commitment witness from a native commitment. It returns an error if there is a conflict between the type parameters and provided native commitment type.
type OpeningProof ¶
type OpeningProof[S algebra.ScalarT, G1El algebra.G1ElementT] struct { QuotientPoly G1El ClaimedValue S Point S }
OpeningProof embeds the opening proof that polynomial evaluated at Point is equal to ClaimedValue. Use ValueOfOpeningProof to initialize a witness from a native opening proof.
func ValueOfOpeningProof ¶
func ValueOfOpeningProof[S algebra.ScalarT, G1El algebra.G1ElementT](point any, proof any) (OpeningProof[S, G1El], error)
ValueOfOpeningProof initializes an opening proof from the given proof and point. It returns an error if there is a mismatch between the type parameters and types of the provided point and proof.
type Verifier ¶
type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT] struct { VerifyingKey[G2El] // contains filtered or unexported fields }
Verifier allows verifying KZG opening proofs.
func NewVerifier ¶
func NewVerifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT](vk VerifyingKey[G2El], curve algebra.Curve[S, G1El], pairing algebra.Pairing[G1El, G2El, GtEl]) *Verifier[S, G1El, G2El, GtEl]
NewVerifier initializes a new Verifier instance.
func (*Verifier[S, G1El, G2El, GtEl]) AssertProof ¶
func (vk *Verifier[S, G1El, G2El, GtEl]) AssertProof(commitment Commitment[G1El], proof OpeningProof[S, G1El]) error
AssertProof asserts the validity of the opening proof for the given commitment.
type VerifyingKey ¶
type VerifyingKey[G2El algebra.G2ElementT] struct { SRS [2]G2El }
VerifyingKey is the trusted setup for KZG polynomial commitment scheme. Use ValueOfVerifyingKey to initialize a witness from the native VerifyingKey.
func ValueOfVerifyingKey ¶
func ValueOfVerifyingKey[G2El algebra.G2ElementT](vk any) (VerifyingKey[G2El], error)
ValueOfVerifyingKey initializes verifying key witness from the native verifying key. It returns an error if there is a mismatch between the type parameters and the provided verifying key type.