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.44k stars 369 forks source link

How to represent a 2D array of frontend.Variables? #798

Closed drakstik closed 1 year ago

drakstik commented 1 year ago

Hi, I am trying to work with 2D arrays, but I get this error:

16:26:11 INF compiling circuit
16:26:11 INF parsed circuit inputs nbPublic=9 nbSecret=9
16:26:11 INF building constraint builder nbConstraints=1
16:26:11 WRN circuit has unconstrained inputs
panic: unrecognized R1CS curve type

goroutine 1 [running]:
github.com/consensys/gnark/backend/groth16.Setup({0x0?, 0x0?})
        /home/x/go/pkg/mod/github.com/consensys/gnark@v0.8.0/backend/groth16/groth16.go:286 +0x4a5
main.main()
        /home/x/PhotoProof/src/main.go:289 +0x7c
exit status 2

This is the simple main.go code I'm running:

func main() {
    // compiles our circuit into a R1CS
    var circuit Matrix
    ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)

    // groth16 zkSNARK: Setup
    pk, vk, _ := groth16.Setup(ccs)

    // witness definition

    a := [3][3]frontend.Variable{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

    b := [3][3]frontend.Variable{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

    assignment := Matrix{X: a, Y: b} // X is secret, Y is public.
    witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
    publicWitness, _ := witness.Public()

    // groth16: Prove & Verify
    proof, _ := groth16.Prove(ccs, pk, witness) // This proof can be sent alongside verification and public witness Y (i.e. the output).
    groth16.Verify(proof, vk, publicWitness)
}

// A Matrix consists of two fields N=16
type Matrix struct {
    X [3][3]frontend.Variable `gnark:"X, secret"` // X = [N*N]frontend.Variable
    Y [3][3]frontend.Variable `gnark:",public"`
}

func (circuit *Matrix) Define(api frontend.API) error {
    api.AssertIsEqual(circuit.Y[0][2], circuit.X[0][2])
    return nil
}

It fails at the "pk, vk, _ := groth16.Setup(ccs)" line in the main function.

I do not know if this is the same issue as #236 but please help!

gbotrel commented 1 year ago

hi -- can you reproduce on develop; (I can't). v0.9.0 (merge develop into master) is coming and may fix your issue.

drakstik commented 1 year ago

hi -- can you reproduce on develop; (I can't). v0.9.0 (merge develop into master) is coming and may fix your issue.

I just reproduced it on v0.9.0. The problem is still there. Can't use 2D arrays, at least not this way.

Are we allowed to define a struct in this manner in Gnark?

type Matrix struct {
    X [3][3]frontend.Variable `gnark:"X, secret"` // X = [N*N]frontend.Variable
    Y [3][3]frontend.Variable `gnark:",public"`
}

If yes and you cannot reproduce the error on your side, what versions are you using? Also, by develop do you mean this branch?: https://github.com/Consensys/gnark/tree/thedarkjester-develop

ivokub commented 1 year ago

Yes, it is allowed. I think you have some dependency mismatch or maybe you are not running the code in the example?

I did

mkdir matrix
cd matrix
go mod init matrix
go get github.com/consensys/gnark
# create main.go as below
go mod tidy
go run main.go

file main.go

package main

import (
        "github.com/consensys/gnark-crypto/ecc"
        "github.com/consensys/gnark/backend/groth16"
        "github.com/consensys/gnark/frontend"
        "github.com/consensys/gnark/frontend/cs/r1cs"
)

func main() {
        // compiles our circuit into a R1CS
        var circuit Matrix
        ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)

        // groth16 zkSNARK: Setup
        pk, vk, _ := groth16.Setup(ccs)

        // witness definition

        a := [3][3]frontend.Variable{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

        b := [3][3]frontend.Variable{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}

        assignment := Matrix{X: a, Y: b} // X is secret, Y is public.
        witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
        publicWitness, _ := witness.Public()

        // groth16: Prove & Verify
        proof, _ := groth16.Prove(ccs, pk, witness) // This proof can be sent alongside verification and public witness Y (i.e. the output).
        groth16.Verify(proof, vk, publicWitness)
}

// A Matrix consists of two fields N=16
type Matrix struct {
        X [3][3]frontend.Variable `gnark:"X, secret"` // X = [N*N]frontend.Variable
        Y [3][3]frontend.Variable `gnark:",public"`
}

func (circuit *Matrix) Define(api frontend.API) error {
        api.AssertIsEqual(circuit.Y[0][2], circuit.X[0][2])
        return nil
}
drakstik commented 1 year ago

Awesome, it worked. I did have dependency issues! Thanks for the fast response.