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.45k stars 380 forks source link

fix bn254 solidity template #1324

Open simplexity-ckcclc opened 4 days ago

simplexity-ckcclc commented 4 days ago

Description

Fixes bn254 solidity template

Type of change

How has this been tested?

How has this been benchmarked?

Checklist:

CLAassistant commented 4 days ago

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.


huangyucong seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

ivokub commented 4 days ago

Hi @simplexity-ckcclc, thanks for the contribution. Your contribution makes sense when reading diff, but I'm wondering that we haven't encountered the bug before. Do you have a regression test or a very small minified example? Don't worry if not, I'll try to create it otherwise.

simplexity-ckcclc commented 3 days ago

Hi, we write this minified circuit for test. When using the original solidity template, in the generated solidity contract below we find in line 401 the first staticcall PRECOMPILE_ADD(i.e. 0x06), the input is 64 bytes. But actually it needs two G1 points, which is 128 bytes. It fails in our evm-compatible virtual machine. We think what is doing here is adding the CONSTANT and the commitment (given that there is only one in this case). So we modify the template and it pass. So we wonder is this a bug or we do it wrong?

type testCircuit struct {
    X [2]frontend.Variable
    Y [2]frontend.Variable `gnark:",public"`
}

func (circuit *testCircuit) Define(api frontend.API) error {
    u64, err := uints.New[uints.U64](api)
    if err != nil {
        return err
    }
    u64.ByteAssertEq(u64.ByteValueOf(circuit.X[0]), u64.ByteValueOf(circuit.Y[0]))
    u64.ByteAssertEq(u64.ByteValueOf(circuit.X[1]), u64.ByteValueOf(circuit.Y[1]))
    return nil
}

func TestCircuit(t *testing.T) {
    var c testCircuit
    ccs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &c)
    pk, vk, _ := groth16.Setup(ccs)
    f, _ := os.Create("test.sol")
    vk.ExportSolidity(f, solidity.WithHashToFieldFunction(sha256.New()))
    assignment := testCircuit{X: [2]frontend.Variable([]frontend.Variable{uint('a'), uint('b')}),
        Y: [2]frontend.Variable([]frontend.Variable{uint('a'), uint('b')})}
    witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
    publicWitness, _ := witness.Public()
    proof, _ := groth16.Prove(ccs, pk, witness, backend.WithProverHashToFieldFunction(sha256.New()))
    groth16.Verify(proof, vk, publicWitness, backend.WithVerifierHashToFieldFunction(sha256.New()))
}

image