feat(target_chains/starknet): add multi-purpose keccak hasher
This commit is contained in:
parent
5fac32fa40
commit
30c741ed49
|
@ -0,0 +1,122 @@
|
||||||
|
use super::reader::{Reader, ReaderImpl};
|
||||||
|
use core::cmp::min;
|
||||||
|
use core::integer::u128_byte_reverse;
|
||||||
|
use pyth::util::{
|
||||||
|
ONE_SHIFT_160, UNEXPECTED_OVERFLOW, UNEXPECTED_ZERO, ONE_SHIFT_64, one_shift_left_bytes_u64,
|
||||||
|
u64_byte_reverse,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Allows to push data as big endian to a buffer and apply
|
||||||
|
/// the keccak256 hash.
|
||||||
|
#[derive(Drop, Debug)]
|
||||||
|
pub struct Hasher {
|
||||||
|
// Inputs in little endian.
|
||||||
|
inputs_le: Array<u64>,
|
||||||
|
// Last pushed bytes in big endian.
|
||||||
|
last_be: u64,
|
||||||
|
// Number of filled bytes in `self.last_be`.
|
||||||
|
num_last_bytes: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[generate_trait]
|
||||||
|
pub impl HasherImpl of HasherTrait {
|
||||||
|
/// Creates an empty hasher.
|
||||||
|
fn new() -> Hasher {
|
||||||
|
Hasher { inputs_le: array![], last_be: 0, num_last_bytes: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_u8(ref self: Hasher, value: u8) {
|
||||||
|
self.push_to_last(value.into(), 1);
|
||||||
|
}
|
||||||
|
fn push_u16(ref self: Hasher, value: u16) {
|
||||||
|
self.push_num_bytes(value.into(), 2);
|
||||||
|
}
|
||||||
|
fn push_u32(ref self: Hasher, value: u32) {
|
||||||
|
self.push_num_bytes(value.into(), 4);
|
||||||
|
}
|
||||||
|
fn push_u64(ref self: Hasher, value: u64) {
|
||||||
|
self.push_num_bytes(value, 8);
|
||||||
|
}
|
||||||
|
fn push_u128(ref self: Hasher, value: u128) {
|
||||||
|
let divisor = ONE_SHIFT_64.try_into().expect(UNEXPECTED_ZERO);
|
||||||
|
let (high, low) = DivRem::div_rem(value, divisor);
|
||||||
|
self.push_u64(high.try_into().expect(UNEXPECTED_OVERFLOW));
|
||||||
|
self.push_u64(low.try_into().expect(UNEXPECTED_OVERFLOW));
|
||||||
|
}
|
||||||
|
fn push_u160(ref self: Hasher, value: u256) {
|
||||||
|
assert!(value / ONE_SHIFT_160 == 0, "u160 value too big");
|
||||||
|
self.push_num_bytes(value.high.try_into().expect(UNEXPECTED_OVERFLOW), 4);
|
||||||
|
self.push_u128(value.low);
|
||||||
|
}
|
||||||
|
fn push_u256(ref self: Hasher, value: u256) {
|
||||||
|
self.push_u128(value.high);
|
||||||
|
self.push_u128(value.low);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads all remaining data from the reader and pushes it to
|
||||||
|
/// the hashing buffer.
|
||||||
|
fn push_reader(ref self: Hasher, ref reader: Reader) -> Result<(), felt252> {
|
||||||
|
let mut result = Result::Ok(());
|
||||||
|
while reader.len() > 0 {
|
||||||
|
let mut chunk_len = 8 - self.num_last_bytes;
|
||||||
|
if reader.len() < chunk_len.into() {
|
||||||
|
// reader.len() < 8
|
||||||
|
chunk_len = reader.len().try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
|
}
|
||||||
|
match reader.read_num_bytes(chunk_len) {
|
||||||
|
Result::Ok(value) => {
|
||||||
|
// chunk_len <= 8 so value must fit in u64.
|
||||||
|
self.push_to_last(value.try_into().expect(UNEXPECTED_OVERFLOW), chunk_len);
|
||||||
|
},
|
||||||
|
Result::Err(err) => {
|
||||||
|
result = Result::Err(err);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the keccak256 hash of the buffer. The output hash is interpreted
|
||||||
|
/// as a big endian unsigned integer.
|
||||||
|
fn finalize(ref self: Hasher) -> u256 {
|
||||||
|
let last_le = if self.num_last_bytes == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
u64_byte_reverse(self.last_be) / one_shift_left_bytes_u64(8 - self.num_last_bytes)
|
||||||
|
};
|
||||||
|
let hash_le = core::keccak::cairo_keccak(
|
||||||
|
ref self.inputs_le, last_le, self.num_last_bytes.into()
|
||||||
|
);
|
||||||
|
u256 { low: u128_byte_reverse(hash_le.high), high: u128_byte_reverse(hash_le.low), }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[generate_trait]
|
||||||
|
impl HasherPrivateImpl of HasherPrivateTrait {
|
||||||
|
// Adds specified number of bytes to the buffer.
|
||||||
|
fn push_num_bytes(ref self: Hasher, value: u64, num_bytes: u8) {
|
||||||
|
assert!(num_bytes <= 8, "num_bytes too high in Hasher::push_num_bytes");
|
||||||
|
let num_high_bytes = min(num_bytes, 8 - self.num_last_bytes);
|
||||||
|
let num_low_bytes = num_bytes - num_high_bytes;
|
||||||
|
let divisor = one_shift_left_bytes_u64(num_low_bytes).try_into().expect(UNEXPECTED_ZERO);
|
||||||
|
let (high, low) = DivRem::div_rem(value, divisor);
|
||||||
|
self.push_to_last(high, num_high_bytes);
|
||||||
|
self.push_to_last(low, num_low_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_to_last(ref self: Hasher, value: u64, num_bytes: u8) {
|
||||||
|
assert!(num_bytes <= 8 - self.num_last_bytes, "num_bytes too high in Hasher::push_to_last");
|
||||||
|
if num_bytes == 8 {
|
||||||
|
self.last_be = value;
|
||||||
|
} else {
|
||||||
|
self.last_be = self.last_be * one_shift_left_bytes_u64(num_bytes) + value;
|
||||||
|
};
|
||||||
|
self.num_last_bytes += num_bytes;
|
||||||
|
if self.num_last_bytes == 8 {
|
||||||
|
self.inputs_le.append(u64_byte_reverse(self.last_be));
|
||||||
|
self.last_be = 0;
|
||||||
|
self.num_last_bytes = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod pyth;
|
pub mod pyth;
|
||||||
pub mod wormhole;
|
pub mod wormhole;
|
||||||
pub mod reader;
|
pub mod reader;
|
||||||
|
pub mod hash;
|
||||||
|
mod util;
|
||||||
|
|
|
@ -3,9 +3,11 @@ use core::array::ArrayTrait;
|
||||||
use core::keccak::cairo_keccak;
|
use core::keccak::cairo_keccak;
|
||||||
use core::integer::u128_byte_reverse;
|
use core::integer::u128_byte_reverse;
|
||||||
use core::fmt::{Debug, Formatter};
|
use core::fmt::{Debug, Formatter};
|
||||||
|
use pyth::util::{UNEXPECTED_OVERFLOW, UNEXPECTED_ZERO, one_shift_left_bytes_u128};
|
||||||
|
|
||||||
pub const EOF: felt252 = 'unexpected end of input';
|
pub mod error_codes {
|
||||||
pub const UNEXPECTED_OVERFLOW: felt252 = 'unexpected overflow';
|
pub const EOF: felt252 = 'unexpected end of input';
|
||||||
|
}
|
||||||
|
|
||||||
/// A byte array with storage format similar to `core::ByteArray`, but
|
/// A byte array with storage format similar to `core::ByteArray`, but
|
||||||
/// suitable for reading data from it.
|
/// suitable for reading data from it.
|
||||||
|
@ -70,8 +72,7 @@ pub impl ByteArrayImpl of ByteArrayTrait {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows to read data from a byte array.
|
/// Allows to read data from a byte array as big endian integers.
|
||||||
/// Uses big endian unless specified otherwise.
|
|
||||||
/// All methods return `EOF` error if attempted to
|
/// All methods return `EOF` error if attempted to
|
||||||
/// read more bytes than is available.
|
/// read more bytes than is available.
|
||||||
#[derive(Drop, Clone)]
|
#[derive(Drop, Clone)]
|
||||||
|
@ -94,7 +95,8 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the specified number of bytes (up to 16) as a big endian unsigned integer.
|
/// Reads the specified number of bytes (up to 16) as a big endian unsigned integer.
|
||||||
fn read(ref self: Reader, num_bytes: u8) -> Result<u128, felt252> {
|
fn read_num_bytes(ref self: Reader, num_bytes: u8) -> Result<u128, felt252> {
|
||||||
|
assert!(num_bytes <= 16, "Reader::read_num_bytes: num_bytes is too large");
|
||||||
if num_bytes <= self.num_current_bytes {
|
if num_bytes <= self.num_current_bytes {
|
||||||
let x = self.read_from_current(num_bytes);
|
let x = self.read_from_current(num_bytes);
|
||||||
return Result::Ok(x);
|
return Result::Ok(x);
|
||||||
|
@ -102,7 +104,7 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
let num_low_bytes = num_bytes - self.num_current_bytes;
|
let num_low_bytes = num_bytes - self.num_current_bytes;
|
||||||
let high = self.current;
|
let high = self.current;
|
||||||
self.fetch_next()?;
|
self.fetch_next()?;
|
||||||
let low = self.read(num_low_bytes)?;
|
let low = self.read_num_bytes(num_low_bytes)?;
|
||||||
let value = if num_low_bytes == 16 {
|
let value = if num_low_bytes == 16 {
|
||||||
low
|
low
|
||||||
} else {
|
} else {
|
||||||
|
@ -112,28 +114,34 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_u256(ref self: Reader) -> Result<u256, felt252> {
|
fn read_u256(ref self: Reader) -> Result<u256, felt252> {
|
||||||
let high = self.read(16)?;
|
let high = self.read_num_bytes(16)?;
|
||||||
let low = self.read(16)?;
|
let low = self.read_num_bytes(16)?;
|
||||||
|
let value = u256 { high, low };
|
||||||
|
Result::Ok(value)
|
||||||
|
}
|
||||||
|
fn read_u160(ref self: Reader) -> Result<u256, felt252> {
|
||||||
|
let high = self.read_num_bytes(4)?;
|
||||||
|
let low = self.read_num_bytes(16)?;
|
||||||
let value = u256 { high, low };
|
let value = u256 { high, low };
|
||||||
Result::Ok(value)
|
Result::Ok(value)
|
||||||
}
|
}
|
||||||
fn read_u128(ref self: Reader) -> Result<u128, felt252> {
|
fn read_u128(ref self: Reader) -> Result<u128, felt252> {
|
||||||
self.read(16)
|
self.read_num_bytes(16)
|
||||||
}
|
}
|
||||||
fn read_u64(ref self: Reader) -> Result<u64, felt252> {
|
fn read_u64(ref self: Reader) -> Result<u64, felt252> {
|
||||||
let value = self.read(8)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value = self.read_num_bytes(8)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
Result::Ok(value)
|
Result::Ok(value)
|
||||||
}
|
}
|
||||||
fn read_u32(ref self: Reader) -> Result<u32, felt252> {
|
fn read_u32(ref self: Reader) -> Result<u32, felt252> {
|
||||||
let value = self.read(4)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value = self.read_num_bytes(4)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
Result::Ok(value)
|
Result::Ok(value)
|
||||||
}
|
}
|
||||||
fn read_u16(ref self: Reader) -> Result<u16, felt252> {
|
fn read_u16(ref self: Reader) -> Result<u16, felt252> {
|
||||||
let value = self.read(2)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value = self.read_num_bytes(2)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
Result::Ok(value)
|
Result::Ok(value)
|
||||||
}
|
}
|
||||||
fn read_u8(ref self: Reader) -> Result<u8, felt252> {
|
fn read_u8(ref self: Reader) -> Result<u8, felt252> {
|
||||||
let value = self.read(1)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value = self.read_num_bytes(1)?.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
Result::Ok(value)
|
Result::Ok(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,7 +150,7 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
let mut result = Result::Ok(());
|
let mut result = Result::Ok(());
|
||||||
while num_bytes > 0 {
|
while num_bytes > 0 {
|
||||||
if num_bytes > 16 {
|
if num_bytes > 16 {
|
||||||
match self.read(16) {
|
match self.read_num_bytes(16) {
|
||||||
Result::Ok(_) => {},
|
Result::Ok(_) => {},
|
||||||
Result::Err(err) => {
|
Result::Err(err) => {
|
||||||
result = Result::Err(err);
|
result = Result::Err(err);
|
||||||
|
@ -151,7 +159,7 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
}
|
}
|
||||||
num_bytes -= 16;
|
num_bytes -= 16;
|
||||||
} else {
|
} else {
|
||||||
match self.read(num_bytes) {
|
match self.read_num_bytes(num_bytes) {
|
||||||
Result::Ok(_) => {},
|
Result::Ok(_) => {},
|
||||||
Result::Err(err) => {
|
Result::Err(err) => {
|
||||||
result = Result::Err(err);
|
result = Result::Err(err);
|
||||||
|
@ -165,7 +173,7 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the specified number of bytes as a new byte array.
|
/// Reads the specified number of bytes as a new byte array.
|
||||||
fn read_bytes(ref self: Reader, num_bytes: usize) -> Result<ByteArray, felt252> {
|
fn read_byte_array(ref self: Reader, num_bytes: usize) -> Result<ByteArray, felt252> {
|
||||||
let mut array: Array<bytes31> = array![];
|
let mut array: Array<bytes31> = array![];
|
||||||
let mut num_last_bytes = Option::None;
|
let mut num_last_bytes = Option::None;
|
||||||
let mut num_remaining_bytes = num_bytes;
|
let mut num_remaining_bytes = num_bytes;
|
||||||
|
@ -204,40 +212,6 @@ pub impl ReaderImpl of ReaderTrait {
|
||||||
};
|
};
|
||||||
self.num_current_bytes.into() + num_next_bytes + self.array.len()
|
self.num_current_bytes.into() + num_next_bytes + self.array.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the specified number of bytes (up to 16) as a little endian unsigned integer.
|
|
||||||
fn read_le(ref self: Reader, num_bytes: u8) -> Result<u128, felt252> {
|
|
||||||
if num_bytes == 0 {
|
|
||||||
return Result::Ok(0);
|
|
||||||
}
|
|
||||||
let value = u128_byte_reverse(self.read(num_bytes)?)
|
|
||||||
/ one_shift_left_bytes_u128(16 - num_bytes);
|
|
||||||
Result::Ok(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads and hashes all the remaining data.
|
|
||||||
fn keccak256(ref self: Reader) -> Result<u256, felt252> {
|
|
||||||
let mut data: Array<u64> = array![];
|
|
||||||
|
|
||||||
let mut result = Result::Ok(());
|
|
||||||
while self.len() >= 8 {
|
|
||||||
match self.read_le(8) {
|
|
||||||
Result::Ok(value) => { data.append(value.try_into().expect(UNEXPECTED_OVERFLOW)); },
|
|
||||||
Result::Err(err) => {
|
|
||||||
result = Result::Err(err);
|
|
||||||
break;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
};
|
|
||||||
result?;
|
|
||||||
|
|
||||||
let last_len = self.len();
|
|
||||||
// last_len < 8
|
|
||||||
let last = self.read_le(last_len.try_into().expect(UNEXPECTED_OVERFLOW))?;
|
|
||||||
let last = last.try_into().expect(UNEXPECTED_OVERFLOW);
|
|
||||||
let hash = cairo_keccak(ref data, last, last_len);
|
|
||||||
Result::Ok(hash)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[generate_trait]
|
#[generate_trait]
|
||||||
|
@ -246,9 +220,10 @@ impl ReaderPrivateImpl of ReaderPrivateTrait {
|
||||||
/// Panics if attempted to read more than `self.num_current_bytes`.
|
/// Panics if attempted to read more than `self.num_current_bytes`.
|
||||||
fn read_from_current(ref self: Reader, num_bytes: u8) -> u128 {
|
fn read_from_current(ref self: Reader, num_bytes: u8) -> u128 {
|
||||||
let num_remaining_bytes = self.num_current_bytes - num_bytes;
|
let num_remaining_bytes = self.num_current_bytes - num_bytes;
|
||||||
let divisor = one_shift_left_bytes_u128(num_remaining_bytes);
|
let divisor = one_shift_left_bytes_u128(num_remaining_bytes)
|
||||||
// divisor != 0
|
.try_into()
|
||||||
let (high, low) = DivRem::div_rem(self.current, divisor.try_into().unwrap());
|
.expect(UNEXPECTED_ZERO);
|
||||||
|
let (high, low) = DivRem::div_rem(self.current, divisor);
|
||||||
self.current = low;
|
self.current = low;
|
||||||
self.num_current_bytes = num_remaining_bytes;
|
self.num_current_bytes = num_remaining_bytes;
|
||||||
high
|
high
|
||||||
|
@ -265,7 +240,7 @@ impl ReaderPrivateImpl of ReaderPrivateTrait {
|
||||||
self.num_current_bytes = 16;
|
self.num_current_bytes = 16;
|
||||||
},
|
},
|
||||||
Option::None => {
|
Option::None => {
|
||||||
let (value, bytes) = self.array.pop_front().ok_or(EOF)?;
|
let (value, bytes) = self.array.pop_front().ok_or(error_codes::EOF)?;
|
||||||
let value: u256 = value.into();
|
let value: u256 = value.into();
|
||||||
if bytes > 16 {
|
if bytes > 16 {
|
||||||
self.current = value.high;
|
self.current = value.high;
|
||||||
|
@ -285,49 +260,25 @@ impl ReaderPrivateImpl of ReaderPrivateTrait {
|
||||||
ref self: Reader, num_bytes: usize, ref array: Array<bytes31>
|
ref self: Reader, num_bytes: usize, ref array: Array<bytes31>
|
||||||
) -> Result<(usize, bool), felt252> {
|
) -> Result<(usize, bool), felt252> {
|
||||||
if num_bytes >= 31 {
|
if num_bytes >= 31 {
|
||||||
let high = self.read(15)?;
|
let high = self.read_num_bytes(15)?;
|
||||||
let low = self.read(16)?;
|
let low = self.read_num_bytes(16)?;
|
||||||
let value: felt252 = u256 { high, low }.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value: felt252 = u256 { high, low }.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
array.append(value.try_into().expect(UNEXPECTED_OVERFLOW));
|
array.append(value.try_into().expect(UNEXPECTED_OVERFLOW));
|
||||||
Result::Ok((31, false))
|
Result::Ok((31, false))
|
||||||
} else if num_bytes > 16 {
|
} else if num_bytes > 16 {
|
||||||
// num_bytes < 31
|
// num_bytes < 31
|
||||||
let high = self.read((num_bytes - 16).try_into().expect(UNEXPECTED_OVERFLOW))?;
|
let high = self
|
||||||
let low = self.read(16)?;
|
.read_num_bytes((num_bytes - 16).try_into().expect(UNEXPECTED_OVERFLOW))?;
|
||||||
|
let low = self.read_num_bytes(16)?;
|
||||||
let value: felt252 = u256 { high, low }.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value: felt252 = u256 { high, low }.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
array.append(value.try_into().expect(UNEXPECTED_OVERFLOW));
|
array.append(value.try_into().expect(UNEXPECTED_OVERFLOW));
|
||||||
Result::Ok((num_bytes, true))
|
Result::Ok((num_bytes, true))
|
||||||
} else {
|
} else {
|
||||||
// bytes < 16
|
// bytes < 16
|
||||||
let low = self.read(num_bytes.try_into().expect(UNEXPECTED_OVERFLOW))?;
|
let low = self.read_num_bytes(num_bytes.try_into().expect(UNEXPECTED_OVERFLOW))?;
|
||||||
let value: felt252 = low.try_into().expect(UNEXPECTED_OVERFLOW);
|
let value: felt252 = low.try_into().expect(UNEXPECTED_OVERFLOW);
|
||||||
array.append(value.try_into().expect(UNEXPECTED_OVERFLOW));
|
array.append(value.try_into().expect(UNEXPECTED_OVERFLOW));
|
||||||
Result::Ok((num_bytes, true))
|
Result::Ok((num_bytes, true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns 1 << (8 * `n_bytes`) as u128, where `n_bytes` must be < BYTES_IN_U128.
|
|
||||||
//
|
|
||||||
// Panics if `n_bytes >= 16`.
|
|
||||||
fn one_shift_left_bytes_u128(n_bytes: u8) -> u128 {
|
|
||||||
match n_bytes {
|
|
||||||
0 => 0x1,
|
|
||||||
1 => 0x100,
|
|
||||||
2 => 0x10000,
|
|
||||||
3 => 0x1000000,
|
|
||||||
4 => 0x100000000,
|
|
||||||
5 => 0x10000000000,
|
|
||||||
6 => 0x1000000000000,
|
|
||||||
7 => 0x100000000000000,
|
|
||||||
8 => 0x10000000000000000,
|
|
||||||
9 => 0x1000000000000000000,
|
|
||||||
10 => 0x100000000000000000000,
|
|
||||||
11 => 0x10000000000000000000000,
|
|
||||||
12 => 0x1000000000000000000000000,
|
|
||||||
13 => 0x100000000000000000000000000,
|
|
||||||
14 => 0x10000000000000000000000000000,
|
|
||||||
15 => 0x1000000000000000000000000000000,
|
|
||||||
_ => core::panic_with_felt252('n_bytes too big'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
use core::integer::u128_byte_reverse;
|
||||||
|
|
||||||
|
pub const ONE_SHIFT_160: u256 = 0x10000000000000000000000000000000000000000;
|
||||||
|
pub const ONE_SHIFT_96: u256 = 0x1000000000000000000000000;
|
||||||
|
|
||||||
|
pub const ONE_SHIFT_64: u128 = 0x10000000000000000;
|
||||||
|
|
||||||
|
pub const UNEXPECTED_OVERFLOW: felt252 = 'unexpected overflow';
|
||||||
|
pub const UNEXPECTED_ZERO: felt252 = 'unexpected zero';
|
||||||
|
|
||||||
|
// Returns 1 << (8 * `n_bytes`) as u128, where `n_bytes` must be < BYTES_IN_U128.
|
||||||
|
//
|
||||||
|
// Panics if `n_bytes >= 16`.
|
||||||
|
pub fn one_shift_left_bytes_u128(n_bytes: u8) -> u128 {
|
||||||
|
match n_bytes {
|
||||||
|
0 => 0x1,
|
||||||
|
1 => 0x100,
|
||||||
|
2 => 0x10000,
|
||||||
|
3 => 0x1000000,
|
||||||
|
4 => 0x100000000,
|
||||||
|
5 => 0x10000000000,
|
||||||
|
6 => 0x1000000000000,
|
||||||
|
7 => 0x100000000000000,
|
||||||
|
8 => 0x10000000000000000,
|
||||||
|
9 => 0x1000000000000000000,
|
||||||
|
10 => 0x100000000000000000000,
|
||||||
|
11 => 0x10000000000000000000000,
|
||||||
|
12 => 0x1000000000000000000000000,
|
||||||
|
13 => 0x100000000000000000000000000,
|
||||||
|
14 => 0x10000000000000000000000000000,
|
||||||
|
15 => 0x1000000000000000000000000000000,
|
||||||
|
_ => core::panic_with_felt252('n_bytes too big'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns 1 << (8 * `n_bytes`) as u64.
|
||||||
|
//
|
||||||
|
// Panics if `n_bytes >= 8`.
|
||||||
|
pub fn one_shift_left_bytes_u64(n_bytes: u8) -> u64 {
|
||||||
|
match n_bytes {
|
||||||
|
0 => 0x1,
|
||||||
|
1 => 0x100,
|
||||||
|
2 => 0x10000,
|
||||||
|
3 => 0x1000000,
|
||||||
|
4 => 0x100000000,
|
||||||
|
5 => 0x10000000000,
|
||||||
|
6 => 0x1000000000000,
|
||||||
|
7 => 0x100000000000000,
|
||||||
|
_ => core::panic_with_felt252('n_bytes too big'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn u64_byte_reverse(value: u64) -> u64 {
|
||||||
|
let reversed = u128_byte_reverse(value.into()) / ONE_SHIFT_64.try_into().expect('not zero');
|
||||||
|
reversed.try_into().unwrap()
|
||||||
|
}
|
|
@ -54,7 +54,7 @@ mod wormhole {
|
||||||
use core::box::BoxTrait;
|
use core::box::BoxTrait;
|
||||||
use core::array::ArrayTrait;
|
use core::array::ArrayTrait;
|
||||||
use super::{VM, IWormhole, GuardianSignature, error_codes, quorum};
|
use super::{VM, IWormhole, GuardianSignature, error_codes, quorum};
|
||||||
use pyth::reader::{Reader, ReaderImpl, ByteArray, UNEXPECTED_OVERFLOW};
|
use pyth::reader::{Reader, ReaderImpl, ByteArray};
|
||||||
use core::starknet::secp256_trait::{Signature, recover_public_key, Secp256PointTrait};
|
use core::starknet::secp256_trait::{Signature, recover_public_key, Secp256PointTrait};
|
||||||
use core::starknet::secp256k1::Secp256k1Point;
|
use core::starknet::secp256k1::Secp256k1Point;
|
||||||
use core::starknet::{
|
use core::starknet::{
|
||||||
|
@ -63,6 +63,8 @@ mod wormhole {
|
||||||
use core::keccak::cairo_keccak;
|
use core::keccak::cairo_keccak;
|
||||||
use core::integer::u128_byte_reverse;
|
use core::integer::u128_byte_reverse;
|
||||||
use core::panic_with_felt252;
|
use core::panic_with_felt252;
|
||||||
|
use pyth::hash::{Hasher, HasherImpl};
|
||||||
|
use pyth::util::{ONE_SHIFT_160, UNEXPECTED_OVERFLOW};
|
||||||
|
|
||||||
#[derive(Drop, Debug, Clone, Serde, starknet::Store)]
|
#[derive(Drop, Debug, Clone, Serde, starknet::Store)]
|
||||||
struct GuardianSet {
|
struct GuardianSet {
|
||||||
|
@ -224,12 +226,12 @@ mod wormhole {
|
||||||
result?;
|
result?;
|
||||||
|
|
||||||
let mut reader_for_hash = reader.clone();
|
let mut reader_for_hash = reader.clone();
|
||||||
let body_hash1_le = reader_for_hash.keccak256()?;
|
let mut hasher = HasherImpl::new();
|
||||||
let mut body_hash1_le_u64s = split_hash(body_hash1_le);
|
hasher.push_reader(ref reader_for_hash)?;
|
||||||
let body_hash2_le = cairo_keccak(ref body_hash1_le_u64s, 0, 0);
|
let body_hash1 = hasher.finalize();
|
||||||
let body_hash2 = u256 {
|
let mut hasher2 = HasherImpl::new();
|
||||||
low: u128_byte_reverse(body_hash2_le.high), high: u128_byte_reverse(body_hash2_le.low),
|
hasher2.push_u256(body_hash1);
|
||||||
};
|
let body_hash2 = hasher2.finalize();
|
||||||
|
|
||||||
let timestamp = reader.read_u32()?;
|
let timestamp = reader.read_u32()?;
|
||||||
let nonce = reader.read_u32()?;
|
let nonce = reader.read_u32()?;
|
||||||
|
@ -238,7 +240,7 @@ mod wormhole {
|
||||||
let sequence = reader.read_u64()?;
|
let sequence = reader.read_u64()?;
|
||||||
let consistency_level = reader.read_u8()?;
|
let consistency_level = reader.read_u8()?;
|
||||||
let payload_len = reader.len();
|
let payload_len = reader.len();
|
||||||
let payload = reader.read_bytes(payload_len)?;
|
let payload = reader.read_byte_array(payload_len)?;
|
||||||
|
|
||||||
let vm = VM {
|
let vm = VM {
|
||||||
version,
|
version,
|
||||||
|
@ -270,53 +272,16 @@ mod wormhole {
|
||||||
Result::Ok(())
|
Result::Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
const ONE_SHIFT_64: u256 = 0x10000000000000000;
|
|
||||||
const ONE_SHIFT_160: u256 = 0x10000000000000000000000000000000000000000;
|
|
||||||
|
|
||||||
fn eth_address(point: Secp256k1Point) -> Result<u256, felt252> {
|
fn eth_address(point: Secp256k1Point) -> Result<u256, felt252> {
|
||||||
let (x, y) = match point.get_coordinates() {
|
let (x, y) = match point.get_coordinates() {
|
||||||
Result::Ok(v) => { v },
|
Result::Ok(v) => { v },
|
||||||
Result::Err(_) => { return Result::Err(error_codes::INVALID_SIGNATURE); },
|
Result::Err(_) => { return Result::Err(error_codes::INVALID_SIGNATURE); },
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut array = array![];
|
let mut hasher = HasherImpl::new();
|
||||||
push_reversed(ref array, x);
|
hasher.push_u256(x);
|
||||||
push_reversed(ref array, y);
|
hasher.push_u256(y);
|
||||||
let key_hash = cairo_keccak(ref array, 0, 0);
|
let address = hasher.finalize() % ONE_SHIFT_160;
|
||||||
let reversed_key_hash = u256 {
|
Result::Ok(address)
|
||||||
low: u128_byte_reverse(key_hash.high), high: u128_byte_reverse(key_hash.low)
|
|
||||||
};
|
|
||||||
Result::Ok(reversed_key_hash % ONE_SHIFT_160)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn split_hash(val: u256) -> Array<u64> {
|
|
||||||
let divisor = ONE_SHIFT_64.try_into().expect('not zero');
|
|
||||||
let (val, v1) = DivRem::div_rem(val, divisor);
|
|
||||||
let (val, v2) = DivRem::div_rem(val, divisor);
|
|
||||||
let (val, v3) = DivRem::div_rem(val, divisor);
|
|
||||||
|
|
||||||
array![
|
|
||||||
v1.try_into().expect(UNEXPECTED_OVERFLOW),
|
|
||||||
v2.try_into().expect(UNEXPECTED_OVERFLOW),
|
|
||||||
v3.try_into().expect(UNEXPECTED_OVERFLOW),
|
|
||||||
val.try_into().expect(UNEXPECTED_OVERFLOW),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push_reversed(ref array: Array<u64>, val: u256) {
|
|
||||||
let divisor = ONE_SHIFT_64.try_into().expect('not zero');
|
|
||||||
let (val, v1) = DivRem::div_rem(val, divisor);
|
|
||||||
let (val, v2) = DivRem::div_rem(val, divisor);
|
|
||||||
let (val, v3) = DivRem::div_rem(val, divisor);
|
|
||||||
|
|
||||||
array.append(u64_byte_reverse(val.try_into().expect(UNEXPECTED_OVERFLOW)));
|
|
||||||
array.append(u64_byte_reverse(v3.try_into().expect(UNEXPECTED_OVERFLOW)));
|
|
||||||
array.append(u64_byte_reverse(v2.try_into().expect(UNEXPECTED_OVERFLOW)));
|
|
||||||
array.append(u64_byte_reverse(v1.try_into().expect(UNEXPECTED_OVERFLOW)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn u64_byte_reverse(value: u128) -> u64 {
|
|
||||||
let reversed = u128_byte_reverse(value) / ONE_SHIFT_64.try_into().expect('not zero');
|
|
||||||
reversed.try_into().expect(UNEXPECTED_OVERFLOW)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue