One of the exciting recent developments around zk-SNARKs is that it is now possible to verify a zk-SNARK proof in a lscs (a.k.a. smart contract) on FreeTON.
Let's see how we can create a Solidity smart contract to generate proofs for that circuit on FreeTON.
Requirements: Boost >= 1.74.
git clone --recursive git@github.com:NilFoundation/ton-proof-verification-contest.git contest && cd contest
mkdir build && cd build
cmake ..
make cli
To update git submodule update --init --recursive
To create VERGRTH16
instruction input you need to represent the 'what you want to prove' in the form of a constraint
system using =nil;Crypto3 Blueprint module and then prove it using
=nil;Crypto3
ZK module. Then you can use byte-serialized output of the 'prove'
function as input to the instruction in your lscs (a.k.a. smart contract).
The =nil;Crypto3 Blueprint zk-SNARK library is a powerful library for defining circuits, generating & verifying proofs. It can be hard to get a sense of how to use it in practice, so please follow the tutorial providing a sense of the high-level components of =nil;Crypto3 Blueprint and how to use it concretely, as well as how to connect the proofs to FreeTON lscs.
If you have runned the generate and prove algorithms for Groth16, than you have all the data you need. There should be verification keys and proof in the appropriate format.
First we need to extract the verification keys and proofs from
=nil;Crypto3 Blueprint in a way that can be consumed by Solidity
smart contracts. In the file cli/src/main.cpp
we demonstrate how to serialize the information from the
objects r1cs_gg_ppzksnark<bls12<381>>::verification_key_type
and r1cs_gg_ppzksnark<bls12<381>>::proof_type
and write
that information to a file in the form of field elements that can be interpreted as byteblobs in Solidity.
We won't go into detail here about the meaning of the values A
, B
, C
etc in the proof data but check
out Vitalik's blog post to learn more. The
main thing to illustrate is that these values are elliptic curve points and hence will be represented by two elements of
the underlying field.
When running the executable cli
from within the build directory two files will be created: proof_data
and vk_data
containing the corresponding data in the form of byteblobs.
You need to use a solc compiler and tvm linker with support for these instructions:
These forks need to be built using instructions from repo.
You will need Boost
with Boost.Filesystem
module to build them.
After compilation you will have 2 files: solc
(solidity compiler) and tvm_linker
(linker).
To use these versions through tondev
:
-
you need to put these files in the directory
~/.tondev/solidity
/ -
give execution rights (
chmod +x
) to these files (otherwisetondev
will crash)
We first take a look at the Solidity file examples/solidity/verifier.sol
which contains the verification contract
code. This file contains the function verify()
, which stores incoming byteblob and gives it as input for the TVM
instruction.
This example is a simple contract which allows to verify Groth16 zk-SNARK proof using TVM.
This contract has two methods.
verification::constructor()
- method run on the contract's deploy.bool verification::verify(slice proof)
- proof packed into a slice with an inner format defined as follows.
zk-SNARK verifier bytes proof
argument contains of 3 parts packed together:
verification_key_type vk
primary_input_type primary_input
proof_type proof
Type requirements for those are described in the Groth16 zk-SNARK policy
Byte vector assumes to be byte representation of all the underlying data types, recursively unwrapped to Fp field
element and integral std::size_t
values. All the values should be putted in the same order the recursion calculated.
- Add ZKP-ready nil's network to
tondev
:tondev network add nil net.freeton.nil.foundation
- Create / Add your wallet via
tondev signer
and save your<YOU_SIGNER_PUBLIC_ADDRESS>
- Download wallet files:
wget https://raw.githubusercontent.com/tonlabs/ton-labs-contracts/master/solidity/setcodemultisig/SetcodeMultisigWallet.abi.json
wget https://github.com/tonlabs/ton-labs-contracts/raw/master/solidity/setcodemultisig/SetcodeMultisigWallet.tvc
- Get wallet address:
tondev contract info SetcodeMultisigWallet.abi.json -n nil
It should be printed as:
Address: 0:
(calculated from TVC and signer public)
- Request test token from Jury (Ask to fund this address someone in related telegram group) to
<address>
- ... Wait for it ...
- now check your balance:
tondev contract info -a 0:<address> -n nil | grep Balance
- Deploy wallet:
tondev contract deploy SetcodeMultisigWallet.abi.json constructor -n nil -i owners:"[0x<YOU_SIGNER_PUBLIC_ADDRESS>]",reqConfirms:1
You will get something like this:
Deploying... Contract has deployed at address: 0:
- Profit!
Now you have wallet and can deploy smart contracts.
Let's go to deployment step!