Skip to content
This repository was archived by the owner on Aug 1, 2025. It is now read-only.

Commit 58cde22

Browse files
authored
Adding Hash Solidity compatible example (#116)
* docs + contracts + test * renaming + link * fmt * changes requested * nit: fmt
1 parent 54d293b commit 58cde22

File tree

8 files changed

+95
-0
lines changed

8 files changed

+95
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Code generated by scarb DO NOT EDIT.
2+
version = 1
3+
4+
[[package]]
5+
name = "hash_solidity_compatible"
6+
version = "0.1.0"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "hash_solidity_compatible"
3+
version = "0.1.0"
4+
5+
[dependencies]
6+
starknet = ">=2.3.0"
7+
8+
[[target.starknet-contract]]
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#[starknet::interface]
2+
trait ISolidityHashExample<TContractState> {
3+
fn hash_data(ref self: TContractState, input_data: Span<u256>) -> u256;
4+
}
5+
6+
7+
#[starknet::contract]
8+
mod SolidityHashExample {
9+
use keccak::{keccak_u256s_be_inputs};
10+
use array::Span;
11+
12+
#[storage]
13+
struct Storage {}
14+
15+
#[abi(embed_v0)]
16+
impl SolidityHashExample of super::ISolidityHashExample<ContractState> {
17+
fn hash_data(ref self: ContractState, input_data: Span<u256>) -> u256 {
18+
let hashed = keccak_u256s_be_inputs(input_data);
19+
20+
// Split the hashed value into two 128-bit segments
21+
let low: u128 = hashed.low;
22+
let high: u128 = hashed.high;
23+
24+
// Reverse each 128-bit segment
25+
let reversed_low = integer::u128_byte_reverse(low);
26+
let reversed_high = integer::u128_byte_reverse(high);
27+
28+
// Reverse merge the reversed segments back into a u256 value
29+
let compatible_hash = u256 { low: reversed_high, high: reversed_low };
30+
31+
compatible_hash
32+
}
33+
}
34+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
mod contract;
2+
3+
#[cfg(test)]
4+
mod tests;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
mod tests {
2+
use hash_solidity_compatible::{contract::{SolidityHashExample, ISolidityHashExample}};
3+
use debug::PrintTrait;
4+
5+
use starknet::{
6+
ContractAddress, get_contract_address, contract_address_const, call_contract_syscall,
7+
testing::{set_contract_address}
8+
};
9+
10+
fn setup() -> SolidityHashExample::ContractState {
11+
let mut state = SolidityHashExample::contract_state_for_testing();
12+
let contract_address = contract_address_const::<0x1>();
13+
set_contract_address(contract_address);
14+
state
15+
}
16+
17+
#[test]
18+
#[available_gas(2000000000)]
19+
fn get_same_hash_solidity() {
20+
let mut state = setup();
21+
let mut array: Array<u256> = ArrayTrait::new();
22+
array.append(1);
23+
24+
let hash_expected: u256 =
25+
0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6;
26+
let hash_received: u256 = state.hash_data(array.span());
27+
28+
assert(hash_received == hash_expected, 'hash_received != hash_expected');
29+
}
30+
}

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,6 @@ Summary
4343
- [Writing to any storage slot](./ch02/write_to_any_slot.md)
4444
- [Storing Arrays](./ch02/storing_arrays.md)
4545
- [Struct as mapping key](./ch02/struct-mapping-key.md)
46+
- [Hash Solidity Compatible](./ch02/hash-solidity-compatible.md)
4647
- [Optimisations](./ch02/optimisations/optimisations.md)
4748
- [Storage Optimisations](./ch02/optimisations/store_using_packing.md)

src/ch02/hash-solidity-compatible.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Hash Solidity Compatible
2+
3+
This contract demonstrates Keccak hashing in Cairo to match Solidity's keccak256. While both use Keccak, their endianness differs: Cairo is little-endian, Solidity big-endian. The contract achieves compatibility by hashing in big-endian using `keccak_u256s_be_inputs`, and reversing the bytes of the result with `u128_byte_reverse`.
4+
5+
For example:
6+
7+
```rust
8+
{{#include ../../listings/ch02-advanced-concepts/hash_solidity_compatible/src/contract.cairo}}
9+
```
10+
11+
Play with the contract in [Remix](https://remix.ethereum.org/?#activate=Starknet&url=https://github.com/NethermindEth/StarknetByExample/blob/main/listings/ch02-advanced-concepts/hash_solidity_compatible/src/contract.cairo).

0 commit comments

Comments
 (0)