use crate::private_key::ETHEREUM_SALT;
use crate::Error;
use num256::Uint256;
use serde::de::Error as SerdeError;
use serde::{
de::{Deserialize, Deserializer},
ser::Serializer,
};
use sha3::{Digest, Keccak256};
use std::str;
pub fn get_ethereum_msg_hash(data: &[u8]) -> Vec<u8> {
let digest = Keccak256::digest(data);
let salt_string = ETHEREUM_SALT.to_string();
let salt_bytes = salt_string.as_bytes();
let digest = Keccak256::digest([salt_bytes, &digest].concat());
digest.to_vec()
}
pub fn hex_str_to_bytes(s: &str) -> Result<Vec<u8>, Error> {
let s = match s.strip_prefix("0x") {
Some(s) => s,
None => s,
};
let bytes = s
.as_bytes()
.chunks(2)
.map::<Result<u8, Error>, _>(|ch| {
let str = str::from_utf8(ch)?;
let byte = u8::from_str_radix(str, 16)?;
Ok(byte)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(bytes)
}
pub fn debug_print_data(input: &[u8]) -> String {
let mut out = String::new();
let count = input.len() / 32;
out += "data hex dump\n";
for i in 0..count {
out += &format!(
"0x{}\n",
bytes_to_hex_str(&input[(i * 32)..((i * 32) + 32)])
)
}
out += "end hex dump\n";
out
}
pub fn display_uint256_as_address(input: Uint256) -> String {
format!("{input:#066x}")
}
pub fn big_endian_uint256_serialize<S>(x: &Uint256, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
if x == &0u32.into() {
s.serialize_bytes(&[])
} else {
let mut bytes = x.to_be_bytes().to_vec();
while let Some(0) = bytes.first() {
bytes.drain(0..1);
}
s.serialize_bytes(&bytes)
}
}
pub fn big_endian_u64_serialize<S>(x: &u64, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let x = *x;
big_endian_uint256_serialize(&x.into(), s)
}
pub fn big_endian_uint256_deserialize<'de, D>(d: D) -> Result<Uint256, D::Error>
where
D: Deserializer<'de>,
{
Ok(Uint256::from_be_bytes(&Vec::<u8>::deserialize(d)?))
}
pub fn big_endian_u64_deserialize<'de, D>(d: D) -> Result<u64, D::Error>
where
D: Deserializer<'de>,
{
let bytes = &Vec::<u8>::deserialize(d)?;
let value = Uint256::from_be_bytes(bytes);
if value > u64::MAX.into() {
Err(SerdeError::invalid_value(
serde::de::Unexpected::Other("Value greater than u64::Max"),
&"Value less than u64::Max",
))
} else {
let mut slice = [0; 8];
let mut c = 7;
for i in bytes.iter().rev() {
slice[c] = *i;
if c == 0 {
break;
}
c += 1;
}
Ok(u64::from_be_bytes(slice))
}
}
pub fn big_endian_u64_from_bytes(bytes: &[u8]) -> Option<u64> {
let value = Uint256::from_be_bytes(bytes);
if value > u64::MAX.into() {
None
} else {
let mut slice = [0; 8];
let mut c = 7;
for i in bytes.iter().rev() {
slice[c] = *i;
if c == 0 {
break;
}
c -= 1;
}
Some(u64::from_be_bytes(slice))
}
}
#[test]
fn decode_bytes() {
assert_eq!(
hex_str_to_bytes("deadbeef").expect("Unable to decode"),
[222, 173, 190, 239]
);
}
#[test]
fn decode_odd_amount_of_bytes() {
assert_eq!(hex_str_to_bytes("f").unwrap(), vec![15]);
}
#[test]
fn bytes_raises_decode_error() {
let e = hex_str_to_bytes("\u{012345}deadbeef").unwrap_err();
match e {
Error::InvalidUtf8(_) => {}
_ => panic!(),
};
}
#[test]
fn bytes_raises_parse_error() {
let e = hex_str_to_bytes("Lorem ipsum").unwrap_err();
match e {
Error::InvalidHex(_) => {}
_ => panic!(),
}
}
#[test]
fn parse_prefixed_empty() {
assert_eq!(hex_str_to_bytes("0x").unwrap(), Vec::<u8>::new());
}
#[test]
fn parse_prefixed_non_empty() {
assert_eq!(
hex_str_to_bytes("0xdeadbeef").unwrap(),
vec![0xde, 0xad, 0xbe, 0xef]
);
}
pub fn bytes_to_hex_str(bytes: &[u8]) -> String {
bytes
.iter()
.map(|b| format!("{b:0>2x?}"))
.fold(String::new(), |acc, x| acc + &x)
}
#[test]
fn encode_bytes() {
assert_eq!(bytes_to_hex_str(&[0xf]), "0f".to_owned());
assert_eq!(bytes_to_hex_str(&[0xff]), "ff".to_owned());
assert_eq!(
bytes_to_hex_str(&[0xde, 0xad, 0xbe, 0xef]),
"deadbeef".to_owned()
);
}
pub fn zpad(bytes: &[u8], len: usize) -> Vec<u8> {
if bytes.len() >= len {
return bytes.to_vec();
}
let mut pad = vec![0u8; len - bytes.len()];
pad.extend(bytes);
pad
}
#[test]
fn verify_zpad() {
assert_eq!(zpad(&[1, 2, 3, 4], 8), [0, 0, 0, 0, 1, 2, 3, 4]);
}
#[test]
fn verify_zpad_exact() {
assert_eq!(zpad(&[1, 2, 3, 4], 4), [1, 2, 3, 4]);
}
#[test]
fn verify_zpad_less_than_size() {
assert_eq!(zpad(&[1, 2, 3, 4], 2), [1, 2, 3, 4]);
}
#[cfg(test)]
use rand::prelude::ThreadRng;
#[cfg(test)]
pub fn get_fuzz_bytes(rng: &mut ThreadRng) -> Vec<u8> {
use rand::distributions::Distribution;
use rand::distributions::Uniform;
use rand::Rng;
let range = Uniform::from(1..200_000);
let size: usize = range.sample(rng);
let event_bytes: Vec<u8> = (0..size)
.map(|_| {
let val: u8 = rng.gen();
val
})
.collect();
event_bytes
}