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"
"github.com/consensys/gnark/std/math/emulated"
)
type KZGVerificationCircuit[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GTEl algebra.GtElementT] struct {
kzg.VerifyingKey[G1El, G2El]
kzg.Commitment[G1El]
kzg.OpeningProof[FR, G1El]
Point emulated.Element[FR]
}
func (c *KZGVerificationCircuit[FR, G1El, G2El, GTEl]) Define(api frontend.API) error {
verifier, err := kzg.NewVerifier[FR, G1El, G2El, GTEl](api)
if err != nil {
return fmt.Errorf("new verifier: %w", err)
}
if err := verifier.CheckOpeningProof(c.Commitment, c.OpeningProof, c.Point, c.VerifyingKey); 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
wProof, err := kzg.ValueOfOpeningProof[sw_bn254.ScalarField, sw_bn254.G1Affine](proof)
if err != nil {
panic("opening proof witness failed: " + err.Error())
}
// create a witness element of the SRS
wVk, err := kzg.ValueOfVerifyingKey[sw_bn254.G1Affine, sw_bn254.G2Affine](srs.Vk)
if err != nil {
panic("verifying key witness failed: " + err.Error())
}
// create a witness element of the evaluation point
wPt, err := kzg.ValueOfScalar[sw_bn254.ScalarField](point)
if err != nil {
panic("point witness failed: " + err.Error())
}
assignment := KZGVerificationCircuit[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{
VerifyingKey: wVk,
Commitment: wCmt,
OpeningProof: wProof,
Point: wPt,
}
circuit := KZGVerificationCircuit[sw_bn254.ScalarField, 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())
}
}
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
wProof, err := kzg.ValueOfOpeningProof[sw_bls12377.ScalarField, sw_bls12377.G1Affine](proof)
if err != nil {
panic("opening proof witness failed: " + err.Error())
}
// create a witness element of the SRS
wVk, err := kzg.ValueOfVerifyingKey[sw_bls12377.G1Affine, sw_bls12377.G2Affine](srs.Vk)
if err != nil {
panic("verifying key witness failed: " + err.Error())
}
// create a witness element of the evaluation point
wPt, err := kzg.ValueOfScalar[sw_bls12377.ScalarField](point)
if err != nil {
panic("point witness failed: " + err.Error())
}
assignment := KZGVerificationCircuit[sw_bls12377.ScalarField, sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT]{
VerifyingKey: wVk,
Commitment: wCmt,
OpeningProof: wProof,
Point: wPt,
}
circuit := KZGVerificationCircuit[sw_bls12377.ScalarField, 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())
}
Index ¶
- func ValueOfScalar[FR emulated.FieldParams](scalar any) (emulated.Element[FR], error)
- type BatchOpeningProof
- type Commitment
- type OpeningProof
- type Verifier
- func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitment[G1El], proofs []OpeningProof[FR, G1El], ...) error
- func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], ...) error
- func (v *Verifier[FR, G1El, G2El, GTEl]) CheckOpeningProof(commitment Commitment[G1El], proof OpeningProof[FR, G1El], ...) error
- func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], ...) (OpeningProof[FR, G1El], Commitment[G1El], error)
- func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProofsMultiPoint(digests []Commitment[G1El], proofs []OpeningProof[FR, G1El], ...) (*G1El, *G1El, error)
- type VerifyingKey
- func PlaceholderVerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT]() VerifyingKey[G1El, G2El]
- func ValueOfVerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk any) (VerifyingKey[G1El, G2El], error)
- func ValueOfVerifyingKeyFixed[G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk any) (VerifyingKey[G1El, G2El], error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ValueOfScalar ¶
ValueOfScalar initializes a scalar in a witness from a native scalar (Fr) point. The scalars are always emulated.
Types ¶
type BatchOpeningProof ¶
type BatchOpeningProof[FR emulated.FieldParams, G1El algebra.G1ElementT] struct { Quotient G1El ClaimedValues []emulated.Element[FR] }
func ValueOfBatchOpeningProof ¶
func ValueOfBatchOpeningProof[FR emulated.FieldParams, G1El any](proof any) (BatchOpeningProof[FR, G1El], error)
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[FR emulated.FieldParams, G1El algebra.G1ElementT] struct { Quotient G1El ClaimedValue emulated.Element[FR] }
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[FR emulated.FieldParams, G1El algebra.G1ElementT](proof any) (OpeningProof[FR, 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[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT] struct { // contains filtered or unexported fields }
Verifier allows verifying KZG opening proofs.
func NewVerifier ¶
func NewVerifier[FR emulated.FieldParams, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT](api frontend.API) (*Verifier[FR, G1El, G2El, GtEl], error)
NewVerifier initializes a new Verifier instance.
func (*Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints ¶
func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifyMultiPoints(digests []Commitment[G1El], proofs []OpeningProof[FR, G1El], points []emulated.Element[FR], vk VerifyingKey[G1El, G2El]) error
BatchVerifyMultiPoints verifies multiple opening proofs at different points.
func (*Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint ¶
func (v *Verifier[FR, G1El, G2El, GTEl]) BatchVerifySinglePoint(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], vk VerifyingKey[G1El, G2El], dataTranscript ...emulated.Element[FR]) error
BatchVerifySinglePoint verifies multiple opening proofs at a single point.
func (*Verifier[FR, G1El, G2El, GTEl]) CheckOpeningProof ¶
func (v *Verifier[FR, G1El, G2El, GTEl]) CheckOpeningProof(commitment Commitment[G1El], proof OpeningProof[FR, G1El], point emulated.Element[FR], vk VerifyingKey[G1El, G2El]) error
CheckOpeningProof asserts the validity of the opening proof for the given commitment at point.
func (*Verifier[FR, G1El, G2El, GTEl]) FoldProof ¶
func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProof(digests []Commitment[G1El], batchOpeningProof BatchOpeningProof[FR, G1El], point emulated.Element[FR], dataTranscript ...emulated.Element[FR]) (OpeningProof[FR, G1El], Commitment[G1El], error)
FoldProof folds multiple commitments and a batch opening proof for a single opening check.
func (*Verifier[FR, G1El, G2El, GTEl]) FoldProofsMultiPoint ¶
func (v *Verifier[FR, G1El, G2El, GTEl]) FoldProofsMultiPoint(digests []Commitment[G1El], proofs []OpeningProof[FR, G1El], points []emulated.Element[FR], vk VerifyingKey[G1El, G2El]) (*G1El, *G1El, error)
FoldProofsMultiPoint folds multiple proofs with openings at multiple points. Used for batch verification of different opening proofs. See also Verifier.BatchVerifyMultiPoints.
type VerifyingKey ¶
type VerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT] struct { G2 [2]G2El G1 G1El }
VerifyingKey is the trusted setup for KZG polynomial commitment scheme. Use ValueOfVerifyingKey to initialize a witness from the native VerifyingKey.
func PlaceholderVerifyingKey ¶
func PlaceholderVerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT]() VerifyingKey[G1El, G2El]
PlaceholderVerifyingKey returns a placeholder value for the verifying key for compiling if the witness is going to be in precomputed form using ValueOfVerifyingKeyFixed.
func ValueOfVerifyingKey ¶
func ValueOfVerifyingKey[G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk any) (VerifyingKey[G1El, 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.
func ValueOfVerifyingKeyFixed ¶
func ValueOfVerifyingKeyFixed[G1El algebra.G1ElementT, G2El algebra.G2ElementT](vk any) (VerifyingKey[G1El, G2El], error)
ValueOfVerifyingKeyFixed initializes verifying key witness from the native verifying key and perform pre-computations for G2 elements. It returns an error if there is a mismatch between the type parameters and the provided verifying key type. Such witness is significantly larger than without precomputations. If witness size is important, then use ValueOfVerifyingKey instead.