Skip to content

Commit

Permalink
feat: solidity compatible keccak (#14)
Browse files Browse the repository at this point in the history
* feat: va tests

* fix: fmt

* fix: mock va

* bytes def

* feat: keccak computation

* feat: refractor

---------

Co-authored-by: 0xevolve <[email protected]>
  • Loading branch information
JordyRo1 and EvolveArt authored Jun 6, 2024
1 parent b71a495 commit 1db67e2
Show file tree
Hide file tree
Showing 9 changed files with 762 additions and 56 deletions.
54 changes: 32 additions & 22 deletions contracts/src/contracts/isms/multisig/validator_announce.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
pub mod validator_announce {
use alexandria_bytes::{Bytes, BytesTrait};
use alexandria_data_structures::array_ext::ArrayTraitExt;
use core::keccak::keccak_u256s_be_inputs;
use core::poseidon::poseidon_hash_span;
use hyperlane_starknet::contracts::libs::checkpoint_lib::checkpoint_lib::{
HYPERLANE_ANNOUNCEMENT
};
use hyperlane_starknet::interfaces::IValidatorAnnounce;
use hyperlane_starknet::interfaces::{IMailboxClientDispatcher, IMailboxClientDispatcherTrait};
use hyperlane_starknet::utils::keccak256::{reverse_endianness, to_eth_signature};
use hyperlane_starknet::utils::keccak256::{
reverse_endianness, to_eth_signature, compute_keccak, ByteData
};
use hyperlane_starknet::utils::store_arrays::StoreFelt252Array;

use starknet::ContractAddress;
use starknet::EthAddress;
use starknet::eth_signature::is_eth_signature_valid;
Expand All @@ -20,7 +21,7 @@ pub mod validator_announce {
struct Storage {
mailboxclient: ContractAddress,
storage_location: LegacyMap::<EthAddress, Array<felt252>>,
replay_protection: LegacyMap::<u256, bool>,
replay_protection: LegacyMap::<felt252, bool>,
validators: LegacyMap::<EthAddress, EthAddress>,
}

Expand Down Expand Up @@ -64,8 +65,9 @@ pub mod validator_announce {
Option::None(()) => { break (); },
}
};
let input = _input.concat(@u256_storage_location);
let replay_id = keccak_hash(input.span());
let replay_id = poseidon_hash_span(
array![felt252_validator].concat(@_storage_location).span()
);
assert(!self.replay_protection.read(replay_id), Errors::REPLAY_PROTECTION_ERROR);
let announcement_digest = self.get_announcement_digest(u256_storage_location);
let signature: Signature = convert_to_signature(_signature);
Expand Down Expand Up @@ -109,13 +111,27 @@ pub mod validator_announce {
fn get_announced_validators(self: @ContractState) -> Span<EthAddress> {
build_validators_array(self)
}
fn get_announcement_digest(self: @ContractState, _storage_location: Array<u256>) -> u256 {

fn get_announcement_digest(
self: @ContractState, mut _storage_location: Array<u256>
) -> u256 {
let domain_hash = domain_hash(self);
let arguments = keccak_u256s_be_inputs(
array![domain_hash.into()].concat(@_storage_location).span()
let mut byte_data_storage_location = array![];
loop {
match _storage_location.pop_front() {
Option::Some(storage) => {
byte_data_storage_location
.append(ByteData { value: storage, is_address: false });
},
Option::None(_) => { break (); }
}
};
let hash = compute_keccak(
array![ByteData { value: domain_hash.into(), is_address: false }]
.concat(@byte_data_storage_location)
.span()
);
let reverse_args = reverse_endianness(arguments);
to_eth_signature(reverse_args)
to_eth_signature(hash)
}
}

Expand All @@ -126,24 +142,18 @@ pub mod validator_announce {
let (_, v) = _signature.read_u8(64);
signature_from_vrs(v.try_into().unwrap(), r, s)
}
fn keccak_hash(_input: Span<u256>) -> u256 {
let hash = keccak_u256s_be_inputs(_input);
reverse_endianness(hash)
}


fn domain_hash(self: @ContractState) -> u256 {
let mailboxclient = IMailboxClientDispatcher {
contract_address: self.mailboxclient.read()
};
let mailboxclient_address: felt252 = self.mailboxclient.read().try_into().unwrap();
let mut input: Array<u256> = array![
mailboxclient.get_local_domain().into(),
mailboxclient_address.try_into().unwrap(),
HYPERLANE_ANNOUNCEMENT.into()
let mut input: Array<ByteData> = array![
ByteData { value: mailboxclient.get_local_domain().into(), is_address: false },
ByteData { value: mailboxclient_address.try_into().unwrap(), is_address: true },
ByteData { value: HYPERLANE_ANNOUNCEMENT.into(), is_address: false }
];
let hash = keccak_u256s_be_inputs(input.span());
reverse_endianness(hash)
compute_keccak(input.span())
}


Expand Down
25 changes: 12 additions & 13 deletions contracts/src/contracts/libs/checkpoint_lib.cairo
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
pub mod checkpoint_lib {
use alexandria_bytes::{Bytes, BytesTrait, BytesStore};
use core::keccak::keccak_u256s_be_inputs;
use hyperlane_starknet::contracts::libs::message::Message;
use hyperlane_starknet::utils::keccak256::reverse_endianness;
use hyperlane_starknet::utils::keccak256::{reverse_endianness, compute_keccak, ByteData};


pub trait CheckpointLib {
Expand All @@ -27,22 +26,22 @@ pub mod checkpoint_lib {
_message_id: u256
) -> u256 {
let domain_hash = CheckpointLib::domain_hash(_origin, _origin_merkle_tree_hook);
let mut input: Array<u256> = array![
domain_hash.into(),
_checkpoint_root.into(),
_checkpoint_index.into(),
_message_id.into(),
let mut input: Array<ByteData> = array![
ByteData { value: domain_hash.into(), is_address: false },
ByteData { value: _checkpoint_root.into(), is_address: false },
ByteData { value: _checkpoint_index.into(), is_address: false },
ByteData { value: _message_id.into(), is_address: false },
];
let hash = keccak_u256s_be_inputs(input.span());
reverse_endianness(hash)
compute_keccak(input.span())
}

fn domain_hash(_origin: u32, _origin_merkle_tree_hook: u256) -> u256 {
let mut input: Array<u256> = array![
_origin.into(), _origin_merkle_tree_hook.into(), HYPERLANE.into()
let mut input: Array<ByteData> = array![
ByteData { value: _origin.into(), is_address: false },
ByteData { value: _origin_merkle_tree_hook.into(), is_address: false },
ByteData { value: HYPERLANE.into(), is_address: false }
];
let hash = keccak_u256s_be_inputs(input.span());
reverse_endianness(hash)
compute_keccak(input.span())
}
}
}
Expand Down
24 changes: 12 additions & 12 deletions contracts/src/contracts/libs/message.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use alexandria_bytes::{Bytes, BytesTrait, BytesStore};
use core::keccak::keccak_u256s_be_inputs;
use core::poseidon::poseidon_hash_span;
use hyperlane_starknet::utils::keccak256::reverse_endianness;
use hyperlane_starknet::utils::keccak256::{reverse_endianness, compute_keccak, ByteData};
use starknet::{ContractAddress, contract_address_const};

pub const HYPERLANE_VERSION: u8 = 3;
Expand Down Expand Up @@ -51,22 +50,23 @@ pub impl MessageImpl of MessageTrait {
let sender: felt252 = _message.sender.into();
let recipient: felt252 = _message.recipient.into();

let mut input: Array<u256> = array![
_message.version.into(),
_message.origin.into(),
sender.into(),
_message.destination.into(),
recipient.into(),
_message.body.size().into()
let mut input: Array<ByteData> = array![
ByteData { value: _message.version.into(), is_address: false },
ByteData { value: _message.origin.into(), is_address: false },
ByteData { value: sender.into(), is_address: true },
ByteData { value: _message.destination.into(), is_address: false },
ByteData { value: recipient.into(), is_address: true },
ByteData { value: _message.body.size().into(), is_address: false },
];
let mut message_data = _message.clone().body.data();
loop {
match message_data.pop_front() {
Option::Some(data) => { input.append(data.into()); },
Option::Some(data) => {
input.append(ByteData { value: data.into(), is_address: false });
},
Option::None(_) => { break (); }
};
};
let hash = keccak_u256s_be_inputs(input.span());
(reverse_endianness(hash), _message)
(compute_keccak(input.span()), _message)
}
}
Loading

0 comments on commit 1db67e2

Please sign in to comment.