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

Export types with no features enables #157

Merged
merged 33 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b8294af
Update scarb
fmkra Oct 23, 2024
a130db2
Separate fact_registry interfaces and add new feature
fmkra Oct 24, 2024
9c131d2
Re-export some types
fmkra Oct 24, 2024
e341830
Update Scarb.toml
fmkra Oct 24, 2024
19c7e80
Format
fmkra Oct 24, 2024
5a135f0
Update snfoundry
fmkra Oct 24, 2024
2d54ef5
Remove snforge_std
fmkra Oct 24, 2024
f065075
Rename cairo_verifier -> integrity
fmkra Nov 5, 2024
de62cf5
Add strict/relaxed public memory verification
fmkra Nov 8, 2024
51e2ec4
Fix CI/CD
fmkra Nov 8, 2024
d9e5e56
Fix CI/CD
fmkra Nov 8, 2024
00cee89
Rename cairo_version => memory_verification
fmkra Nov 8, 2024
4e36286
Fmt
fmkra Nov 8, 2024
7a07c4f
Update deployed contracts
fmkra Nov 8, 2024
635fcbb
Update README and comment
fmkra Nov 8, 2024
5ddde54
Implement lib utils
fmkra Nov 14, 2024
c193677
Fix runner
fmkra Nov 15, 2024
6abd258
Merge remote-tracking branch 'origin/audit' into update_scarb
fmkra Nov 18, 2024
ab8eb14
Remove lfs
fmkra Nov 18, 2024
9b345da
Fix benches
fmkra Nov 18, 2024
0ff7e2f
Remove lfs from CI/CD
fmkra Nov 18, 2024
5702c4f
example proofs
Okm165 Nov 19, 2024
ea794d0
_verifier_logic feature rename
Okm165 Nov 19, 2024
2a27aeb
Merge branch 'main' into update_scarb
fmkra Nov 19, 2024
18d3e2f
Update class hashes
fmkra Nov 19, 2024
4f3de98
Redeploy contracts
fmkra Nov 19, 2024
961ec70
Update utils
fmkra Nov 19, 2024
6b70008
Fmt
fmkra Nov 19, 2024
bc3b482
Add get_fact_registry to proxy contract
fmkra Nov 19, 2024
c467455
Update utils
fmkra Nov 19, 2024
be4cbc0
Update README
fmkra Nov 19, 2024
ce1f952
Update README
fmkra Nov 19, 2024
6e27944
README reorder
fmkra Nov 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitattributes

This file was deleted.

62 changes: 30 additions & 32 deletions .github/workflows/proof_verification_tests.yml
Original file line number Diff line number Diff line change
@@ -1,37 +1,35 @@
name: Continuous Integration - proof verification tests

on:
push:
branches:
- main
pull_request:
branches:
- main
push:
branches:
- main
pull_request:
branches:
- main

jobs:
verify-example-proofs:
runs-on: ubuntu-latest
strategy:
matrix:
cairo_version: ["cairo0", "cairo1"]
layout: ["recursive", "recursive_with_poseidon", "small", "dex", "starknet", "starknet_with_keccak"]
hash_function: ["keccak"]
hasher_bit_length: ["160_lsb"]
stone_version: ["stone5"]
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
lfs: true

- name: Setup Scarb
uses: software-mansion/setup-scarb@v1

- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1

- name: Build project
run: scarb build --no-default-features --features monolith,${{ matrix.layout }},${{ matrix.hash_function }}

- name: Run verification
run: cargo run --release --bin runner -- --program target/dev/cairo_verifier.sierra.json --cairo-version ${{ matrix.cairo_version }} --stone-version ${{ matrix.stone_version }} --hasher-bit-length ${{ matrix.hasher_bit_length }} < examples/proofs/${{ matrix.layout }}/${{ matrix.cairo_version }}_${{ matrix.stone_version }}_${{ matrix.hash_function }}_${{ matrix.hasher_bit_length }}_example_proof.json
verify-example-proofs:
runs-on: ubuntu-latest
strategy:
matrix:
memory_verification: ['cairo0', 'cairo1']
layout: ['recursive', 'recursive_with_poseidon', 'small', 'dex', 'starknet', 'starknet_with_keccak']
hash_function: ['keccak']
hasher_bit_length: ['160_lsb']
stone_version: ['stone5']
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Setup Scarb
uses: software-mansion/setup-scarb@v1

- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1

- name: Build project
run: scarb build --no-default-features --features monolith,${{ matrix.layout }},${{ matrix.hash_function }}

- name: Run verification
run: cargo run --release --bin runner -- --program target/dev/integrity.sierra.json --memory-verification ${{ matrix.memory_verification == 'cairo0' && 'strict' || 'cairo1' }} --stone-version ${{ matrix.stone_version }} --hasher-bit-length ${{ matrix.hasher_bit_length }} < examples/proofs/${{ matrix.layout }}/${{ matrix.memory_verification }}_${{ matrix.stone_version }}_${{ matrix.hash_function }}_${{ matrix.hasher_bit_length }}_example_proof.json
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scarb 2.8.2
starknet-foundry 0.30.0
scarb 2.8.4
starknet-foundry 0.32.0
170 changes: 134 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# Cairo Verifier
# Integrity

![Integrity](.github/readme.png)

[![Continuous Integration - tests](https://github.com/HerodotusDev/cairo-verifier/actions/workflows/tests.yml/badge.svg)](https://github.com/HerodotusDev/cairo-verifier/actions/workflows/tests.yml)
[![Continuous Integration - tests](https://github.com/HerodotusDev/integrity/actions/workflows/tests.yml/badge.svg)](https://github.com/HerodotusDev/cairo-verifier/actions/workflows/tests.yml)

[![Continuous Integration - proof verification tests](https://github.com/HerodotusDev/cairo-verifier/actions/workflows/proof_verification_tests.yml/badge.svg)](https://github.com/HerodotusDev/cairo-verifier/actions/workflows/proof_verification_tests.yml)
[![Continuous Integration - proof verification tests](https://github.com/HerodotusDev/integrity/actions/workflows/proof_verification_tests.yml/badge.svg)](https://github.com/HerodotusDev/cairo-verifier/actions/workflows/proof_verification_tests.yml)

Integrity is a STARK proof verifier written in cairo language and deployed on Starknet.

## Table of contents

- [Prerequisites](#prerequisites)
- [Using Verifier contracts on Starknet](#using-verifier-contracts-on-starknet)
- [FactRegistry and Proxy contract](#factregistry-and-proxy-contract)
- [Calls from Starknet contracts](#calls-from-starknet-contracts)
- [Running locally](#running-locally)
- [Creating a Proof](#creating-a-proof)
- [Deployment](#deployment)
Expand All @@ -21,10 +25,6 @@ To use the verifier with contracts deployed on Starknet, you need to have [Rust]

For running locally and development, you will need [scarb](https://docs.swmansion.com/scarb/) (we recommend using [asdf](https://asdf-vm.com/) version manager).

### Getting example proofs

Because of large size of proofs, we don't store example proofs directly in this repository, but rather in [Large File Storage](https://git-lfs.com/), so you need to have it installed and then run `git lfs pull` to get all example proofs.

## Using Verifier contracts on Starknet

Integrity verifier is deployed on Starknet and can be used for verifying proofs onchain. The intended way of using the verifier is through FactRegistry contract, which besides running the verification process, also stores data for all verified proofs. (For more information see [FactRegistry and Proxy contract](#factregistry-and-proxy-contract))
Expand All @@ -44,7 +44,7 @@ After that, you can use `verify-on-starknet.sh` script to send the transaction t
For example, run:

```bash
./verify-on-starknet.sh 0x16409cfef9b6c3e6002133b61c59d09484594b37b8e4daef7dcba5495a0ef1a examples/calldata recursive keccak_248_lsb stone5 cairo0
./verify-on-starknet.sh 0x4ce7851f00b6c3289674841fd7a1b96b6fd41ed1edc248faccd672c26371b8c examples/calldata recursive keccak_248_lsb stone5 strict
```

This bash script internally calls `verify_proof_full_and_register_fact` function on FactRegistry contract.
Expand All @@ -53,6 +53,101 @@ This bash script internally calls `verify_proof_full_and_register_fact` function

To generate split calldata, please refer to [Calldata Generator README](https://github.com/HerodotusDev/integrity-calldata-generator/blob/main/README.md). This repository also provides script for automatic transaction sending (proof verification is split into multiple transactions, for more information see [Split Verifier Architecture](#split-verifier-architecture)).

## FactRegistry and Proxy contract

Since verifier can be configured in many ways and some parts of the logic changes with new stone versions, a contract which routes calls to the correct verifier is needed. This task is handled by FactRegistry contract that also stores data for all verified proofs.

After proof is verified, `FactRegistered` event is emitted which contains `fact_hash`, `verification_hash`, `security_bits` and `settings`. `fact_hash` is a value that represents proven program and its output (formally `fact_hash = poseidon_hash(program_hash, output_hash)`). Remember that registration of some `fact_hash` doesn't necessary mean that it has been verified by someone with secure enough proof. You always need to check `security_bits` and `settings` which is part of `verification_hash` (formally `verification_hash = poseidon_hash(fact_hash, security_bits, settings)`).

For more detailed and visual representation of those hash calculations, check out [Integrity Hashes Calculator](https://integrity-hashes-calculator.vercel.app/) tool. It generates all mentioned hashes for arbitrary user input and even proof JSON file.

`FactRegistry` provides two methods for checking verified proofs:

- `get_verification(verification_hash)` - returns fact hash, security bits and settings for given `verification_hash`.
- `get_all_verifications_for_fact_hash(fact_hash)` - returns list of all verification hashes, security bits and settings for given `fact_hash`. This method is useful for checking if given program has been verified by someone with secure enough proof.

FactRegistry contract is trustless which means that the owner of the contract can't override or change any existing behavior, they can only add new verifiers. Proxy contract on the other hand is upgradable, so every function can be changed or removed. It has the advantage of having all future updates of the verifier logic without having to replace the address of FactRegistry contract. Proxy contract provides the same interface as FactRegistry with additional `get_fact_registry` method which returns address of FactRegistry contract.

## Calls from Starknet contracts

Since integrity is deployed on Starknet, other contracts can call FactRegistry to check whether certain proof has been verified. Integrity can be used as a dependency of your cairo1 project by including it in project's `Scarb.toml`:

```toml
[dependencies]
integrity = { git = "https://github.com/HerodotusDev/integrity" }
```

The package provides many utility functions for interacting with the verifier. For contract calls, you can use `Integrity` struct which provides following methods:

- `new() -> Integrity` - creates new interface for interacting with official FactRegistry (contract address is set automatically).
- `new_proxy() -> Integrity` - creates new interface using official Proxy contract (contract address is set automatically).
- `from_address(address: ContractAddress) -> Integrity` - create new interface using custom FactRegistry deployment.
- `is_fact_hash_valid_with_security(self: Integrity, fact_hash: felt252, security_bits: u32) -> bool` - checks if given `fact_hash` has been verified with at least `security_bits` number of security bits.
- `is_verification_hash_valid(self: Integrity, verification_hash: felt252) -> bool` - checks if given `verification_hash` has been verified.
- `with_config(self: Integrity, verifier_config: VerifierConfiguration, security_bits: u32) -> IntegrityWithConfig` - returns new interface with custom verifier configuration.
- `with_hashed_config(self: Integrity, verifier_config_hash: felt252, security_bits: u32) -> IntegrityWithConfig` - returns new interface with custom verifier configuration given its hash.

On `IntegrityWithConfig` interface you can call:

- `is_fact_hash_valid(self: IntegrityWithConfig, fact_hash: felt252) -> bool` - checks if given `fact_hash` has been verified with selected config.

There are also few utility function for calculating hashes:

- `get_verifier_config_hash(verifier_config: VerifierConfiguration) -> felt252` - calculates hash for given verifier configuration, which is used necessary for calculating verification hash.
- `get_verification_hash(fact_hash: felt252, verifier_config_hash: felt252, security_bits: u32) -> felt252` - calculates verification hash for given `fact_hash`, `verifier_config_hash` and `security_bits`.
- `calculate_fact_hash(program_hash: felt256, output: Span<felt252>) -> felt252` - calculates fact hash for given `program_hash` and `output` array.
- `calculate_bootloaded_fact_hash(bootloader_program_hash: felt252, child_program_hash: felt252, child_output: Span<felt252>) -> felt252` - calculates fact hash for program that was bootloaded with standard bootloader.

Available constants are:

- `INTEGRITY_ADDRESS` - address of official FactRegistry contract deployed on Starknet Sepolia
- `PROXY_ADDRESS` - address of official Proxy contract deployed on Starknet Sepolia
- `SHARP_BOOTLOADER_PROGRAM_HASH` - program hash of the bootloader used by SHARP prover
- `STONE_BOOTLOADER_PROGRAM_HASH` - program hash of [TODO LINK]

Example:

```
use integrity::{Integrity, IntegrityWithConfig, calculate_bootloaded_fact_hash, SHARP_BOOTLOADER_PROGRAM_HASH, VerifierConfiguration};

fn is_fibonacci_verified(fib_index: felt252, fib_value: felt252) -> bool {
let SECURITY_BITS = 70;
let fibonacci_program_hash = 0x59874649ccc5a0a15ee77538f1eb760acb88cab027a2d48f4246bf17b7b7694;
let fact_hash = calculate_bootloaded_fact_hash(
SHARP_BOOTLOADER_PROGRAM_HASH, fibonacci_program_hash, [fib_index, fib_value].span()
);

let integrity = Integrity::new();
integrity.is_fact_hash_valid_with_security(fact_hash, SECURITY_BITS)
}

fn is_multi_fibonacci_verified(fib: Span<(felt252, felt252)>) -> bool {
let config = VerifierConfiguration {
layout: 'recursive_with_poseidon',
hasher: 'keccak_160_lsb',
stone_version: 'stone6',
memory_verification: 'relaxed',
};
let SECURITY_BITS = 96;
let fibonacci_program_hash = 0x59874649ccc5a0a15ee77538f1eb760acb88cab027a2d48f4246bf17b7b7694;

let integrity = Integrity::new().with_config(config, SECURITY_BITS);

let mut ret = true;
for f in fib {
let (fib_index, fib_value) = *f;
let fact_hash = calculate_bootloaded_fact_hash(
SHARP_BOOTLOADER_PROGRAM_HASH, fibonacci_program_hash, [fib_index, fib_value].span()
);

if !integrity.is_fact_hash_valid(fact_hash) {
ret = false;
}
};
ret
}
```

## Running locally

To run the verifier locally, first you need to build cairo project using:
Expand All @@ -69,8 +164,8 @@ You can use cairo runner to run the verifier on example proof:

```bash
cargo run --release --bin runner -- \
--program target/dev/cairo_verifier.sierra.json \
--cairo-version cairo0 \
--program target/dev/integrity.sierra.json \
--memory-verification strict \
--stone-version stone5 \
--hasher-bit-length 160_lsb \
< examples/proofs/recursive/cairo0_stone5_keccak_160_lsb_example_proof.json
Expand All @@ -84,21 +179,41 @@ By default, the verifier is configured for monolith version, recursive layout an
scarb build --no-default-features --features small,blake2s,monolith
```

`layout`: [`dex`, `recursive`, `recursive_with_poseidon`, `small`, `starknet`, `starknet_with_keccak`]<br />
hash functions: [`keccak`, `blake2s`]<br />
verifier types: [`monolith`, `split`]
- `layout`
- `dex`
- `recursive`
- `recursive_with_poseidon`
- `small`
- `starknet`
- `starknet_with_keccak`
- hash functions:
- `keccak`
- `blake2s`
- verifier types
- `monolith`
- `split`

There are also additional settings that can be configured at runtime:

`cairo_version`: [`cairo0`, `cairo1`]<br />
`stone_version`: [`stone5`, `stone6`]<br />
hasher bit length: [`160_lsb`, `248_lsb`]
- `memory_verification`
- `strict`
- `relaxed`
- `cairo1`
- `stone_version`
- `stone5`
- `stone6`
- hasher bit length
- `160_lsb`
- `248_lsb`

Hash function and hasher bit length are combined into one setting:

`hasher`: [`keccak_160_lsb`, `blake2s_160`, `blake2s_248_lsb`]
- `hasher`
- `keccak_160_lsb`
- `blake2s_160`
- `blake2s_248_lsb`

For `stone5` available `hasher`s are `keccak_160_lsb` and `blake2s_160`, for `stone6` - `keccak_160_lsb` and `blake2s_248_lsb`.
For `stone5` available hashers are `keccak_160_lsb` and `blake2s_160`, for `stone6` - `keccak_160_lsb` and `blake2s_248_lsb`.

### Running tests

Expand All @@ -113,7 +228,7 @@ scarb test
In order to launch benchmarking, just run this (it requires recursive layout configuration):

```bash
cargo run --release --bin benches -- target/dev/cairo_verifier.sierra.json
cargo run --release --bin benches -- target/dev/integrity.sierra.json
```

## Creating a Proof
Expand Down Expand Up @@ -154,27 +269,10 @@ bash deployment/verifiers/<layout>/<hasher>/register.sh

## Split Verifier Architecture

### Background information

Because of great complexity of the verifier compared to standard starknet contracts, we encounter some limitations enforced by starknet. The most important ones are:

- Contract classhash size limit
- Transaction calldata limit
- Transaction steps limit

To overcome these limitations, we split the verifier into multiple contracts and transactions. The biggest part of classhash size is autogenerated (e.g. [recursive autogenerated](/src/air/layouts/recursive/autogenerated.cairo)), so we extracted that part into separate contract (or many contracts in case of `starknet_with_keccak` layout), which is called automatically by the main verifier contract. On the other hand the biggest part of calldata is fri witness, so user can send subsequent chunks of fri witness in separate step transactions.

### FactRegistry and Proxy contract

Since verifier can be configured in many ways and some parts of the logic changes with new stone versions, a contract which routes calls to the correct verifier is needed. This task is handled by FactRegistry contract that also stores data for all verified proofs.

After proof is verified, `FactRegistered` event is emitted which contains `fact_hash`, `verification_hash`, `security_bits` and `settings`. `fact_hash` is a value that represents proven program and its output (formally `fact_hash = poseidon_hash(program_hash, output_hash)`). Remember that registration of some `fact_hash` doesn't necessary mean that it has been verified by someone with secure enough proof. You always need to check `security_bits` and `settings` which is part of `verification_hash` (formally `verification_hash = poseidon_hash(fact_hash, security_bits, settings)`).

`FactRegistry` provides two methods for checking verified proofs:

- `get_verification(verification_hash)` - returns fact hash, security bits and settings for given `verification_hash`.
- `get_all_verifications_for_fact_hash(fact_hash)` - returns list of all verification hashes, security bits and settings for given `fact_hash`. This method is useful for checking if given program has been verified by someone with secure enough proof.

FactRegistry contract is trustless which means that the owner of the contract can't override or change any existing behavior, they can only add new verifiers. Proxy contract on the other hand is upgradable, so every function can be changed or removed. It has the advantage of having all future updates of the verifier logic without having to replace the address of FactRegistry contract.

TODO: how to read FactRegistered event
21 changes: 11 additions & 10 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
[package]
name = "cairo_verifier"
name = "integrity"
version = "0.1.0"

[dependencies]
starknet = "2.8.2"
starknet = "2.8.4"

[dev-dependencies]
cairo_test = "2.8.2"
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.27.0" }
cairo_test = "2.8.4"

[[target.starknet-contract]]
casm = true
Expand All @@ -19,12 +18,14 @@ casm = false

[features]

recursive = []
recursive_with_poseidon = []
dex = []
small = []
starknet = []
starknet_with_keccak = []
_verifier_logic = []

recursive = ["_verifier_logic"]
recursive_with_poseidon = ["_verifier_logic"]
dex = ["_verifier_logic"]
small = ["_verifier_logic"]
starknet = ["_verifier_logic"]
starknet_with_keccak = ["_verifier_logic"]

keccak = []
blake2s = []
Expand Down
2 changes: 1 addition & 1 deletion benches/src/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub fn bench(sierra_program: Program, function: &str) -> Result<RunResultStarkne
let func = runner.find_function(function).unwrap();
runner.run_function_with_starknet_context(
func,
&[],
vec![],
Some(u32::MAX as usize),
Default::default(),
)
Expand Down
Loading
Loading