Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

smartcontract, examples: add API for Groth16 Verifier contract building and examples #3043

Merged
merged 12 commits into from
Oct 5, 2023

Conversation

AnnaShaleva
Copy link
Member

@AnnaShaleva AnnaShaleva commented Jun 14, 2023

Three major improvements are included into this PR:

  1. Add zkpbinding package that exports API to generate and interact with circuit-cpecific (and Groth-16 parameters-specific) Verifier Go smart contract. This API is assumed to be used by smart contract developers who wants to verify some ZK proofs on Neo.
  2. Add an example of Verifier contract generation and proof generation/verification for a simple cubic circuit with the help of https://github.com/Consensys/gnark, zkpbinding package and neotest.
  3. Port the Add zkp in neo neo-project/neo#2647 (comment) example from the C# to Go and invoke it with exactly the same proof and witnesses. This example is added to ensure that NeoGo BLS12-381 interoperability is compatible with the C# implementation. This example is not for the external users.

Close #3002.

TODO:

  • Properly deal with scalar multipliers form.
  • Add clear and concise documentation.
  • Update interop deps (after PR finalization and all conversations resolving).

@codecov
Copy link

codecov bot commented Jun 14, 2023

Codecov Report

Merging #3043 (fc6e87a) into master (4598f3d) will increase coverage by 0.02%.
The diff coverage is 0.00%.

@@            Coverage Diff             @@
##           master    #3043      +/-   ##
==========================================
+ Coverage   84.89%   84.92%   +0.02%     
==========================================
  Files         330      330              
  Lines       44332    44332              
==========================================
+ Hits        37637    37649      +12     
+ Misses       5180     5168      -12     
  Partials     1515     1515              
Files Coverage Δ
pkg/core/native/crypto.go 84.23% <ø> (ø)
pkg/core/native/crypto_blspoints.go 57.57% <0.00%> (+4.32%) ⬆️

... and 3 files with indirect coverage changes

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@AnnaShaleva
Copy link
Member Author

We have to think about moving Verifier contract auto-generation to a separate package so that contract devs are able to use it from the outside to generate their own verification contracts without massive copy-pasting. @roman-khimov, what do you think?

And with Consensys/gnark#799, the generator-related code will be much simplier.

@AnnaShaleva AnnaShaleva changed the title examples: add compatibility example for Groth16 verification examples: add examples for Groth16 verification Jul 29, 2023
@AnnaShaleva AnnaShaleva changed the title examples: add examples for Groth16 verification smartcontract, examples: add API for Groth16 Verifier contract building and examples Aug 3, 2023
@AnnaShaleva AnnaShaleva force-pushed the groth16-verify-compat branch 2 times, most recently from d4e63bd to a247fc9 Compare August 3, 2023 12:07
@AnnaShaleva AnnaShaleva marked this pull request as ready for review August 3, 2023 12:09
@AnnaShaleva AnnaShaleva added smartcontract Smart contracts and associated package enhancement Improving existing functionality labels Aug 3, 2023
@AnnaShaleva AnnaShaleva force-pushed the groth16-verify-compat branch 2 times, most recently from 4e540e5 to 00d278e Compare August 3, 2023 12:22
@AnnaShaleva
Copy link
Member Author

@roman-khimov, could you, please, review the PR? We need to finalize the external smartcontract's generator API, let's fix the issues if there are any.

pkg/core/native/crypto.go Outdated Show resolved Hide resolved
examples/zkp/xor_compat/go.mod Outdated Show resolved Hide resolved
examples/zkp/xor_compat/go.mod Outdated Show resolved Hide resolved
examples/zkp/xor_compat/verify.go Outdated Show resolved Hide resolved
examples/zkp/xor_compat/verify.go Outdated Show resolved Hide resolved
examples/zkp/cubic_circuit/main.go Outdated Show resolved Hide resolved
examples/zkp/cubic_circuit/main.go Show resolved Hide resolved
pkg/smartcontract/zkpbinding/binding.go Outdated Show resolved Hide resolved
pkg/smartcontract/zkpbinding/binding.go Outdated Show resolved Hide resolved
pkg/smartcontract/zkpbinding/binding.go Show resolved Hide resolved
@AnnaShaleva AnnaShaleva force-pushed the groth16-verify-compat branch 2 times, most recently from fec8386 to 48010df Compare September 22, 2023 17:20
@AnnaShaleva
Copy link
Member Author

Not ready for review yet, will test against the C# node and update.

@AnnaShaleva
Copy link
Member Author

I've tested it on testnet (carefully with preliminary test Verify execution and result check). Here's the test:

func TestCubicCircuit_Compat(t *testing.T) {
	var (
		circuit    CubicCircuit
		assignment = CubicCircuit{X: 3, Y: 35}
	)

	// Compile our circuit into a R1CS (a constraint system).
	ccs, err := frontend.Compile(ecc.BLS12_381.ScalarField(), r1cs.NewBuilder, &circuit)
	require.NoError(t, err)

	// One time setup (groth16 zkSNARK).
	pk, vk, err := groth16.Setup(ccs)
	require.NoError(t, err)

	// Intermediate step: witness definition.
	witness, err := frontend.NewWitness(&assignment, ecc.BLS12_381.ScalarField())
	require.NoError(t, err)
	publicWitness, err := witness.Public()
	require.NoError(t, err)

	// Proof creation (groth16).
	proof, err := groth16.Prove(ccs, pk, witness)
	require.NoError(t, err)

	// Ensure that gnark can successfully verify the proof (just in case).
	err = groth16.Verify(proof, vk, publicWitness)
	require.NoError(t, err)

	// Now, when we're sure that the proof is valid, we can create and deploy verification
	// contract to the Neo testing chain.
	args, err := zkpbinding.GetVerifyProofArgs(proof, publicWitness)
	require.NoError(t, err)

	// Create contract file.
	tmpDir := t.TempDir()
	srcPath := filepath.Join(tmpDir, "verify.go")
	f, err := os.Create(srcPath)
	require.NoError(t, err)

	// Create contract configuration file.
	cfgPath := filepath.Join(tmpDir, "verify.yml")
	fCfg, err := os.Create(cfgPath)
	require.NoError(t, err)

	// Create contract go.mod and go.sum files.
	fMod, err := os.Create(filepath.Join(tmpDir, "go.mod"))
	require.NoError(t, err)
	fSum, err := os.Create(filepath.Join(tmpDir, "go.sum"))
	require.NoError(t, err)

	err = zkpbinding.GenerateVerifier(zkpbinding.Config{
		VerifyingKey: vk,
		Output:       f,
		CfgOutput:    fCfg,
		GomodOutput:  fMod,
		GosumOutput:  fSum,
	})
	require.NoError(t, err)

	require.NoError(t, f.Close())
	require.NoError(t, fCfg.Close())
	require.NoError(t, fMod.Close())
	require.NoError(t, fSum.Close())

	// rpcUrl := "https://rpc.t5.n3.nspcc.ru:20331"
	rpcUrl := "http://seed1t5.neo.org:20332"
	c, err := rpcclient.New(context.Background(), rpcUrl, rpcclient.Options{})
	require.NoError(t, err)
	require.NoError(t, c.Init())

	w, err := wallet.NewWalletFromFile("../../../n3testnet.json")
	require.NoError(t, err)
	acc := w.Accounts[0]
	require.NoError(t, acc.Decrypt("qwerty", w.Scrypt))

	s := transaction.Signer{
		Account: acc.ScriptHash(),
		Scopes:  transaction.CalledByEntry,
	}
	act, err := actor.New(c, []actor.SignerAccount{{
		Signer:  s,
		Account: acc,
	}})
	require.NoError(t, err)
	man := management.New(act)

	ctr := neotest.CompileFile(t, acc.ScriptHash(), srcPath, cfgPath)
	fmt.Println(ctr.Hash.StringLE())
	res, err := act.Wait(man.Deploy(ctr.NEF, ctr.Manifest, nil))
	require.NoError(t, err)
	require.Equal(t, vmstate.Halt, res.VMState, res.FaultException)

	res, err = act.Wait(act.SendCall(ctr.Hash, "verifyProof", args.A, args.B, args.C, args.PublicWitnesses))
	require.NoError(t, err)
	require.Equal(t, vmstate.Halt, res.VMState, res.FaultException)
	require.True(t, res.Stack[0].Value().(bool))
	fmt.Println(res.Container.StringLE())
}

Here's the contract: https://dora.coz.io/contract/neo3/testnet/c110099c025aadf10b5f4d6af32c65efd5268135
Here's the transaction (it pushes True on stack for both nodes): https://dora.coz.io/transaction/neo3/testnet/87a02195b611e4898275c2d21fb7d62ff60bef3a538bd8d54d47c7f20445cfec

So the bls12381Mul NeoGo implementation matches the NeoC# one.

@AnnaShaleva AnnaShaleva marked this pull request as draft September 25, 2023 11:04
AnnaShaleva added a commit that referenced this pull request Oct 4, 2023
…t multiplier

Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: #3043 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
AnnaShaleva added a commit that referenced this pull request Oct 4, 2023
…t multiplier

Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: #3043 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
AnnaShaleva added a commit that referenced this pull request Oct 4, 2023
…t multiplier

Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: #3043 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
Port the C# contract provided in the
neo-project/neo#2647 (comment) and
add an integration test for it. Part of the #3002.

Signed-off-by: Anna Shaleva <[email protected]>
AnnaShaleva added a commit that referenced this pull request Oct 5, 2023
…t multiplier

Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: #3043 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
The example shows that the proover knows the solution of the cubic
equation: y = x^3 + x + 5. The example is constructed for BLS12-381
curve points using Groth-16 prooving algorithm. The example includes
everything that developer needs to start using ZKP on the NEO platform
with Go SDK:
1. The described cubic circuit implementation.
2. The off-chain proof generation with the help of gnark-crypto library.
3. Go verification contract generation and deployment with the help of
   NeoGo libraries.
4. The on-chain proof verification for various sets of input data.

Signed-off-by: Anna Shaleva <[email protected]>
AnnaShaleva added a commit that referenced this pull request Oct 5, 2023
…t multiplier

Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: #3043 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
@AnnaShaleva AnnaShaleva force-pushed the groth16-verify-compat branch 2 times, most recently from 8ace218 to a964b21 Compare October 5, 2023 10:35
@AnnaShaleva AnnaShaleva marked this pull request as ready for review October 5, 2023 10:37
@AnnaShaleva
Copy link
Member Author

Linter is also fixed, the issue was caused by an update to gnark v0.9.0 in the core library. v0.9.0 requires go 1.19, and we still support go 1.18. Thus, #3079 is left unclosed until we'll bump minimum required go version for neo-go.

@AnnaShaleva AnnaShaleva marked this pull request as draft October 5, 2023 10:41
Add an example and instructions for production CRS generation to ZKP examples
with gnark >= v0.9.0.

Signed-off-by: Anna Shaleva <[email protected]>
An upgrade from gnark v0.8.X to v0.9.0 changes serialization format of verifying/proving keys
and proofs. In neo-go zkpbinding package we have to support both at least for now, because
[email protected] requires minimum go 1.19.

Signed-off-by: Anna Shaleva <[email protected]>
It's not differ from BN254, but we'd better use the proper package.

Signed-off-by: Anna Shaleva <[email protected]>
…t multiplier

Field element multiplier must be provided in the LE form, confirmed by
cross-node invocation: #3043 (comment).

Signed-off-by: Anna Shaleva <[email protected]>
And ignore on dependency checks, we update all the examples at once
anyway, so may safely skip the check for zkp folder.

Signed-off-by: Anna Shaleva <[email protected]>
Signed-off-by: Anna Shaleva <[email protected]>
@AnnaShaleva AnnaShaleva marked this pull request as ready for review October 5, 2023 10:47
@AnnaShaleva
Copy link
Member Author

Dependencies are updated as far.

@roman-khimov roman-khimov merged commit 91c928e into master Oct 5, 2023
13 of 18 checks passed
@roman-khimov roman-khimov deleted the groth16-verify-compat branch October 5, 2023 10:58
AnnaShaleva added a commit that referenced this pull request Oct 5, 2023
Should be a part of #3043.

Signed-off-by: Anna Shaleva <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improving existing functionality smartcontract Smart contracts and associated package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add an example for ZKP
2 participants