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 u256. // // Panics if `n_bytes >= 32`. pub fn one_shift_left_bytes_u256(n_bytes: u8) -> u256 { 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, 16 => 0x100000000000000000000000000000000, 17 => 0x10000000000000000000000000000000000, 18 => 0x1000000000000000000000000000000000000, 19 => 0x100000000000000000000000000000000000000, 20 => 0x10000000000000000000000000000000000000000, 21 => 0x1000000000000000000000000000000000000000000, 22 => 0x100000000000000000000000000000000000000000000, 23 => 0x10000000000000000000000000000000000000000000000, 24 => 0x1000000000000000000000000000000000000000000000000, 25 => 0x100000000000000000000000000000000000000000000000000, 26 => 0x10000000000000000000000000000000000000000000000000000, 27 => 0x1000000000000000000000000000000000000000000000000000000, 28 => 0x100000000000000000000000000000000000000000000000000000000, 29 => 0x10000000000000000000000000000000000000000000000000000000000, 30 => 0x1000000000000000000000000000000000000000000000000000000000000, 31 => 0x100000000000000000000000000000000000000000000000000000000000000, _ => core::panic_with_felt252('n_bytes too big'), } } // Returns 1 << (8 * `n_bytes`) as 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() } /// If `self` is an error, panics with a `felt252` value /// corresponding to the error. Otherwise, returns the success value. /// This differs from `Result::unwrap` which always panics with /// the same message and doesn't include information about the error. pub trait UnwrapWithFelt252 { fn unwrap_with_felt252(self: Result) -> T; } /// Reinterpret `u64` as `i64` as if it was a two's complement binary representation. pub fn u64_as_i64(value: u64) -> i64 { if value < 0x8000000000000000 { value.try_into().unwrap() } else { let value: i128 = value.into(); (value - 0x10000000000000000).try_into().unwrap() } } /// Reinterpret `u32` as `i32` as if it was a two's complement binary representation. pub fn u32_as_i32(value: u32) -> i32 { if value < 0x80000000 { value.try_into().unwrap() } else { let value: i64 = value.into(); (value - 0x100000000).try_into().unwrap() } } pub fn array_felt252_to_bytes31(mut input: Array) -> Array { let mut output = array![]; loop { match input.pop_front() { Option::Some(v) => { output.append(v.try_into().unwrap()); }, Option::None => { break; }, } }; output } #[cfg(test)] mod tests { use super::{u64_as_i64, u32_as_i32}; #[test] fn test_u64_as_i64() { assert!(u64_as_i64(0) == 0); assert!(u64_as_i64(1) == 1); assert!(u64_as_i64(2) == 2); assert!(u64_as_i64(3) == 3); assert!(u64_as_i64(9223372036854775806) == 9223372036854775806); assert!(u64_as_i64(9223372036854775807) == 9223372036854775807); assert!(u64_as_i64(9223372036854775808) == -9223372036854775808); assert!(u64_as_i64(9223372036854775809) == -9223372036854775807); assert!(u64_as_i64(18446744073709551614) == -2); assert!(u64_as_i64(18446744073709551615) == -1); } #[test] fn test_u32_as_i32() { assert!(u32_as_i32(0) == 0); assert!(u32_as_i32(1) == 1); assert!(u32_as_i32(2) == 2); assert!(u32_as_i32(3) == 3); assert!(u32_as_i32(2147483646) == 2147483646); assert!(u32_as_i32(2147483647) == 2147483647); assert!(u32_as_i32(2147483648) == -2147483648); assert!(u32_as_i32(2147483649) == -2147483647); assert!(u32_as_i32(4294967294) == -2); assert!(u32_as_i32(4294967295) == -1); } }