Consensys / gnark

gnark is a fast zk-SNARK library that offers a high-level API to design circuits. The library is open source and developed under the Apache 2.0 license
https://hackmd.io/@gnark
Apache License 2.0
1.43k stars 368 forks source link

Refactor 2-Chain std API #607

Closed tumberger closed 1 year ago

tumberger commented 1 year ago

Following the PR #561 from @gbotrel;

Problem

Currently, the Groth16 verifier for recursion over 2-Chains of elliptic curves only exposes Verify() and Assign(). Assigning the proof requires access to the internal package in the master branch.

561 addresses this issue to make third party workflow and integration easier.

However, from a developer perspective, it's still required to work with curve specific variables.

var innerVk groth16_bls12377.VerifyingKey
var innerProof groth16_bls12377.Proof

Solution

I'd suggest additionally exposing an API for proof assignment, as follows:

// Assign the proof values of Groth16
func (proof *Proof) Assign(_oproof groth16.Proof) {
    oproof, ok := _oproof.(*groth16_bls12377.Proof)
    if !ok {
        panic("expected *groth16_bls12377.Proof, got " + reflect.TypeOf(oproof).String())
    }
    proof.Ar.Assign(&oproof.Ar)
    proof.Krs.Assign(&oproof.Krs)
    proof.Bs.Assign(&oproof.Bs)
}

This would allow for simple usage of the generic Groth16 object rather than curve specific libraries. I believe that this would improve the usability of the provided tools for recursion in other libraries. It also removes the need for the developer to understand Groth16 inner workings.

func TestVerifier(t *testing.T) {

    // create a mock cs: knowing the preimage of a hash using mimc
    var MimcCircuit mimcCircuit
    r1cs, err := frontend.Compile(ecc.BLS12_377.ScalarField(), r1cs.NewBuilder, &MimcCircuit)
    if err != nil {
        t.Fatal(err)
    }

    var pre_assignment mimcCircuit
    pre_assignment.PreImage = preImage
    pre_assignment.Hash = publicHash
    pre_witness, err := frontend.NewWitness(&pre_assignment, ecc.BLS12_377.ScalarField())
    if err != nil {
        t.Fatal(err)
    }

    innerPk, innerVk, err := groth16.Setup(r1cs)
    if err != nil {
        t.Fatal(err)
    }

    proof, err := groth16.Prove(r1cs, innerPk, pre_witness)
    if err != nil {
        t.Fatal(err)
    }

    publicWitness, err := pre_witness.Public()
    if err != nil {
        t.Fatal(err)
    }

    // Check that proof verifies before continuing
    if err := groth16.Verify(proof, innerVk, publicWitness); err != nil {
        t.Fatal(err)
    }

    var circuit verifierCircuit
    circuit.InnerVk.FillG1K(innerVk)

    var witness verifierCircuit
    witness.InnerProof.Assign(proof)
    witness.InnerVk.Assign(innerVk)
    witness.Hash = preComputeMimc(preImage)

    assert := test.NewAssert(t)

    assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BW6_761), test.WithBackends(backend.GROTH16))
}

Forked the library and made the quick fix here. Also, added FillG1K to remove the need to use any curves specific library, i.e. groth16_bls12377.

// Fill one point for inner verifying key
func (vk *VerifyingKey) FillG1K(_ovk groth16.VerifyingKey) {
    ovk, ok := _ovk.(*groth16_bls12377.VerifyingKey)
    if !ok {
        panic("expected *groth16_bls12377.VerifyingKey, got " + reflect.TypeOf(_ovk).String())
    }
    vk.G1.K = make([]sw_bls12377.G1Affine, len(ovk.G1.K))
}

Proposition

In summary, instead of exposing

func Verify(api frontend.API, vk VerifyingKey, proof Proof, publicInputs []frontend.Variable)
func (vk *VerifyingKey) Assign(_ovk groth16.VerifyingKey)

do sth like

func Verify(api frontend.API, vk VerifyingKey, proof Proof, publicInputs []frontend.Variable)
func (vk *VerifyingKey) Assign(_ovk groth16.VerifyingKey)
func (vk *VerifyingKey) FillG1K(_ovk groth16.VerifyingKey)
func (proof *Proof) Assign(_oproof groth16.Proof)
yelhousni commented 1 year ago

@tumberger That makes sense. Can you make a PR that upstreams the fix in your fork to gnark?

yelhousni commented 1 year ago

@tumberger That makes sense. Can you make a PR that upstreams the fix in your fork to gnark?

Drafted a quick PR that ports your suggestions + some consolidating/perf work on the pairing side.

tumberger commented 1 year ago

Great, sounds good to me! Anything you'd like me to still add?

yelhousni commented 1 year ago

Great, sounds good to me! Anything you'd like me to still add?

I think we're good to close this issue. Thanks!