Skip to content

Commit

Permalink
docs(contract-libraries): add near_groth16_verifier documentation and CI
Browse files Browse the repository at this point in the history
  • Loading branch information
veigajoao committed Nov 30, 2022
1 parent d3d552c commit f38670e
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 6 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/near_groth16_verifier.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: near-groth16-verifier CI

on:
pull_request:
paths:
- 'packages/contract-libraries/groth_verifier/**'

env:
RUSTFLAGS: -D warnings

defaults:
run:
shell: bash
working-directory: packages/contract-libraries/groth_verifier

jobs:
test_near_bigint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2

- name: Install Rust
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
rustup component add rustfmt
rustup target add wasm32-unknown-unknown
- name: Install Yarn Globally
run: npm install -g yarn

- name: Installing Dependencies
run: yarn

- name: Tests
run: yarn test

- name: Install Audit
run: cargo install cargo-audit

- name: Run Audit
run: cargo audit --ignore RUSTSEC-2020-0071
4 changes: 4 additions & 0 deletions packages/contract-libraries/groth_verifier/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Changelog

## [1.0.0] - 2022-11-28
* Added original implementation
110 changes: 104 additions & 6 deletions packages/contract-libraries/groth_verifier/readme.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,109 @@
# Groth16 Verifier Lib for NEAR Protocol
<div align="center">

## References
<h1><code>near-groth16-verifier</code></h1>

## Using
<p>
<strong>Rust library to use verify groth16 zero knowledge proofs inside a NEAR Protocol smart contract.</strong>
</p>

### Dependencies
</div>

### Running tests
## Use cases
Applying zero knowledge cryptography inside blockchain smart contracts has been one of the most widely praised uses of this new technology. In the Ethereum ecosystem, there are many applications using zero-knowledge proofs to ensure data privacy and computational efficiency in a permissionless blockchain context.

### Using within other smart contracts
Developing this kind of applications became accessible to a normal (read not a cryptography expert) developer with libraries such as [snarky.js](https://github.com/o1-labs/snarkyjs) and [circom](https://docs.circom.io/), which simplify the construction of algorithms by abstracting away all cryptography implementation and allowing developers to only focus on business logic.
This tooling, however, is only compatible with EVM based blockchains. For developers looking to build zk-based applications on the NEAR protocol the tool was not enough.

With this in mind, we developed this library as a generic proof verifier utilizing the [groth16 algorithm](https://www.zeroknowledgeblog.com/index.php/groth16). This can be utilized together with snarky.js and circom to generate a full fledged application running zk proofs.

You can use this library as a substitute for the `Verifying from a Smart Contract` section in the [circom tutorial](https://docs.circom.io/getting-started/proving-circuits/#verifying-from-a-smart-contract).

## How to use it
To implement this Verifier in your Smart Contract you must first have setup your logical circuit and produced a trusted setup using snarky.js. This library will allow you to verify if a proof is valid or not inside the Smart Contract. To do so you must:
1. Initialize the Verifier in the Smart Contract's state by passing the setup values generated by snarky.js to it
2. Submit proofs generated by the prover binary (created by snarky.js) to the smart contract

The verifier can be implemented with a simple import:
```rust
use near_sdk::borsh::{self, BorshDeserialize, BorshSerialize};
use near_sdk::json_types::U128;
use near_sdk::{env, near_bindgen, PanicOnDefault, AccountId, BorshStorageKey};
use near_sdk::collections::{LookupSet};
use near_groth16_verifier::{self, Verifier};

#[near_bindgen]
#[derive(PanicOnDefault, BorshDeserialize, BorshSerialize)]
pub struct Contract {
pub verifier: Verifier,
}

impl Contract {
#[init]
pub fn new(
verifier: Verifier
) -> Self {
assert!(!env::state_exists(), "Already initialized");

Self {
verifier
}
}
}
```

The `Verifier` struct can be represented as a series of elliptic curve points:
```rust
#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize, Clone, Debug)]
#[serde(crate = "near_sdk::serde")]
pub struct G1Point {
pub x: U256,
pub y: U256,
}

#[derive(Serialize, Deserialize, BorshSerialize, BorshDeserialize, Clone)]
#[serde(crate = "near_sdk::serde")]
pub struct G2Point {
pub x: [U256; 2],
pub y: [U256; 2],
}

#[derive(BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Verifier {
pub alfa1: G1Point,
pub beta2: G2Point,
pub gamma2: G2Point,
pub delta2: G2Point,
pub ic: Vec<G1Point>,
pub snark_scalar_field: U256,
}
```

To fill out this values, refer to the verification_key.json file generated by snarky.js, it will provide all the parameters to initialize the `Verifier`, except for `snark_scalar_field`.

`snark_scalar_field` is the size of the scalar field used in the construction of your circuit. The standard value for this variable in snarky.js is `21888242871839275222246405745257275088548364400416034343698204186575808495617`. To better understand this parameter, please refer to the [circom documentation](https://docs.circom.io/circom-language/basic-operators/).


After initializing the verifier, it can be used to evaluate any proof in your circuit and check whether it is valid or not with the verify method.
```rust
pub fn verify(&self, input: Vec<U256>, proof: Proof) -> bool

#[derive(Serialize, Deserialize)]
#[serde(crate = "near_sdk::serde")]
pub struct Proof {
pub a: G1Point,
pub b: G2Point,
pub c: G1Point,
}
```

Proofs always follow the same structure and are generated by snarky.js when running the prover algorithm.

the `input` parameter refers to the public inputs provided to the circuit. Those must be provided as a Vec of big integers.

Snarky.js generates 2 files whenever it creates a proof:
1. public -> contains an array of values that should be passed to `input`
2. proof -> contains the `Proof` struct in json format

## Supported near-sdk versions
near-groth16-verifier is built on top of near-sdk 4.0.0 and will be updated periodically to reflect updates on near-sdk. Previous near-sdk versions are not compatible with this library.

1 comment on commit f38670e

@vercel
Copy link

@vercel vercel bot commented on f38670e Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.