Skip to content

Commit

Permalink
Add proxy contract
Browse files Browse the repository at this point in the history
  • Loading branch information
fmkra committed Aug 16, 2024
1 parent 2acbb39 commit 19180a5
Show file tree
Hide file tree
Showing 6 changed files with 352 additions and 91 deletions.
222 changes: 222 additions & 0 deletions fact_registry/src/fact_registry.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
use cairo_verifier::{
StarkProofWithSerde, CairoVersion,
fri::fri::{FriLayerWitness, FriVerificationStateConstant, FriVerificationStateVariable},
};
use starknet::ContractAddress;
use fact_registry::verifier::InitResult;


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

#[starknet::interface]
trait IFactRegistry<TContractState> {
fn verify_proof_full_and_register_fact(
ref self: TContractState,
stark_proof: StarkProofWithSerde,
cairo_version: CairoVersion,
settings: VerifierSettings,
);

fn verify_proof_initial(
self: @TContractState,
job_id: felt252,
stark_proof_serde: StarkProofWithSerde,
cairo_version: CairoVersion,
settings: VerifierSettings,
) -> InitResult;

fn verify_proof_step(
self: @TContractState,
job_id: felt252,
state_constant: FriVerificationStateConstant,
state_variable: FriVerificationStateVariable,
witness: FriLayerWitness,
settings: VerifierSettings,
) -> (FriVerificationStateVariable, u32);

fn verify_proof_final_and_register_fact(
ref self: TContractState,
job_id: felt252,
state_constant: FriVerificationStateConstant,
state_variable: FriVerificationStateVariable,
last_layer_coefficients: Span<felt252>,
settings: VerifierSettings,
);

fn is_valid(self: @TContractState, fact: felt252) -> bool;
fn get_verifier_address(self: @TContractState, settings: VerifierSettings) -> ContractAddress;
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, StarkProof, CairoVersion,
fri::fri::{FriLayerWitness, FriVerificationStateConstant, FriVerificationStateVariable},
};
use starknet::{ContractAddress, get_caller_address};
use core::{
poseidon::{Poseidon, PoseidonImpl, HashStateImpl}, keccak::keccak_u256s_be_inputs,
starknet::event::EventEmitter
};
use fact_registry::verifier::{
InitResult, ICairoVerifierDispatcher, ICairoVerifierDispatcherTrait
};
use super::{VerifierSettings, IFactRegistry};

#[storage]
struct Storage {
owner: ContractAddress,
verifiers: LegacyMap<felt252, ContractAddress>,
facts: LegacyMap<felt252, bool>,
}

#[event]
#[derive(Drop, starknet::Event)]
enum Event {
FactRegistered: FactRegistered,
OwnershipTransferred: OwnershipTransferred,
VerifierRegistered: VerifierRegistered,
}

#[derive(Drop, starknet::Event)]
struct FactRegistered {
#[key]
fact: felt252,
#[key]
verifier_address: ContractAddress,
}

#[derive(Drop, starknet::Event)]
struct VerifierRegistered {
#[key]
settings: VerifierSettings,
#[key]
address: ContractAddress,
}

#[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_proof_full_and_register_fact(
ref self: ContractState,
stark_proof: StarkProofWithSerde,
cairo_version: CairoVersion,
settings: VerifierSettings,
) {
let verifier_address = self.get_verifier_address(settings);
let fact = ICairoVerifierDispatcher {
contract_address: verifier_address
}.verify_proof_full(stark_proof.into(), cairo_version);

self.emit(Event::FactRegistered(FactRegistered { fact, verifier_address }));
self.facts.write(fact, true);
}

fn verify_proof_initial(
self: @ContractState,
job_id: felt252,
stark_proof_serde: StarkProofWithSerde,
cairo_version: CairoVersion,
settings: VerifierSettings,
) -> InitResult {
ICairoVerifierDispatcher {
contract_address: self.get_verifier_address(settings)
}.verify_proof_initial(job_id, stark_proof_serde, cairo_version)
}

fn verify_proof_step(
self: @ContractState,
job_id: felt252,
state_constant: FriVerificationStateConstant,
state_variable: FriVerificationStateVariable,
witness: FriLayerWitness,
settings: VerifierSettings,
) -> (FriVerificationStateVariable, u32) {
ICairoVerifierDispatcher {
contract_address: self.get_verifier_address(settings)
}.verify_proof_step(job_id, state_constant, state_variable, witness)
}

fn verify_proof_final_and_register_fact(
ref self: ContractState,
job_id: felt252,
state_constant: FriVerificationStateConstant,
state_variable: FriVerificationStateVariable,
last_layer_coefficients: Span<felt252>,
settings: VerifierSettings,
) {
let verifier_address = self.get_verifier_address(settings);
assert(verifier_address.into() != 0, 'VERIFIER_NOT_FOUND');
let fact = ICairoVerifierDispatcher {
contract_address: verifier_address
}.verify_proof_final(job_id, state_constant, state_variable, last_layer_coefficients);

self.emit(Event::FactRegistered(FactRegistered { fact, verifier_address }));
self.facts.write(fact, true);
}

fn is_valid(self: @ContractState, fact: felt252) -> bool {
self.facts.read(fact)
}

fn get_verifier_address(self: @ContractState, settings: VerifierSettings) -> ContractAddress {
let verifier_address = self.verifiers.read(self._hash_settings(settings));
assert(verifier_address.into() != 0, 'VERIFIER_NOT_FOUND');
verifier_address
}

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);
self.emit(Event::VerifierRegistered(VerifierRegistered {
settings, 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]
impl InternalFactRegistry of InternalFactRegistryTrait {
fn _hash_settings(self: @ContractState, settings: VerifierSettings) -> felt252 {
PoseidonImpl::new()
.update(settings.layout)
.update(settings.hasher)
.update(settings.security_bits)
.update(settings.version)
.finalize()
}
}
}
90 changes: 1 addition & 89 deletions fact_registry/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -1,90 +1,2 @@
mod verifier;

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

// #[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
// );
// fn is_valid(self: @TContractState, fact: felt252) -> bool;
// }

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

// #[starknet::contract]
// mod FactRegistry {
// 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 super::{ISmartProofDispatcher, ISmartProofDispatcherTrait};

// component!(path: CairoVerifier, storage: cairo_verifier, event: CairoVerifierEvent);

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

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

// #[derive(Drop, starknet::Event)]
// struct FactRegistered {
// #[key]
// fact: felt252,
// }

// #[abi(embed_v0)]
// impl FactRegistryImpl of IFactRegistry<ContractState> {
// 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 (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)
// }
// }

// #[generate_trait]
// impl InternalFactRegistry of InternalFactRegistryTrait {
// fn _register_fact(ref self: ContractState, program_hash: felt252, output_hash: felt252,) {
// let fact = PoseidonImpl::new().update(program_hash).update(output_hash).finalize();
// self.emit(Event::FactRegistered(FactRegistered { fact }));
// self.facts.write(fact, true);
// }
// }
// }
mod fact_registry;
31 changes: 29 additions & 2 deletions fact_registry/src/verifier.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ trait ICairoVerifier<TContractState> {
state_constant: FriVerificationStateConstant,
state_variable: FriVerificationStateVariable,
last_layer_coefficients: Span<felt252>,
);
) -> felt252;

fn verify_proof_full(
ref self: TContractState,
stark_proof_serde: StarkProofWithSerde,
cairo_version: CairoVersion,
) -> felt252;
}

#[starknet::contract]
Expand Down Expand Up @@ -142,7 +148,7 @@ mod CairoVerifier {
state_constant: FriVerificationStateConstant,
state_variable: FriVerificationStateVariable,
last_layer_coefficients: Span<felt252>,
) {
) -> felt252 {
assert(hash_constant(@state_constant) == self.state_constant.read(job_id).unwrap(), 'Invalid state (constant)');
assert(hash_variable(@state_variable) == self.state_variable.read(job_id).unwrap(), 'Invalid state (variable)');
let fact = self.state_fact.read(job_id).expect('No fact saved');
Expand All @@ -155,6 +161,27 @@ mod CairoVerifier {
self.state_fact.write(job_id, Option::None);

self.emit(ProofVerified { job_id, fact });
fact
}

fn verify_proof_full(
ref self: ContractState,
stark_proof_serde: StarkProofWithSerde,
cairo_version: CairoVersion,
) -> felt252 {
let stark_proof: StarkProof = stark_proof_serde.into();
let (program_hash, output_hash) = match cairo_version {
CairoVersion::Cairo0 => stark_proof.public_input.verify_cairo0(),
CairoVersion::Cairo1 => stark_proof.public_input.verify_cairo1(),
};
stark_proof.verify_full(
SECURITY_BITS, self.contract_address_1.read(), self.contract_address_2.read()
);

let fact = PoseidonImpl::new().update(program_hash).update(output_hash).finalize();

self.emit(ProofVerified { job_id: 0, fact });
fact
}
}
}
11 changes: 11 additions & 0 deletions multicall/add_cairo_verifier.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[[call]]
call_type = "invoke"
contract_address = "0x00225abd9d24ea97a18711eca30c97987a9a8c55105faf77f0d4fc15e326ae5b" # FactRegistry address
function = "register_verifier"
inputs = [
"0x737461726b6e65745f776974685f6b656363616b", # layout
"0x6b656363616b", # hasher
"50", # security_bits
"0x73746f6e6535", # version
"0x005c9b26f786f724a26b6ade37270f9e79fc903a3a96a61d6a14380d099d1df2", # CairoVerifier address
]
6 changes: 6 additions & 0 deletions multicall/deploy_fact_registry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[[call]]
call_type = "deploy"
class_hash = "0x49cc114a5b78d679c970e22b7fd0d6e503b29a7d96aaa3efda46381c36d8407"
inputs = ["REPLACE WITH DEPLOYER ADDRESS"]
unique = true
id = "fact_registry"
Loading

0 comments on commit 19180a5

Please sign in to comment.