Skip to content

Commit 2848e44

Browse files
authored
Merge pull request #33 from HerodotusDev/feat/keccak-mmr-hdp-module-support
Keccak mmr hdp module support
2 parents 0d543ec + 88fc2e8 commit 2848e44

File tree

8 files changed

+212
-54
lines changed

8 files changed

+212
-54
lines changed

cairo/Scarb.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ source = "git+https://github.com/HerodotusDev/cairo-lib.git?branch=cairo_2.11#8b
88

99
[[package]]
1010
name = "integrity"
11-
version = "2.0.0"
12-
source = "git+https://github.com/HerodotusDev/integrity.git#fc39dd8c447de088d8c43e106a08869f5282e00e"
11+
version = "2.1.0"
12+
source = "git+https://github.com/HerodotusDev/integrity.git#331bd29a437452f5321bc5c6d31cdb13b649929b"
1313

1414
[[package]]
1515
name = "openzeppelin"

cairo/deploy.toml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[[call]]
22
call_type = "deploy"
3-
class_hash = "$CLASS_HASH"
3+
class_hash = "0x19ed1f90f98ede33ad93ee15a82759afa27c270169a4a3af80c3ea7915bed0c"
44
inputs = [
55
"$CHAIN_ID",
66
"0",
@@ -15,3 +15,16 @@ call_type = "invoke"
1515
contract_address = "satellite"
1616
function = "setL1MessageSender"
1717
inputs = ["$L1_ADDRESS"]
18+
19+
[[call]]
20+
call_type = "deploy"
21+
class_hash = "0x438e4f756b6339f3ec78c93daf15a9ab69b42836eae40b2f75defe0f04158a6"
22+
inputs = []
23+
id = "evm-growing-inner"
24+
unique = false
25+
26+
[[call]]
27+
call_type = "invoke"
28+
contract_address = "satellite"
29+
function = "_setGrowingInnerContractAddress"
30+
inputs = ["evm-growing-inner"]

cairo/src/data_processor.cairo

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@ struct MmrData {
2222
mmr_size: u256,
2323
}
2424

25+
#[derive(Drop, Serde)]
26+
struct MmrCollection {
27+
poseidon_mmr: Span<MmrData>,
28+
keccak_mmr: Span<MmrData>,
29+
}
30+
2531
#[derive(Drop, Serde)]
2632
struct TaskData {
27-
mmr_data: Span<MmrData>,
33+
mmr_collection: MmrCollection,
2834
task_result_low: u128,
2935
task_result_high: u128,
3036
task_hash_low: u128,
3137
task_hash_high: u128,
32-
module_hash: u256,
3338
program_hash: felt252,
3439
}
3540

@@ -70,15 +75,15 @@ pub trait IDataProcessor<TContractState> {
7075

7176
#[starknet::component]
7277
pub mod data_processor_component {
73-
use integrity::calculate_fact_hash;
78+
use integrity::{SHARP_BOOTLOADER_PROGRAM_HASH, calculate_bootloaded_fact_hash};
7479
use openzeppelin::access::ownable::OwnableComponent;
7580
use openzeppelin::access::ownable::OwnableComponent::InternalTrait as OwnableInternal;
7681
use starknet::storage::{
7782
Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess,
7883
};
7984
use crate::cairo_fact_registry::{ICairoFactRegistry, cairo_fact_registry_component};
80-
use crate::mmr_core::POSEIDON_HASHING_FUNCTION;
8185
use crate::mmr_core::mmr_core_component::MmrCoreExternalImpl;
86+
use crate::mmr_core::{KECCAK_HASHING_FUNCTION, POSEIDON_HASHING_FUNCTION};
8287
use crate::state::state_component;
8388
use super::*;
8489

@@ -211,9 +216,11 @@ pub mod data_processor_component {
211216
program_output.append(task_data.task_hash_high.into());
212217
program_output.append(task_data.task_result_low.into());
213218
program_output.append(task_data.task_result_high.into());
219+
program_output.append(task_data.mmr_collection.poseidon_mmr.len().into());
220+
program_output.append(task_data.mmr_collection.keccak_mmr.len().into());
214221

215222
let state = get_dep_component!(@self, State);
216-
for mmr in task_data.mmr_data {
223+
for mmr in task_data.mmr_collection.poseidon_mmr {
217224
let mmr_root = state
218225
.mmrs
219226
.entry(*mmr.chain_id)
@@ -229,7 +236,31 @@ pub mod data_processor_component {
229236
program_output.append(mmr_root.try_into().expect('mmr_root not felt252'));
230237
}
231238

232-
let fact_hash = calculate_fact_hash(task_data.program_hash, program_output.span());
239+
for mmr in task_data.mmr_collection.keccak_mmr {
240+
let mmr_root = state
241+
.mmrs
242+
.entry(*mmr.chain_id)
243+
.entry(*mmr.mmr_id)
244+
.entry(KECCAK_HASHING_FUNCTION)
245+
.mmr_size_to_root
246+
.entry(*mmr.mmr_size)
247+
.read();
248+
assert(mmr_root != 0, 'InvalidMmrRoot');
249+
program_output.append((*mmr.mmr_id).try_into().expect('mmr_id not felt252'));
250+
program_output.append((*mmr.mmr_size).try_into().expect('mmr_size not felt252'));
251+
program_output.append((*mmr.chain_id).try_into().expect('chain_id not felt252'));
252+
253+
// Split 256-bit root into two 128-bit limbs
254+
let mmr_root_low: u128 = mmr_root.low;
255+
let mmr_root_high: u128 = mmr_root.high;
256+
257+
program_output.append(mmr_root_low.try_into().expect('mmr_root_low not felt252'));
258+
program_output.append(mmr_root_high.try_into().expect('mmr_root_high not felt252'));
259+
}
260+
261+
let fact_hash = calculate_bootloaded_fact_hash(
262+
SHARP_BOOTLOADER_PROGRAM_HASH, task_data.program_hash, program_output.span(),
263+
);
233264

234265
let cairo_fact_registry = get_dep_component!(@self, CairoFactRegistry);
235266
assert(cairo_fact_registry.isCairoFactValidForInternal(fact_hash), 'Invalid fact');
@@ -264,4 +295,3 @@ pub mod data_processor_component {
264295
}
265296
}
266297
}
267-

cairo/src/evm_growing.cairo

Lines changed: 119 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,17 @@ use cairo_lib::data_structures::mmr::proof::Proof;
44
use cairo_lib::hashing::keccak::keccak_cairo_words64;
55
use cairo_lib::hashing::poseidon::hash_words64;
66
use cairo_lib::utils::types::words64::Words64;
7+
use starknet::ContractAddress;
8+
9+
// Growing module is separated into different contract to reduce class size of the Satellite
10+
// contract.
711

812
#[starknet::interface]
913
pub trait IEvmGrowing<TContractState> {
14+
fn _setGrowingInnerContractAddress(
15+
ref self: TContractState, inner_contract_address: ContractAddress,
16+
);
17+
1018
fn onchainEvmAppendBlocksBatch(
1119
ref self: TContractState,
1220
chain_id: u256,
@@ -21,15 +29,17 @@ pub trait IEvmGrowing<TContractState> {
2129

2230
#[starknet::component]
2331
pub mod evm_growing_component {
32+
use openzeppelin::access::ownable::OwnableComponent;
33+
use openzeppelin::access::ownable::OwnableComponent::InternalTrait as OwnableInternal;
2434
use starknet::storage::{StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess};
2535
use crate::mmr_core::{POSEIDON_HASHING_FUNCTION, RootForHashingFunction};
2636
use crate::state::state_component;
27-
use crate::utils::decoders::{decode_block_number, decode_parent_hash, decode_rlp};
28-
use crate::utils::header_rlp_index;
2937
use super::*;
3038

3139
#[storage]
32-
struct Storage {}
40+
struct Storage {
41+
inner_contract_address: ContractAddress,
42+
}
3343

3444
#[derive(Drop, Serde)]
3545
enum GrownBy {
@@ -59,7 +69,15 @@ pub mod evm_growing_component {
5969
+HasComponent<TContractState>,
6070
+Drop<TContractState>,
6171
impl State: state_component::HasComponent<TContractState>,
72+
impl Ownable: OwnableComponent::HasComponent<TContractState>,
6273
> of IEvmGrowing<ComponentState<TContractState>> {
74+
fn _setGrowingInnerContractAddress(
75+
ref self: ComponentState<TContractState>, inner_contract_address: ContractAddress,
76+
) {
77+
get_dep_component!(@self, Ownable).assert_only_owner();
78+
self.inner_contract_address.write(inner_contract_address);
79+
}
80+
6381
fn onchainEvmAppendBlocksBatch(
6482
ref self: ComponentState<TContractState>,
6583
chain_id: u256,
@@ -86,6 +104,102 @@ pub mod evm_growing_component {
86104
.try_into()
87105
.expect('ROOT_DOES_NOT_FIT'),
88106
};
107+
108+
let initial_blockhash = if mmr_proof.is_none() {
109+
let reference_block = reference_block.unwrap();
110+
Some(
111+
state
112+
.received_parent_hashes
113+
.entry(chain_id)
114+
.entry(POSEIDON_HASHING_FUNCTION)
115+
.entry(reference_block)
116+
.read(),
117+
)
118+
} else {
119+
None
120+
};
121+
122+
let (mmr, start_block, end_block) = IEvmGrowingInternalDispatcher {
123+
contract_address: self.inner_contract_address.read(),
124+
}
125+
.inner_onchainEvmAppendBlocksBatch(
126+
chain_id,
127+
headers_rlp,
128+
mmr_peaks,
129+
mmr_id,
130+
reference_block,
131+
mmr_index,
132+
mmr_proof,
133+
mmr,
134+
initial_blockhash,
135+
);
136+
137+
mmr_data.mmr_size_to_root.write(mmr.last_pos, mmr.root.into());
138+
mmr_data.latest_size.write(mmr.last_pos);
139+
140+
self
141+
.emit(
142+
Event::GrownMmr(
143+
GrownMmr {
144+
first_appended_block: start_block,
145+
last_appended_block: end_block,
146+
roots_for_hashing_functions: [
147+
RootForHashingFunction {
148+
hashing_function: POSEIDON_HASHING_FUNCTION,
149+
root: mmr.root.into(),
150+
}
151+
]
152+
.span(),
153+
mmr_size: mmr.last_pos,
154+
mmr_id,
155+
accumulated_chain_id: chain_id,
156+
grown_by: GrownBy::EvmOnChainGrowing,
157+
},
158+
),
159+
);
160+
}
161+
}
162+
}
163+
164+
#[starknet::interface]
165+
trait IEvmGrowingInternal<TContractState> {
166+
fn inner_onchainEvmAppendBlocksBatch(
167+
self: @TContractState,
168+
chain_id: u256,
169+
headers_rlp: Span<Words64>,
170+
mmr_peaks: Peaks,
171+
mmr_id: u256,
172+
reference_block: Option<u256>,
173+
mmr_index: Option<MmrSize>,
174+
mmr_proof: Option<Proof>,
175+
mmr: MMR,
176+
initial_blockhash: Option<u256>,
177+
) -> (MMR, u256, u256);
178+
}
179+
180+
#[starknet::contract]
181+
pub mod evm_growing_contract {
182+
use crate::utils::decoders::{decode_block_number, decode_parent_hash, decode_rlp};
183+
use crate::utils::header_rlp_index;
184+
use super::*;
185+
186+
#[storage]
187+
struct Storage {}
188+
189+
#[abi(embed_v0)]
190+
impl EvmGrowingInternalImpl of IEvmGrowingInternal<ContractState> {
191+
fn inner_onchainEvmAppendBlocksBatch(
192+
self: @ContractState,
193+
chain_id: u256,
194+
mut headers_rlp: Span<Words64>,
195+
mmr_peaks: Peaks,
196+
mmr_id: u256,
197+
reference_block: Option<u256>,
198+
mmr_index: Option<MmrSize>,
199+
mmr_proof: Option<Proof>,
200+
mut mmr: MMR,
201+
initial_blockhash: Option<u256>,
202+
) -> (MMR, u256, u256) {
89203
assert(mmr.root != 0, 'SRC_MMR_NOT_FOUND');
90204

91205
let headers_rlp_len = headers_rlp.len();
@@ -128,13 +242,7 @@ pub mod evm_growing_component {
128242
start_block = reference_block - 1;
129243
end_block = (start_block + 1) - headers_rlp_len.into();
130244

131-
let initial_blockhash = state
132-
.received_parent_hashes
133-
.entry(chain_id)
134-
.entry(POSEIDON_HASHING_FUNCTION)
135-
.entry(reference_block)
136-
.read();
137-
245+
let initial_blockhash = initial_blockhash.unwrap();
138246
assert(initial_blockhash != 0, 'BLOCK_NOT_RECEIVED');
139247
assert(initial_blockhash == poseidon_hash.into(), 'INVALID_INITIAL_HEADER_RLP');
140248

@@ -161,29 +269,7 @@ pub mod evm_growing_component {
161269
peaks = p;
162270
}
163271

164-
mmr_data.mmr_size_to_root.write(mmr.last_pos, mmr.root.into());
165-
mmr_data.latest_size.write(mmr.last_pos);
166-
167-
self
168-
.emit(
169-
Event::GrownMmr(
170-
GrownMmr {
171-
first_appended_block: start_block,
172-
last_appended_block: end_block,
173-
roots_for_hashing_functions: [
174-
RootForHashingFunction {
175-
hashing_function: POSEIDON_HASHING_FUNCTION,
176-
root: mmr.root.into(),
177-
}
178-
]
179-
.span(),
180-
mmr_size: mmr.last_pos,
181-
mmr_id,
182-
accumulated_chain_id: chain_id,
183-
grown_by: GrownBy::EvmOnChainGrowing,
184-
},
185-
),
186-
);
272+
(mmr, start_block, end_block)
187273
}
188274
}
189275
}

cairo/upgrade.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
call_type = "invoke"
33
contract_address = "0x06d523b16d7f6f71e250fc7f8d95df3e9e987a120878ea1a25ff312d92f42c8e"
44
function = "upgrade"
5-
inputs = ["0x5589e2791261df71ab33f11d53bdca615df68f60b517571d2b52b359f820b96"]
5+
inputs = ["0x19ed1f90f98ede33ad93ee15a82759afa27c270169a4a3af80c3ea7915bed0c"]

solidity/src/interfaces/modules/IDataProcessorModule.sol

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,19 @@ interface IDataProcessorModule is IFactsRegistryCommon {
3131
uint256 mmrSize;
3232
}
3333

34-
/// @param mmrData For each used MMR, its chain ID, ID and size
34+
struct MmrCollection {
35+
MmrData[] poseidonMmr;
36+
MmrData[] keccakMmr;
37+
}
38+
39+
/// @param mmrCollection Grouped Poseidon & Keccak MMR data
3540
/// @param taskResultLow The low part of the task result
3641
/// @param taskResultHigh The high part of the task result
3742
/// @param taskHashLow The low part of the task hash
3843
/// @param taskHashHigh The high part of the task hash
3944
/// @param programHash The program hash that was used to compute the task
4045
struct TaskData {
41-
MmrData[] mmrData;
46+
MmrCollection mmrCollection;
4247
uint256 taskResultLow;
4348
uint256 taskResultHigh;
4449
uint256 taskHashLow;

solidity/src/modules/CairoFactRegistryModule.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ contract CairoFactRegistryModule is ICairoFactRegistryModule, AccessController {
4040
/// @inheritdoc ICairoFactRegistryModule
4141
function isCairoVerifiedFactValid(bytes32 factHash) public view returns (bool) {
4242
CairoFactRegistryModuleStorage storage ms = moduleStorage();
43-
return ms.facts[factHash] || address(ms.externalFactRegistry) != address(0) && ms.externalFactRegistry.isValid(factHash);
43+
return ms.facts[factHash] || (address(ms.externalFactRegistry) != address(0) && ms.externalFactRegistry.isValid(factHash));
4444
}
4545

4646
/// @inheritdoc ICairoFactRegistryModule

0 commit comments

Comments
 (0)