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

Proxy Fact Registry #138

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scarb 2.6.3
scarb nightly-2024-04-20
starknet-foundry 0.24.0
24 changes: 24 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
[package]
name = "cairo_verifier"
version = "0.1.0"

[dependencies]
snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.24.0" }

[[target.starknet-contract]]
casm = true

[lib]
sierra = true
casm = false

[features]

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

keccak = []
blake2s = []

default = ["recursive", "keccak"]
107 changes: 73 additions & 34 deletions fact_registry/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,50 +1,53 @@
mod verifier;

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


#[derive(Drop, Copy, Serde)]
struct VerifierSettings {
layout: felt252,
hasher: felt252,
security_bits: felt252,
version: felt252,
}

#[starknet::interface]
trait IFactRegistry<TContractState> {
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
ref self: TContractState,
stark_proof: StarkProofWithSerde,
cairo_version: CairoVersion,
settings: VerifierSettings,
);
fn is_valid(self: @TContractState, fact: felt252) -> bool;
}

#[starknet::interface]
trait ISmartProof<TContractState> {
fn get_proof(self: @TContractState) -> (Array<felt252>, CairoVersion);
fn register_verifier(ref self: TContractState, settings: VerifierSettings, address: ContractAddress);
fn transfer_ownership(ref self: TContractState, new_owner: ContractAddress);
}

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

component!(path: CairoVerifier, storage: cairo_verifier, event: CairoVerifierEvent);
use cairo_verifier::verifier::{ICairoVerifierDispatcher, ICairoVerifierDispatcherTrait, StarkProof};
use super::{VerifierSettings, IFactRegistry};

#[storage]
struct Storage {
#[substorage(v0)]
cairo_verifier: CairoVerifier::Storage,
owner: ContractAddress,
verifiers: LegacyMap<felt252, ContractAddress>,
facts: LegacyMap<felt252, bool>,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
#[flat]
CairoVerifierEvent: CairoVerifier::Event,
// #[flat]
// CairoVerifierEvent: CairoVerifier::Event,
FactRegistered: FactRegistered,
OwnershipTransferred: OwnershipTransferred,
}

#[derive(Drop, starknet::Event)]
Expand All @@ -53,30 +56,57 @@ mod FactRegistry {
fact: felt252,
}

#[derive(Drop, starknet::Event)]
struct OwnershipTransferred {
previous_owner: ContractAddress,
new_owner: ContractAddress
}

#[constructor]
fn constructor(ref self: ContractState, owner: ContractAddress) {
self.owner.write(owner);
}

#[abi(embed_v0)]
impl FactRegistryImpl of IFactRegistry<ContractState> {
fn verify_and_register_fact(
ref self: ContractState, stark_proof: StarkProofWithSerde, cairo_version: CairoVersion
ref self: ContractState,
stark_proof: StarkProofWithSerde,
cairo_version: CairoVersion,
settings: VerifierSettings,
) {
let (program_hash, output_hash) = self
.cairo_verifier
.verify_proof(stark_proof.into(), cairo_version);
let verifier_address = self.verifiers.read(self._hash_settings(settings));
assert(verifier_address.into() != 0, 'VERIFIER_NOT_FOUND');
let (program_hash, output_hash) = ICairoVerifierDispatcher {
contract_address: verifier_address
}.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 (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 {
self.facts.read(fact)
}

fn register_verifier(ref self: ContractState, settings: VerifierSettings, address: ContractAddress) {
assert(self.owner.read() == get_caller_address(), 'ONLY_OWNER');
assert(address.into() != 0, 'INVALID_VERIFIER_ADDRESS');
let settings_hash = self._hash_settings(settings);
assert(self.verifiers.read(settings_hash).into() == 0, 'VERIFIER_ALREADY_EXISTS');
self.verifiers.write(settings_hash, address);
}

fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) {
let caller = get_caller_address();
assert(self.owner.read() == caller, 'ONLY_OWNER');
self.owner.write(new_owner);

self
.emit(
Event::OwnershipTransferred(
OwnershipTransferred { previous_owner: caller, new_owner }
)
);
}
}

#[generate_trait]
Expand All @@ -86,5 +116,14 @@ mod FactRegistry {
self.emit(Event::FactRegistered(FactRegistered { fact }));
self.facts.write(fact, true);
}

fn _hash_settings(self: @ContractState, settings: VerifierSettings) -> felt252 {
PoseidonImpl::new()
.update(settings.layout)
.update(settings.hasher)
.update(settings.security_bits)
.update(settings.version)
.finalize()
}
}
}
6 changes: 6 additions & 0 deletions fact_registry/starknet/deploy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[[call]]
call_type = "deploy"
class_hash = "0x79b972400cbbbc9afe4056a377366773bc069e292e1b9657bec2e48b4353ad3"
inputs = ["REPLACE WITH YOUR ACCOUNT ADDRESS"]
unique = false
id = "fact_registry"
18 changes: 18 additions & 0 deletions fact_registry/starknet/register_verifier.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[[call]]
call_type = "deploy"
class_hash = "VERIFIER CLASS HASH"
inputs = []
unique = false
id = "verifier"

[[call]]
call_type = "invoke"
contract_address = "REPLACE WITH FACT REGISTRY ADDRESS"
function = "register_verifier"
inputs = [
"SETTINGS.LAYOUT",
"SETTINGS.HASHER",
"SETTINGS.SECURITY_BITS",
"SETTINGS.VERSION",
"verifier"
]
30 changes: 11 additions & 19 deletions src/air/layouts.cairo
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
// === DEX BEGIN ===
// mod dex;
// === DEX END ===
// === RECURSIVE BEGIN ===
#[cfg(feature: 'dex')]
mod dex;
#[cfg(feature: 'recursive')]
mod recursive;
// === RECURSIVE END ===
// === RECURSIVE_WITH_POSEIDON BEGIN ===
// mod recursive_with_poseidon;
// === RECURSIVE_WITH_POSEIDON END ===
// === SMALL BEGIN ===
// mod small;
// === SMALL END ===
// === STARKNET BEGIN ===
// mod starknet;
// === STARKNET END ===
// === STARKNET_WITH_KECCAK BEGIN ===
// mod starknet_with_keccak;
// === STARKNET_WITH_KECCAK END ===


#[cfg(feature: 'recursive_with_poseidon')]
mod recursive_with_poseidon;
#[cfg(feature: 'small')]
mod small;
#[cfg(feature: 'starknet')]
mod starknet;
#[cfg(feature: 'starknet_with_keccak')]
mod starknet_with_keccak;
34 changes: 15 additions & 19 deletions src/air/public_input.cairo
Original file line number Diff line number Diff line change
@@ -1,23 +1,5 @@
use cairo_verifier::{
domains::StarkDomains, air::constants::{MAX_ADDRESS, INITIAL_PC},
// === DEX BEGIN ===
// air::layouts::dex::constants::segments,
// === DEX END ===
// === RECURSIVE BEGIN ===
air::layouts::recursive::constants::segments,
// === RECURSIVE END ===
// === RECURSIVE_WITH_POSEIDON BEGIN ===
// air::layouts::recursive_with_poseidon::constants::segments,
// === RECURSIVE_WITH_POSEIDON END ===
// === SMALL BEGIN ===
// air::layouts::small::constants::segments,
// === SMALL END ===
// === STARKNET BEGIN ===
// air::layouts::starknet::constants::segments,
// === STARKNET END ===
// === STARKNET_WITH_KECCAK BEGIN ===
// air::layouts::starknet_with_keccak::constants::segments,
// === STARKNET_WITH_KECCAK END ===
air::public_memory::{
Page, PageTrait, ContinuousPageHeader, get_continuous_pages_product, AddrValueSize
},
Expand All @@ -26,9 +8,21 @@ use cairo_verifier::{
math::{pow, Felt252PartialOrd, Felt252Div},
},
};

use core::{pedersen::PedersenTrait, hash::{HashStateTrait, HashStateExTrait, Hash}};
use poseidon::poseidon_hash_span;
#[cfg(feature: 'dex')]
use cairo_verifier::air::layouts::dex::constants::segments;
#[cfg(feature: 'recursive')]
use cairo_verifier::air::layouts::recursive::constants::segments;
#[cfg(feature: 'recursive_with_poseidon')]
use cairo_verifier::air::layouts::recursive_with_poseidon::constants::segments;
#[cfg(feature: 'small')]
use cairo_verifier::air::layouts::small::constants::segments;
#[cfg(feature: 'starknet')]
use cairo_verifier::air::layouts::starknet::constants::segments;
#[cfg(feature: 'starknet_with_keccak')]
use cairo_verifier::air::layouts::starknet_with_keccak::constants::segments;


#[derive(Drop, Copy, PartialEq, Serde)]
struct SegmentInfo {
Expand Down Expand Up @@ -184,6 +178,8 @@ fn verify_cairo1_public_input(public_input: @PublicInput) -> (felt252, felt252)
(program_hash, output_hash)
}

#[cfg(feature: 'recursive')]
#[cfg(feature: 'keccak')]
#[cfg(test)]
mod tests {
use super::get_public_input_hash;
Expand Down
40 changes: 22 additions & 18 deletions src/common/hasher.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,42 @@ use cairo_verifier::common::{
flip_endianness::FlipEndiannessTrait
};

// === BLAKE2S BEGIN ===
// fn hash_n_bytes(mut data: Array<u8>, n: u8, hash_len: bool) -> u256 {
// if hash_len {
// data.append(n);
// }
// blake2s_u8(data)
// }
// fn hash_truncated(data: Array<u32>) -> felt252 {
// truncated_blake2s(data)
// }
// fn hash(data: Array<u32>) -> u256 {
// blake2s(data)
// }
// === BLAKE2S END ===
#[cfg(feature: 'blake2s')]
fn hash_n_bytes(mut data: Array<u8>, n: u8, hash_len: bool) -> u256 {
if hash_len {
data.append(n);
}
blake2s_u8(data)
}

// === KECCAK BEGIN ===
#[cfg(feature: 'blake2s')]
fn hash_truncated(data: Array<u32>) -> felt252 {
truncated_blake2s(data)
}

#[cfg(feature: 'blake2s')]
fn hash(data: Array<u32>) -> u256 {
blake2s(data)
}

#[cfg(feature: 'keccak')]
fn hash_n_bytes(mut data: Array<u64>, n: u8, hash_len: bool) -> u256 {
if hash_len {
keccak::cairo_keccak(ref data, n.into(), 1)
} else {
keccak::cairo_keccak(ref data, 0, 0)
}
}

#[cfg(feature: 'keccak')]
fn hash_truncated(mut data: Array<u64>) -> felt252 {
(keccak::cairo_keccak(ref data, 0, 0)
.flip_endianness() % 0x10000000000000000000000000000000000000000)
.try_into()
.unwrap()
}

#[cfg(feature: 'keccak')]
fn hash(mut data: Array<u64>) -> u256 {
keccak::cairo_keccak(ref data, 0, 0)
}
// === KECCAK END ===


Loading
Loading