Skip to content

Commit

Permalink
perf: use new fixed-arg pairing in kzg (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
yelhousni committed Nov 11, 2023
1 parent 44d4faf commit 03861c5
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 218 deletions.
44 changes: 24 additions & 20 deletions std/algebra/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,33 +53,37 @@ func GetCurve[S ScalarT, G1El G1ElementT](api frontend.API) (Curve[S, G1El], err
// GetPairing returns the [Pairing] implementation corresponding to the groups
// type parameters. The method allows to have a fully generic implementation
// without taking into consideration the initialization differences.
func GetPairing[G1El G1ElementT, G2El G2ElementT, GtEl GtElementT, L LinesT](api frontend.API) (Pairing[G1El, G2El, GtEl, LinesT], error) {
var ret Pairing[G1El, G2El, GtEl, LinesT]
func GetPairing[G1El G1ElementT, G2El G2ElementT, GtEl GtElementT, L LinesT](api frontend.API) (Pairing[G1El, G2El, GtEl, L], error) {
var ret Pairing[G1El, G2El, GtEl, L]
switch s := any(&ret).(type) {
case *Pairing[sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl, sw_bn254.LineEvaluation]:
p, err := sw_bn254.NewPairing(api)
if err != nil {
return ret, fmt.Errorf("new pairing: %w", err)
}
*s = p
/*
case *Pairing[sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl, sw_bn254.LineEvaluation]:
p, err := sw_bn254.NewPairing(api)
if err != nil {
return ret, fmt.Errorf("new pairing: %w", err)
}
*s = p
*/
case *Pairing[sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl, sw_bw6761.LineEvaluation]:
p, err := sw_bw6761.NewPairing(api)
if err != nil {
return ret, fmt.Errorf("new pairing: %w", err)
}
*s = p
case *Pairing[sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl, sw_bls12381.LineEvaluation]:
p, err := sw_bls12381.NewPairing(api)
if err != nil {
return ret, fmt.Errorf("new pairing: %w", err)
}
*s = p
case *Pairing[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT, sw_bls12377.LineEvaluation]:
p := sw_bls12377.NewPairing(api)
*s = p
case *Pairing[sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT, sw_bls24315.LineEvaluation]:
p := sw_bls24315.NewPairing(api)
*s = p
/*
case *Pairing[sw_bls12381.G1Affine, sw_bls12381.G2Affine, sw_bls12381.GTEl, sw_bls12381.LineEvaluation]:
p, err := sw_bls12381.NewPairing(api)
if err != nil {
return ret, fmt.Errorf("new pairing: %w", err)
}
*s = p
case *Pairing[sw_bls12377.G1Affine, sw_bls12377.G2Affine, sw_bls12377.GT, sw_bls12377.LineEvaluation]:
p := sw_bls12377.NewPairing(api)
*s = p
case *Pairing[sw_bls24315.G1Affine, sw_bls24315.G2Affine, sw_bls24315.GT, sw_bls24315.LineEvaluation]:
p := sw_bls24315.NewPairing(api)
*s = p
*/
default:
return ret, fmt.Errorf("unknown type parametrisation")
}
Expand Down
8 changes: 8 additions & 0 deletions std/algebra/emulated/sw_bw6761/pairing.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ type LineEvaluation struct {
R0, R1 emulated.Element[emulated.BW6761Fp]
}

// NewLineEvaluation allocates a witness from the native LineEvaluationAff and returns it.
func NewLineEvaluation(v bw6761.LineEvaluationAff) LineEvaluation {
return LineEvaluation{
R0: emulated.ValueOf[emulated.BW6761Fp](v.R0),
R1: emulated.ValueOf[emulated.BW6761Fp](v.R1),
}
}

// Pair calculates the reduced pairing for a set of points
// ∏ᵢ e(Pᵢ, Qᵢ).
//
Expand Down
2 changes: 2 additions & 0 deletions std/commitments/kzg/native_doc_test.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package kzg_test

/*
import (
"crypto/rand"
Expand Down Expand Up @@ -126,3 +127,4 @@ func Example_native() {
panic("circuit verification failed: " + err.Error())
}
}
*/
36 changes: 18 additions & 18 deletions std/commitments/kzg/nonnative_doc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@ import (
"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"
fr_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr"
kzg_bw6761 "github.com/consensys/gnark-crypto/ecc/bw6-761/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/algebra/emulated/sw_bw6761"
"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]
type KZGVerificationCircuit[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GTEl algebra.GtElementT, L algebra.LinesT] struct {
kzg.VerifyingKey[L]
kzg.Commitment[G1El]
kzg.OpeningProof[S, G1El]
}

func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl]) Define(api frontend.API) error {
func (c *KZGVerificationCircuit[S, G1El, G2El, GTEl, L]) 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)
pairing, err := algebra.GetPairing[G1El, G2El, GTEl, L](api)
if err != nil {
return fmt.Errorf("get pairing: %w", err)
}
Expand Down Expand Up @@ -55,61 +55,61 @@ func Example_emulated() {
if err != nil {
panic("sampling alpha failed: " + err.Error())
}
srs, err := kzg_bn254.NewSRS(kzgSize, alpha) // UNSAFE!
srs, err := kzg_bw6761.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)
f := make([]fr_bw6761.Element, polynomialSize)
for i := range f {
f[i].SetRandom()
}

// natively commit to the polynomial using SRS
com, err := kzg_bn254.Commit(f, srs.Pk)
com, err := kzg_bw6761.Commit(f, srs.Pk)
if err != nil {
panic("commitment failed: " + err.Error())
}

// sample random evaluation point
var point fr_bn254.Element
var point fr_bw6761.Element
point.SetRandom()

// construct a proof of correct opening. The evaluation value is proof.ClaimedValue
proof, err := kzg_bn254.Open(f, point, srs.Pk)
proof, err := kzg_bw6761.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 {
if err = kzg_bw6761.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)
wCmt, err := kzg.ValueOfCommitment[sw_bw6761.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)
wProof, err := kzg.ValueOfOpeningProof[sw_bw6761.Scalar, sw_bw6761.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)
wVk, err := kzg.ValueOfVerifyingKey[sw_bw6761.LineEvaluation](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]{
assignment := KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl, sw_bw6761.LineEvaluation]{
VerifyingKey: wVk,
Commitment: wCmt,
OpeningProof: wProof,
}
circuit := KZGVerificationCircuit[sw_bn254.Scalar, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl]{}
circuit := KZGVerificationCircuit[sw_bw6761.Scalar, sw_bw6761.G1Affine, sw_bw6761.G2Affine, sw_bw6761.GTEl, sw_bw6761.LineEvaluation]{}

// as we are currently using the emulated implementation of BN254
// in-circuit, then we can compile to any curve. For example purposes, here
Expand Down
94 changes: 51 additions & 43 deletions std/commitments/kzg/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,68 +168,76 @@ func ValueOfOpeningProof[S algebra.ScalarT, G1El algebra.G1ElementT](point any,

// VerifyingKey is the trusted setup for KZG polynomial commitment scheme. Use
// [ValueOfVerifyingKey] to initialize a witness from the native VerifyingKey.
type VerifyingKey[G2El algebra.G2ElementT] struct {
SRS [2]G2El
type VerifyingKey[L algebra.LinesT] struct {
SRS [2][2][189]L
}

// 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 ValueOfVerifyingKey[G2El algebra.G2ElementT](vk any) (VerifyingKey[G2El], error) {
var ret VerifyingKey[G2El]
func ValueOfVerifyingKey[L algebra.LinesT](vk any) (VerifyingKey[L], error) {
var ret VerifyingKey[L]
switch s := any(&ret).(type) {
case *VerifyingKey[sw_bn254.G2Affine]:
tVk, ok := vk.(kzg_bn254.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bn254.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bn254.NewG2Affine(tVk.G2[1])
case *VerifyingKey[sw_bls12377.G2Affine]:
tVk, ok := vk.(kzg_bls12377.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bls12377.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bls12377.NewG2Affine(tVk.G2[1])
case *VerifyingKey[sw_bls12381.G2Affine]:
tVk, ok := vk.(kzg_bls12381.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bls12381.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bls12381.NewG2Affine(tVk.G2[1])
case *VerifyingKey[sw_bw6761.G2Affine]:
/*
case *VerifyingKey[sw_bn254.G2Affine]:
tVk, ok := vk.(kzg_bn254.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bn254.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bn254.NewG2Affine(tVk.G2[1])
case *VerifyingKey[sw_bls12377.G2Affine]:
tVk, ok := vk.(kzg_bls12377.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bls12377.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bls12377.NewG2Affine(tVk.G2[1])
case *VerifyingKey[sw_bls12381.G2Affine]:
tVk, ok := vk.(kzg_bls12381.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bls12381.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bls12381.NewG2Affine(tVk.G2[1])
*/
case *VerifyingKey[sw_bw6761.LineEvaluation]:
tVk, ok := vk.(kzg_bw6761.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bw6761.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bw6761.NewG2Affine(tVk.G2[1])
case *VerifyingKey[sw_bls24315.G2Affine]:
tVk, ok := vk.(kzg_bls24315.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
for i := 0; i < 189; i++ {
s.SRS[0][0][i] = sw_bw6761.NewLineEvaluation(tVk.Lines[0][0][i])
s.SRS[0][1][i] = sw_bw6761.NewLineEvaluation(tVk.Lines[0][1][i])
s.SRS[1][0][i] = sw_bw6761.NewLineEvaluation(tVk.Lines[1][0][i])
s.SRS[1][1][i] = sw_bw6761.NewLineEvaluation(tVk.Lines[1][1][i])
}
s.SRS[0] = sw_bls24315.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bls24315.NewG2Affine(tVk.G2[1])
/*
case *VerifyingKey[sw_bls24315.G2Affine]:
tVk, ok := vk.(kzg_bls24315.VerifyingKey)
if !ok {
return ret, fmt.Errorf("mismatching types %T %T", ret, vk)
}
s.SRS[0] = sw_bls24315.NewG2Affine(tVk.G2[0])
s.SRS[1] = sw_bls24315.NewG2Affine(tVk.G2[1])
*/
default:
return ret, fmt.Errorf("unknown type parametrization")
}
return ret, nil
}

// Verifier allows verifying KZG opening proofs.
type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT] struct {
VerifyingKey[G2El]
type Verifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT, L algebra.LinesT] struct {
VerifyingKey[L]

curve algebra.Curve[S, G1El]
pairing algebra.Pairing[G1El, G2El, GtEl]
pairing algebra.Pairing[G1El, G2El, GtEl, L]
}

// NewVerifier initializes a new Verifier instance.
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] {
return &Verifier[S, G1El, G2El, GtEl]{
func NewVerifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2ElementT, GtEl algebra.G2ElementT, L algebra.LinesT](vk VerifyingKey[L], curve algebra.Curve[S, G1El], pairing algebra.Pairing[G1El, G2El, GtEl, L]) *Verifier[S, G1El, G2El, GtEl, L] {
return &Verifier[S, G1El, G2El, GtEl, L]{
VerifyingKey: vk,
curve: curve,
pairing: pairing,
Expand All @@ -238,7 +246,7 @@ func NewVerifier[S algebra.ScalarT, G1El algebra.G1ElementT, G2El algebra.G2Elem

// AssertProof asserts the validity of the opening proof for the given
// commitment.
func (vk *Verifier[S, G1El, G2El, GtEl]) AssertProof(commitment Commitment[G1El], proof OpeningProof[S, G1El]) error {
func (vk *Verifier[S, G1El, G2El, GtEl, L]) AssertProof(commitment Commitment[G1El], proof OpeningProof[S, G1El]) error {
// [f(a)]G₁
claimedValueG1 := vk.curve.ScalarMulBase(&proof.ClaimedValue)

Expand All @@ -254,9 +262,9 @@ func (vk *Verifier[S, G1El, G2El, GtEl]) AssertProof(commitment Commitment[G1El]
totalG1 = vk.curve.Add(totalG1, fminusfaG1)

// e([f(α)-f(a)+aH(α)]G₁], G₂).e([-H(α)]G₁, [α]G₂) == 1
if err := vk.pairing.DoublePairingFixedQCheck(
[2]*G1El{totalG1, negQuotientPoly},
&vk.SRS[1],
if err := vk.pairing.PairingFixedQCheck(
[]*G1El{totalG1, negQuotientPoly},
[][2][189]L{vk.SRS[0], vk.SRS[1]},
); err != nil {
return fmt.Errorf("pairing check: %w", err)
}
Expand Down
Loading

0 comments on commit 03861c5

Please sign in to comment.