Skip to content

Commit

Permalink
Merge pull request #130 from delaaxe/feat/cairo1
Browse files Browse the repository at this point in the history
Support Cairo1 proof verification
  • Loading branch information
Okm165 authored Jun 11, 2024
2 parents a29acce + e9c5d6b commit d1a0a51
Show file tree
Hide file tree
Showing 18 changed files with 1,604 additions and 62 deletions.
36 changes: 35 additions & 1 deletion .github/workflows/proof_verification_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,38 @@ jobs:
run: scarb test

- name: Run verification
run: cargo run --release --bin runner -- target/dev/cairo_verifier.sierra.json < examples/proofs/${{ matrix.layout }}/example_proof.json
run: cargo run --release --bin runner -- target/dev/cairo_verifier.sierra.json 0 < examples/proofs/${{ matrix.layout }}/example_proof.json

verify-proof-cairo1:
runs-on: ubuntu-latest
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: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.10'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Configure layout
run: python configure.py -l recursive -s keccak

- name: Build project
run: scarb build

- name: Test project
run: scarb test

- name: Run verification
run: cargo run --release --bin runner -- target/dev/cairo_verifier.sierra.json 1 < examples/proofs/recursive_cairo1/example_proof.json
5 changes: 4 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ jobs:
run: scarb fmt --check

- name: Run tests
run: scarb test
run: scarb test

- name: Build fact registry
run: (cd fact_registry && scarb build)
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scarb nightly-2024-03-16
scarb 2.6.3
starknet-foundry 0.20.1
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ scarb test

For local proof verification, follow these steps:

1. Run the verifier locally on example proof using the following command:
1. Run the verifier locally using the following command on example proof, followed by the Cairo version of the circuit (0 or 1) used to generate the proof:

```bash
cargo run --release --bin runner -- target/dev/cairo_verifier.sierra.json < examples/proofs/recursive/example_proof.json
cargo run --release --bin runner -- target/dev/cairo_verifier.sierra.json 0 < examples/proofs/recursive/example_proof.json
```

### Starknet Proof Verification
Expand Down
1,423 changes: 1,423 additions & 0 deletions examples/proofs/recursive_cairo1/example_proof.json

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions examples/starknet/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use cairo_proof_parser::parse;
use itertools::{chain, Itertools};
use itertools::chain;
use runner::VecFelt252;
use std::io::{stdin, Read};

Expand All @@ -20,16 +20,18 @@ fn main() -> anyhow::Result<()> {
public_input.into_iter(),
unsent_commitment.into_iter(),
witness.into_iter()
)
.collect_vec();
);

let proof_string = proof
.iter()
let cairo_version = 0; // TODO: pass as argument

let calldata = chain!(proof, vec![cairo_version.into()].into_iter());

let calldata_string = calldata
.map(|f| f.to_string())
.collect::<Vec<String>>()
.join(" ");

println!("{}", proof_string);
println!("{}", calldata_string);

Ok(())
}
30 changes: 18 additions & 12 deletions fact_registry/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
mod verifier;

use cairo_verifier::StarkProofWithSerde;
use cairo_verifier::{StarkProofWithSerde, CairoVersion};
use starknet::ContractAddress;

#[starknet::interface]
trait IFactRegistry<TContractState> {
fn verify_and_register_fact(ref self: TContractState, stark_proof: StarkProofWithSerde);
fn verify_and_register_fact(
ref self: TContractState, stark_proof: StarkProofWithSerde, cairo_version: CairoVersion
);
fn verify_and_register_fact_from_contract(
ref self: TContractState, contract_address: ContractAddress
);
Expand All @@ -14,18 +16,18 @@ trait IFactRegistry<TContractState> {

#[starknet::interface]
trait ISmartProof<TContractState> {
fn get_proof(self: @TContractState) -> Array<felt252>;
fn get_proof(self: @TContractState) -> (Array<felt252>, CairoVersion);
}

#[starknet::contract]
mod FactRegistry {
use cairo_verifier::StarkProofWithSerde;
use cairo_verifier::{StarkProofWithSerde, CairoVersion};
use starknet::ContractAddress;
use core::{
poseidon::{Poseidon, PoseidonImpl, HashStateImpl}, keccak::keccak_u256s_be_inputs,
starknet::event::EventEmitter
};
use fact_registry::{verifier::{CairoVerifier, ICairoVerifier, StarkProof}, IFactRegistry,};
use fact_registry::{verifier::{CairoVerifier, ICairoVerifier, StarkProof}, IFactRegistry};
use super::{ISmartProofDispatcher, ISmartProofDispatcherTrait};

component!(path: CairoVerifier, storage: cairo_verifier, event: CairoVerifierEvent);
Expand Down Expand Up @@ -53,19 +55,23 @@ mod FactRegistry {

#[abi(embed_v0)]
impl FactRegistryImpl of IFactRegistry<ContractState> {
fn verify_and_register_fact(ref self: ContractState, stark_proof: StarkProofWithSerde) {
let (program_hash, output_hash) = self.cairo_verifier.verify_proof(stark_proof.into());
fn verify_and_register_fact(
ref self: ContractState, stark_proof: StarkProofWithSerde, cairo_version: CairoVersion
) {
let (program_hash, output_hash) = self
.cairo_verifier
.verify_proof(stark_proof.into(), cairo_version);
self._register_fact(program_hash, output_hash);
}

fn verify_and_register_fact_from_contract(
ref self: ContractState, contract_address: ContractAddress
) {
let mut proof_array = ISmartProofDispatcher { contract_address }.get_proof().span();
self
.verify_and_register_fact(
Serde::<StarkProofWithSerde>::deserialize(ref proof_array).unwrap()
);
let (proof_array, cairo_version) = ISmartProofDispatcher { contract_address }
.get_proof();
let mut proof_array = proof_array.span();
let proof = Serde::<StarkProofWithSerde>::deserialize(ref proof_array).unwrap();
self.verify_and_register_fact(proof, cairo_version);
}

fn is_valid(self: @ContractState, fact: felt252) -> bool {
Expand Down
17 changes: 12 additions & 5 deletions fact_registry/src/verifier.cairo
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use cairo_verifier::stark::StarkProof;
use cairo_verifier::{StarkProof, CairoVersion};

#[starknet::interface]
trait ICairoVerifier<TContractState> {
fn verify_proof(ref self: TContractState, stark_proof: StarkProof) -> (felt252, felt252);
fn verify_proof(
ref self: TContractState, stark_proof: StarkProof, cairo_version: CairoVersion
) -> (felt252, felt252);
}

#[starknet::component]
mod CairoVerifier {
use cairo_verifier::{PublicInputImpl, stark::{StarkProof, StarkProofImpl}};
use cairo_verifier::{CairoVersion, PublicInputImpl, stark::{StarkProof, StarkProofImpl}};

#[storage]
struct Storage {}
Expand All @@ -32,10 +34,15 @@ mod CairoVerifier {
TContractState, +HasComponent<TContractState>
> of super::ICairoVerifier<ComponentState<TContractState>> {
fn verify_proof(
ref self: ComponentState<TContractState>, stark_proof: StarkProof
ref self: ComponentState<TContractState>,
stark_proof: StarkProof,
cairo_version: CairoVersion
) -> (felt252, felt252) {
stark_proof.verify(SECURITY_BITS);
let (program_hash, output_hash) = stark_proof.public_input.verify();
let (program_hash, output_hash) = match cairo_version {
CairoVersion::Cairo0 => stark_proof.public_input.verify_cairo0(),
CairoVersion::Cairo1 => stark_proof.public_input.verify_cairo1(),
};
self.emit(ProofVerified { program_hash, output_hash });
(program_hash, output_hash)
}
Expand Down
18 changes: 9 additions & 9 deletions runner/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ use std::{
#[command(author, version, about, long_about = None)]
struct Cli {
/// Path to compiled sierra file
target: String,
program: String,
/// Cairo version
cairo_version: u8,
}

fn main() -> anyhow::Result<()> {
Expand All @@ -25,7 +27,6 @@ fn main() -> anyhow::Result<()> {
stdin().read_to_string(&mut input)?;
let parsed = parse(input)?;

let target = cli.target;
let function = "main";

let config: VecFelt252 = serde_json::from_str(&parsed.config.to_string()).unwrap();
Expand All @@ -45,7 +46,7 @@ fn main() -> anyhow::Result<()> {
println!("proof size: {} felts", proof.len());

let sierra_program =
serde_json::from_str::<VersionedProgram>(&fs::read_to_string(target)?)?.into_v1()?;
serde_json::from_str::<VersionedProgram>(&fs::read_to_string(cli.program)?)?.into_v1()?;

let runner = SierraCasmRunner::new(
sierra_program.program.clone(),
Expand All @@ -54,14 +55,13 @@ fn main() -> anyhow::Result<()> {
Some(ProfilingInfoCollectionConfig::default()),
)
.unwrap();

let func = runner.find_function(function).unwrap();
let proof_arg = Arg::Array(proof.into_iter().map(Arg::Value).collect_vec());
let cairo_version_arg = Arg::Value(cli.cairo_version.into());
let args = &[proof_arg, cairo_version_arg];
let result = runner
.run_function_with_starknet_context(
func,
&[Arg::Array(proof.into_iter().map(Arg::Value).collect_vec())],
Some(u32::MAX as usize),
Default::default(),
)
.run_function_with_starknet_context(func, args, Some(u32::MAX as usize), Default::default())
.unwrap();
// let profiling_processor =
// ProfilingInfoProcessor::new(None, sierra_program.program, UnorderedHashMap::default());
Expand Down
8 changes: 6 additions & 2 deletions src/air/layouts/dex/public_input.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use cairo_verifier::{
segments, get_builtins, CPU_COMPONENT_HEIGHT, CPU_COMPONENT_STEP, LAYOUT_CODE,
PEDERSEN_BUILTIN_ROW_RATIO, RANGE_CHECK_BUILTIN_ROW_RATIO, ECDSA_BUILTIN_ROW_RATIO
},
public_input::{PublicInput, PublicInputTrait}
public_input::{PublicInput, PublicInputTrait, verify_cairo1_public_input}
},
domains::StarkDomains
};
Expand All @@ -19,7 +19,7 @@ use core::{pedersen::PedersenTrait, hash::{HashStateTrait, HashStateExTrait, Has
use poseidon::poseidon_hash_span;

impl DexPublicInputImpl of PublicInputTrait {
fn verify(self: @PublicInput) -> (felt252, felt252) {
fn verify_cairo0(self: @PublicInput) -> (felt252, felt252) {
let public_segments = self.segments;

let initial_pc = *public_segments.at(segments::PROGRAM).begin_addr;
Expand Down Expand Up @@ -114,6 +114,10 @@ impl DexPublicInputImpl of PublicInputTrait {
(program_hash, output_hash)
}

fn verify_cairo1(self: @PublicInput) -> (felt252, felt252) {
verify_cairo1_public_input(self)
}

fn validate(self: @PublicInput, stark_domains: @StarkDomains) {
assert_range_u128_le(*self.log_n_steps, MAX_LOG_N_STEPS);
let n_steps = pow(2, *self.log_n_steps);
Expand Down
11 changes: 7 additions & 4 deletions src/air/layouts/recursive/public_input.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use cairo_verifier::{
segments, get_builtins, CPU_COMPONENT_HEIGHT, CPU_COMPONENT_STEP, LAYOUT_CODE,
PEDERSEN_BUILTIN_ROW_RATIO, RANGE_CHECK_BUILTIN_ROW_RATIO, BITWISE_ROW_RATIO
},
public_input::{PublicInput, PublicInputTrait}
public_input::{PublicInput, PublicInputTrait, verify_cairo1_public_input}
},
domains::StarkDomains
};
Expand All @@ -19,7 +19,7 @@ use core::{pedersen::PedersenTrait, hash::{HashStateTrait, HashStateExTrait, Has
use poseidon::poseidon_hash_span;

impl RecursivePublicInputImpl of PublicInputTrait {
fn verify(self: @PublicInput) -> (felt252, felt252) {
fn verify_cairo0(self: @PublicInput) -> (felt252, felt252) {
let public_segments = self.segments;

let initial_pc = *public_segments.at(segments::PROGRAM).begin_addr;
Expand Down Expand Up @@ -107,13 +107,16 @@ impl RecursivePublicInputImpl of PublicInputTrait {

// Check main page len
assert(
*memory.at(memory_index - 1) == *self.main_page.at(self.main_page.len() - 1),
'Invalid main page len'
*memory.at(memory_index - 1) == *memory.at(memory.len() - 1), 'Invalid main page len'
);

(program_hash, output_hash)
}

fn verify_cairo1(self: @PublicInput) -> (felt252, felt252) {
verify_cairo1_public_input(self)
}

fn validate(self: @PublicInput, stark_domains: @StarkDomains) {
assert_range_u128_le(*self.log_n_steps, MAX_LOG_N_STEPS);
let n_steps = pow(2, *self.log_n_steps);
Expand Down
8 changes: 6 additions & 2 deletions src/air/layouts/recursive_with_poseidon/public_input.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use cairo_verifier::{
PEDERSEN_BUILTIN_ROW_RATIO, RANGE_CHECK_BUILTIN_ROW_RATIO, BITWISE_ROW_RATIO,
POSEIDON_ROW_RATIO
},
public_input::{PublicInput, PublicInputTrait}
public_input::{PublicInput, PublicInputTrait, verify_cairo1_public_input}
},
domains::StarkDomains
};
Expand All @@ -20,7 +20,7 @@ use core::{pedersen::PedersenTrait, hash::{HashStateTrait, HashStateExTrait, Has
use poseidon::poseidon_hash_span;

impl RecursiveWithPoseidonPublicInputImpl of PublicInputTrait {
fn verify(self: @PublicInput) -> (felt252, felt252) {
fn verify_cairo0(self: @PublicInput) -> (felt252, felt252) {
let public_segments = self.segments;

let initial_pc = *public_segments.at(segments::PROGRAM).begin_addr;
Expand Down Expand Up @@ -115,6 +115,10 @@ impl RecursiveWithPoseidonPublicInputImpl of PublicInputTrait {
(program_hash, output_hash)
}

fn verify_cairo1(self: @PublicInput) -> (felt252, felt252) {
verify_cairo1_public_input(self)
}

fn validate(self: @PublicInput, stark_domains: @StarkDomains) {
assert_range_u128_le(*self.log_n_steps, MAX_LOG_N_STEPS);
let n_steps = pow(2, *self.log_n_steps);
Expand Down
8 changes: 6 additions & 2 deletions src/air/layouts/small/public_input.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use cairo_verifier::{
segments, get_builtins, CPU_COMPONENT_HEIGHT, CPU_COMPONENT_STEP, LAYOUT_CODE,
PEDERSEN_BUILTIN_ROW_RATIO, RANGE_CHECK_BUILTIN_ROW_RATIO, ECDSA_BUILTIN_ROW_RATIO
},
public_input::{PublicInput, PublicInputTrait}
public_input::{PublicInput, PublicInputTrait, verify_cairo1_public_input}
},
domains::StarkDomains
};
Expand All @@ -19,7 +19,7 @@ use core::{pedersen::PedersenTrait, hash::{HashStateTrait, HashStateExTrait, Has
use poseidon::poseidon_hash_span;

impl SmallPublicInputImpl of PublicInputTrait {
fn verify(self: @PublicInput) -> (felt252, felt252) {
fn verify_cairo0(self: @PublicInput) -> (felt252, felt252) {
let public_segments = self.segments;

let initial_pc = *public_segments.at(segments::PROGRAM).begin_addr;
Expand Down Expand Up @@ -114,6 +114,10 @@ impl SmallPublicInputImpl of PublicInputTrait {
(program_hash, output_hash)
}

fn verify_cairo1(self: @PublicInput) -> (felt252, felt252) {
verify_cairo1_public_input(self)
}

fn validate(self: @PublicInput, stark_domains: @StarkDomains) {
assert_range_u128_le(*self.log_n_steps, MAX_LOG_N_STEPS);
let n_steps = pow(2, *self.log_n_steps);
Expand Down
Loading

0 comments on commit d1a0a51

Please sign in to comment.