From 479f3c6bf4777eaa2846da1d48619e8bda30432e Mon Sep 17 00:00:00 2001 From: Filip Krawczyk Date: Tue, 10 Sep 2024 12:17:11 +0200 Subject: [PATCH] Change handling of security bits --- fact_registry/src/fact_registry.cairo | 334 +++++++++--------- fact_registry/src/lib.cairo | 130 +------ src/benches/stark/stark_proof_verify.cairo | 5 +- src/fact_registry.cairo | 221 ++++++++++++ src/lib.cairo | 7 +- src/stark.cairo | 28 +- src/stark/tests/test_stark_proof_verify.cairo | 11 +- src/verifier.cairo | 38 +- 8 files changed, 437 insertions(+), 337 deletions(-) create mode 100644 src/fact_registry.cairo diff --git a/fact_registry/src/fact_registry.cairo b/fact_registry/src/fact_registry.cairo index ca1478335..d65d1b6ef 100644 --- a/fact_registry/src/fact_registry.cairo +++ b/fact_registry/src/fact_registry.cairo @@ -1,16 +1,14 @@ use cairo_verifier::{ StarkProofWithSerde, CairoVersion, fri::fri::{FriLayerWitness, FriVerificationStateConstant, FriVerificationStateVariable}, + verifier::InitResult, }; use starknet::ContractAddress; -use fact_registry::verifier::InitResult; - #[derive(Drop, Copy, Serde)] struct VerifierSettings { layout: felt252, hasher: felt252, - security_bits: felt252, version: felt252, } @@ -55,168 +53,168 @@ trait IFactRegistry { 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, - facts: LegacyMap, - } - - #[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 { - 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, - 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() - } - } -} \ No newline at end of file +// #[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, +// facts: LegacyMap, +// } + +// #[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 { +// 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, security_bits) = ICairoVerifierDispatcher { +// contract_address: verifier_address +// }.verify_proof_full(stark_proof.into(), cairo_version); + +// self.emit(Event::FactRegistered(FactRegistered { fact, verifier_address, security_bits })); +// 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, +// settings: VerifierSettings, +// ) { +// let verifier_address = self.get_verifier_address(settings); +// assert(verifier_address.into() != 0, 'VERIFIER_NOT_FOUND'); +// let (fact, security_bits) = 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, security_bits })); +// 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() +// } +// } +// } \ No newline at end of file diff --git a/fact_registry/src/lib.cairo b/fact_registry/src/lib.cairo index e1e4cff79..8549fa1db 100644 --- a/fact_registry/src/lib.cairo +++ b/fact_registry/src/lib.cairo @@ -1,129 +1 @@ -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 { - fn verify_and_register_fact( - ref self: TContractState, - stark_proof: StarkProofWithSerde, - cairo_version: CairoVersion, - settings: VerifierSettings, - ); - fn is_valid(self: @TContractState, fact: felt252) -> bool; - 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, get_caller_address}; - use core::{ - poseidon::{Poseidon, PoseidonImpl, HashStateImpl}, keccak::keccak_u256s_be_inputs, - starknet::event::EventEmitter - }; - use cairo_verifier::verifier::{ICairoVerifierDispatcher, ICairoVerifierDispatcherTrait, StarkProof}; - use super::{VerifierSettings, IFactRegistry}; - - #[storage] - struct Storage { - owner: ContractAddress, - verifiers: LegacyMap, - facts: LegacyMap, - } - - #[event] - #[derive(Drop, starknet::Event)] - enum Event { - // #[flat] - // CairoVerifierEvent: CairoVerifier::Event, - FactRegistered: FactRegistered, - OwnershipTransferred: OwnershipTransferred, - } - - #[derive(Drop, starknet::Event)] - struct FactRegistered { - #[key] - 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 { - fn verify_and_register_fact( - ref self: ContractState, - stark_proof: StarkProofWithSerde, - cairo_version: CairoVersion, - settings: VerifierSettings, - ) { - 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 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] - 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); - } - - fn _hash_settings(self: @ContractState, settings: VerifierSettings) -> felt252 { - PoseidonImpl::new() - .update(settings.layout) - .update(settings.hasher) - .update(settings.security_bits) - .update(settings.version) - .finalize() - } - } -} \ No newline at end of file +mod fact_registry; \ No newline at end of file diff --git a/src/benches/stark/stark_proof_verify.cairo b/src/benches/stark/stark_proof_verify.cairo index 41a5452f9..4eacc5ece 100644 --- a/src/benches/stark/stark_proof_verify.cairo +++ b/src/benches/stark/stark_proof_verify.cairo @@ -1,7 +1,7 @@ use cairo_verifier::{stark::{StarkProof, StarkProofTrait}, tests::stone_proof_fibonacci_keccak}; fn bench_stark_proof_verify() { - let security_bits: felt252 = 50; + let SECURITY_BITS: u32 = 50; let stark_proof = StarkProof { config: stone_proof_fibonacci_keccak::stark::config::get(), @@ -10,5 +10,6 @@ fn bench_stark_proof_verify() { witness: stone_proof_fibonacci_keccak::stark::witness::get(), }; - stark_proof.verify_initial(security_bits, 0.try_into().unwrap(), 0.try_into().unwrap()); + let security_bits = stark_proof.verify_full(0.try_into().unwrap(), 0.try_into().unwrap()); + assert(security_bits >= SECURITY_BITS, 'Security bits too low'); } diff --git a/src/fact_registry.cairo b/src/fact_registry.cairo new file mode 100644 index 000000000..6ec2bfbbc --- /dev/null +++ b/src/fact_registry.cairo @@ -0,0 +1,221 @@ +use cairo_verifier::{ + StarkProofWithSerde, CairoVersion, + fri::fri::{FriLayerWitness, FriVerificationStateConstant, FriVerificationStateVariable}, + verifier::InitResult, +}; +use starknet::ContractAddress; + +#[derive(Drop, Copy, Serde)] +struct VerifierSettings { + layout: felt252, + hasher: felt252, + version: felt252, +} + +#[starknet::interface] +trait IFactRegistry { + 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, + 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, + verifier::{ + InitResult, ICairoVerifierDispatcher, ICairoVerifierDispatcherTrait + }, + 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 super::{VerifierSettings, IFactRegistry}; + + #[storage] + struct Storage { + owner: ContractAddress, + verifiers: LegacyMap, + facts: LegacyMap, + } + + #[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, + #[key] + security_bits: u32, + } + + #[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 { + 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, security_bits) = ICairoVerifierDispatcher { + contract_address: verifier_address + }.verify_proof_full(stark_proof.into(), cairo_version); + + self.emit(Event::FactRegistered(FactRegistered { fact, verifier_address, security_bits })); + 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, + settings: VerifierSettings, + ) { + let verifier_address = self.get_verifier_address(settings); + assert(verifier_address.into() != 0, 'VERIFIER_NOT_FOUND'); + let (fact, security_bits) = 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, security_bits })); + 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.version) + .finalize() + } + } +} \ No newline at end of file diff --git a/src/lib.cairo b/src/lib.cairo index a41b745c3..bed8074cf 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -11,6 +11,7 @@ mod stark; mod table_commitment; mod vector_commitment; mod verifier; +mod fact_registry; #[cfg(feature: 'recursive')] mod benches; @@ -36,14 +37,16 @@ use cairo_verifier::air::layouts::starknet::public_input::StarknetPublicInputImp use cairo_verifier::air::layouts::starknet_with_keccak::public_input::StarknetWithKeccakPublicInputImpl as PublicInputImpl; -const SECURITY_BITS: felt252 = 50; +const SECURITY_BITS: u32 = 50; #[cfg(feature: 'monolit')] fn main(mut serialized: Span, cairo_version: CairoVersion) -> (felt252, felt252) { let stark_proof_serde = Serde::::deserialize(ref serialized).unwrap(); let stark_proof: StarkProof = stark_proof_serde.into(); - stark_proof.verify_full(SECURITY_BITS, 0.try_into().unwrap(), 0.try_into().unwrap()); + let security_bits = stark_proof.verify_full(0.try_into().unwrap(), 0.try_into().unwrap()); + assert(security_bits >= SECURITY_BITS, 'Security bits are too low'); + let (program_hash, output_hash) = match cairo_version { CairoVersion::Cairo0 => stark_proof.public_input.verify_cairo0(), CairoVersion::Cairo1 => stark_proof.public_input.verify_cairo1(), diff --git a/src/stark.cairo b/src/stark.cairo index 1b81387ac..dc2b17ae3 100644 --- a/src/stark.cairo +++ b/src/stark.cairo @@ -73,9 +73,9 @@ struct StarkProof { #[generate_trait] impl StarkProofImpl of StarkProofTrait { - fn verify_initial(self: @StarkProof, security_bits: felt252, contract_address_1: ContractAddress, contract_address_2: ContractAddress) -> (FriVerificationStateConstant, FriVerificationStateVariable, Span) { + fn verify_initial(self: @StarkProof, contract_address_1: ContractAddress, contract_address_2: ContractAddress) -> (FriVerificationStateConstant, FriVerificationStateVariable, Span, u32) { // Validate config. - self.config.validate(security_bits); + let security_bits = self.config.validate(); // Validate the public input. let stark_domains = StarkDomainsImpl::new( @@ -112,7 +112,7 @@ impl StarkProofImpl of StarkProofTrait { stark_domains, contract_address_2 ); - (con, var, last_layer_coefficients) + (con, var, last_layer_coefficients, security_bits) } fn verify_step( @@ -131,8 +131,8 @@ impl StarkProofImpl of StarkProofTrait { fri_verify_final(stateConstant, stateVariable, last_layer_coefficients) } - fn verify_full(self: @StarkProof, security_bits: felt252, contract_address_1: ContractAddress, contract_address_2: ContractAddress) { - let (mut con, mut var, last_layer_coefficients) = self.verify_initial(security_bits, contract_address_1, contract_address_2); + fn verify_full(self: @StarkProof, contract_address_1: ContractAddress, contract_address_2: ContractAddress) -> u32 { + let (mut con, mut var, last_layer_coefficients, security_bits) = self.verify_initial(contract_address_1, contract_address_2); let n = con.n_layers; let mut i = 0; @@ -150,6 +150,7 @@ impl StarkProofImpl of StarkProofTrait { let (_, new_var) = StarkProofTrait::verify_final(con, var, last_layer_coefficients); assert(new_var.iter.into() == n + 1, 'Verification not finalized'); + security_bits } } @@ -172,18 +173,10 @@ struct StarkConfig { #[generate_trait] impl StarkConfigImpl of StarkConfigTrait { - fn validate(self: @StarkConfig, security_bits: felt252) { + fn validate(self: @StarkConfig) -> u32 { // Validate Proof of work config. self.proof_of_work.validate(); - // Check security bits. - assert( - Into::::into(security_bits) <= (*self.n_queries).into() - * (*self.log_n_cosets).into() - + (*self.proof_of_work.n_bits).into(), - 'Invalid security bits' - ); - // Validate traces config. let log_eval_domain_size = *self.log_trace_domain_size + *self.log_n_cosets; self.traces.validate(log_eval_domain_size, *self.n_verifier_friendly_commitment_layers); @@ -196,6 +189,13 @@ impl StarkConfigImpl of StarkConfigTrait { // Validate Fri config. self.fri.validate(*self.log_n_cosets, *self.n_verifier_friendly_commitment_layers); + + // Security bits. + let n_queries: u32 = (*self.n_queries).try_into().unwrap(); + let log_n_cosets: u32 = (*self.log_n_cosets).try_into().unwrap(); + let proof_of_work_bits: u32 = (*self.proof_of_work.n_bits).try_into().unwrap(); + + n_queries * log_n_cosets + proof_of_work_bits } } diff --git a/src/stark/tests/test_stark_proof_verify.cairo b/src/stark/tests/test_stark_proof_verify.cairo index 7cec1fde2..651c22ccf 100644 --- a/src/stark/tests/test_stark_proof_verify.cairo +++ b/src/stark/tests/test_stark_proof_verify.cairo @@ -7,7 +7,7 @@ use cairo_verifier::{ #[test] #[available_gas(99999999999)] fn test_stark_proof_fibonacci_verify() { - let security_bits: felt252 = 50; + let SECURITY_BITS: felt252 = 50; let stark_proof = StarkProof { config: stone_proof_fibonacci::stark::config::get(), @@ -16,14 +16,15 @@ fn test_stark_proof_fibonacci_verify() { witness: stone_proof_fibonacci::stark::witness::get(), }; - stark_proof.verify_initial(security_bits, 0.try_into().unwrap(), 0.try_into().unwrap()); + let security_bits = stark_proof.verify_full(security_bits, 0.try_into().unwrap(), 0.try_into().unwrap()); + assert(security_bits >= SECURITY_BITS, 'Security bits too low'); } #[cfg(feature: 'keccak')] #[test] #[available_gas(9999999999)] fn test_stark_proof_fibonacci_verify() { - let security_bits: felt252 = 50; + let SECURITY_BITS: u32 = 50; let stark_proof = StarkProof { config: stone_proof_fibonacci_keccak::stark::config::get(), @@ -32,6 +33,6 @@ fn test_stark_proof_fibonacci_verify() { witness: stone_proof_fibonacci_keccak::stark::witness::get(), }; - stark_proof.verify_initial(security_bits, 0.try_into().unwrap(), 0.try_into().unwrap()); - // TODO: next steps + let security_bits = stark_proof.verify_full(0.try_into().unwrap(), 0.try_into().unwrap()); + assert(security_bits >= SECURITY_BITS, 'Security bits too low'); } diff --git a/src/verifier.cairo b/src/verifier.cairo index 30a81d345..c775d7abf 100644 --- a/src/verifier.cairo +++ b/src/verifier.cairo @@ -34,13 +34,13 @@ trait ICairoVerifier { state_constant: FriVerificationStateConstant, state_variable: FriVerificationStateVariable, last_layer_coefficients: Span, - ) -> felt252; + ) -> (felt252, u32); fn verify_proof_full( ref self: TContractState, stark_proof_serde: StarkProofWithSerde, cairo_version: CairoVersion, - ) -> felt252; + ) -> (felt252, u32); } #[starknet::contract] @@ -59,9 +59,10 @@ mod CairoVerifier { contract_address_1: ContractAddress, contract_address_2: ContractAddress, - state_constant: LegacyMap>, // job_id => hash(constant state) - state_variable: LegacyMap>, // job_id => hash(variable state) - state_fact: LegacyMap>, // job_id => fact_hash + state_constant: LegacyMap>, // job_id => hash(constant state) + state_variable: LegacyMap>, // job_id => hash(variable state) + state_fact: LegacyMap>, // job_id => fact_hash + state_security_bits: LegacyMap>, // job_id => security_bits } #[constructor] @@ -82,10 +83,10 @@ mod CairoVerifier { job_id: felt252, #[key] fact: felt252, + #[key] + security_bits: u32, } - const SECURITY_BITS: felt252 = 50; - #[abi(embed_v0)] impl CairoVerifier of ICairoVerifier { fn verify_proof_initial( @@ -104,12 +105,13 @@ mod CairoVerifier { let fact = PoseidonImpl::new().update(program_hash).update(output_hash).finalize(); - let (con, var, last_layer_coefficients) = stark_proof.verify_initial( - SECURITY_BITS, self.contract_address_1.read(), self.contract_address_2.read() + let (con, var, last_layer_coefficients, security_bits) = stark_proof.verify_initial( + self.contract_address_1.read(), self.contract_address_2.read() ); self.state_constant.write(job_id, Option::Some(hash_constant(@con))); self.state_variable.write(job_id, Option::Some(hash_variable(@var))); self.state_fact.write(job_id, Option::Some(fact)); + self.state_security_bits.write(job_id, Option::Some(security_bits)); let layers_left = con.n_layers - var.iter; @@ -148,10 +150,11 @@ mod CairoVerifier { state_constant: FriVerificationStateConstant, state_variable: FriVerificationStateVariable, last_layer_coefficients: Span, - ) -> felt252 { + ) -> (felt252, u32) { 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'); + let security_bits = self.state_security_bits.read(job_id).expect('No security bits saved'); let (new_con, new_var) = StarkProofImpl::verify_final(state_constant, state_variable, last_layer_coefficients); assert(new_var.iter.into() == new_con.n_layers + 1, 'Verification not finalized'); @@ -159,29 +162,30 @@ mod CairoVerifier { self.state_variable.write(job_id, Option::None); self.state_constant.write(job_id, Option::None); self.state_fact.write(job_id, Option::None); + self.state_security_bits.write(job_id, Option::None); - self.emit(ProofVerified { job_id, fact }); - fact + self.emit(ProofVerified { job_id, fact, security_bits }); + (fact, security_bits) } fn verify_proof_full( ref self: ContractState, stark_proof_serde: StarkProofWithSerde, cairo_version: CairoVersion, - ) -> felt252 { + ) -> (felt252, u32) { 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 security_bits = stark_proof.verify_full( + 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 + self.emit(ProofVerified { job_id: 0, fact, security_bits }); + (fact, security_bits) } } }