diff --git a/Cargo.toml b/Cargo.toml index f0488b33d5..2dda6578fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "eth2/types", "eth2/utils/bls", "eth2/utils/boolean-bitfield", + "eth2/utils/eth2_bytes", "eth2/utils/hashing", "eth2/utils/honey-badger-split", "eth2/utils/slot_clock", diff --git a/eth2/utils/eth2_bytes/Cargo.toml b/eth2/utils/eth2_bytes/Cargo.toml new file mode 100644 index 0000000000..afee169f24 --- /dev/null +++ b/eth2/utils/eth2_bytes/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "eth2_bytes" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +[dependencies] +bytes = "0.4" + +[dev-dependencies] +yaml-rust = "0.4.2" +hex = "0.3" diff --git a/eth2/utils/eth2_bytes/src/lib.rs b/eth2/utils/eth2_bytes/src/lib.rs new file mode 100644 index 0000000000..537d7b5c84 --- /dev/null +++ b/eth2/utils/eth2_bytes/src/lib.rs @@ -0,0 +1,125 @@ +use bytes::{BufMut, BytesMut}; + +/// Returns `int` as little-endian bytes with a length of 1. +pub fn int_to_bytes1(int: u8) -> Vec { + vec![int] +} + +/// Returns `int` as little-endian bytes with a length of 2. +pub fn int_to_bytes2(int: u16) -> Vec { + let mut bytes = BytesMut::with_capacity(2); + bytes.put_u16_le(int); + bytes.to_vec() +} + +/// Returns `int` as little-endian bytes with a length of 3. +/// +/// An `Option` is returned as Rust does not support a native +/// `u24` type. +/// +/// The Eth 2.0 specification uses `int.to_bytes(2, 'little')`, which throws an error if `int` +/// doesn't fit within 3 bytes. The specification relies upon implicit asserts for some validity +/// conditions, so we ensure the calling function is aware of the error condition as opposed to +/// hiding it with a modulo. +pub fn int_to_bytes3(int: u32) -> Option> { + if int < 2_u32.pow(3 * 8) { + let mut bytes = BytesMut::with_capacity(4); + bytes.put_u32_le(int); + Some(bytes[0..3].to_vec()) + } else { + None + } +} + +/// Returns `int` as little-endian bytes with a length of 4. +pub fn int_to_bytes4(int: u32) -> Vec { + let mut bytes = BytesMut::with_capacity(4); + bytes.put_u32_le(int); + bytes.to_vec() +} + +/// Returns `int` as little-endian bytes with a length of 8. +pub fn int_to_bytes8(int: u64) -> Vec { + let mut bytes = BytesMut::with_capacity(8); + bytes.put_u64_le(int); + bytes.to_vec() +} + +/// Returns `int` as little-endian bytes with a length of 32. +pub fn int_to_bytes32(int: u64) -> Vec { + let mut bytes = BytesMut::with_capacity(32); + bytes.put_u64_le(int); + bytes.resize(32, 0); + bytes.to_vec() +} + +/// Returns `int` as little-endian bytes with a length of 48. +pub fn int_to_bytes48(int: u64) -> Vec { + let mut bytes = BytesMut::with_capacity(48); + bytes.put_u64_le(int); + bytes.resize(48, 0); + bytes.to_vec() +} + +/// Returns `int` as little-endian bytes with a length of 96. +pub fn int_to_bytes96(int: u64) -> Vec { + let mut bytes = BytesMut::with_capacity(96); + bytes.put_u64_le(int); + bytes.resize(96, 0); + bytes.to_vec() +} + +#[cfg(test)] +mod tests { + use super::*; + use hex; + use std::{fs::File, io::prelude::*, path::PathBuf}; + use yaml_rust::yaml; + + #[test] + fn int_to_bytes3_returns_none() { + assert_eq!(int_to_bytes3(2_u32.pow(24)), None); + } + + #[test] + fn test_vectors() { + /* + * Test vectors are generated here: + * + * https://github.com/ethereum/eth2.0-test-generators + */ + let mut file = { + let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + file_path_buf.push("src/specs/test_vector_int_to_bytes.yml"); + + File::open(file_path_buf).unwrap() + }; + + let mut yaml_str = String::new(); + + file.read_to_string(&mut yaml_str).unwrap(); + + let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap(); + let doc = &docs[0]; + let test_cases = doc["test_cases"].as_vec().unwrap(); + + for test_case in test_cases { + let byte_length = test_case["byte_length"].as_i64().unwrap() as u64; + let int = test_case["int"].as_i64().unwrap() as u64; + let bytes_string = test_case["bytes"].clone().into_string().unwrap(); + let bytes = hex::decode(bytes_string.replace("0x", "")).unwrap(); + + match byte_length { + 1 => assert_eq!(int_to_bytes1(int as u8), bytes), + 2 => assert_eq!(int_to_bytes2(int as u16), bytes), + 3 => assert_eq!(int_to_bytes3(int as u32), Some(bytes)), + 4 => assert_eq!(int_to_bytes4(int as u32), bytes), + 8 => assert_eq!(int_to_bytes8(int), bytes), + 32 => assert_eq!(int_to_bytes32(int), bytes), + 48 => assert_eq!(int_to_bytes48(int), bytes), + 96 => assert_eq!(int_to_bytes96(int), bytes), + _ => panic!("Unknown byte length in test vector."), + } + } + } +} diff --git a/eth2/utils/eth2_bytes/src/specs/test_vector_int_to_bytes.yml b/eth2/utils/eth2_bytes/src/specs/test_vector_int_to_bytes.yml new file mode 100644 index 0000000000..3b7eaa9c10 --- /dev/null +++ b/eth2/utils/eth2_bytes/src/specs/test_vector_int_to_bytes.yml @@ -0,0 +1,215 @@ +fork: tchaikovsky +summary: Test vectors for the `int_to_bytes[n]` functions.` +test_suite: int_to_bytes +title: int_to_bytes Tests +version: 1.0 +test_cases: +- {byte_length: 1, bytes: '0x00', int: 0} +- {byte_length: 1, bytes: '0x01', int: 1} +- {byte_length: 1, bytes: '0xff', int: 255} +- {byte_length: 1, bytes: '0xc0', int: 192} +- {byte_length: 1, bytes: '0xc7', int: 199} +- {byte_length: 1, bytes: '0xf2', int: 242} +- {byte_length: 1, bytes: '0x26', int: 38} +- {byte_length: 1, bytes: '0xfb', int: 251} +- {byte_length: 1, bytes: '0xd5', int: 213} +- {byte_length: 1, bytes: '0x74', int: 116} +- {byte_length: 1, bytes: '0xa8', int: 168} +- {byte_length: 1, bytes: '0xc6', int: 198} +- {byte_length: 1, bytes: '0x3d', int: 61} +- {byte_length: 1, bytes: '0xc2', int: 194} +- {byte_length: 1, bytes: '0x68', int: 104} +- {byte_length: 1, bytes: '0x64', int: 100} +- {byte_length: 1, bytes: '0xc2', int: 194} +- {byte_length: 1, bytes: '0x78', int: 120} +- {byte_length: 1, bytes: '0x33', int: 51} +- {byte_length: 2, bytes: '0x0000', int: 0} +- {byte_length: 2, bytes: '0x0100', int: 1} +- {byte_length: 2, bytes: '0xffff', int: 65535} +- {byte_length: 2, bytes: '0xedea', int: 60141} +- {byte_length: 2, bytes: '0x2d93', int: 37677} +- {byte_length: 2, bytes: '0x611e', int: 7777} +- {byte_length: 2, bytes: '0x637c', int: 31843} +- {byte_length: 2, bytes: '0xe370', int: 28899} +- {byte_length: 2, bytes: '0x96b3', int: 45974} +- {byte_length: 2, bytes: '0xde44', int: 17630} +- {byte_length: 2, bytes: '0xa009', int: 2464} +- {byte_length: 2, bytes: '0xf6ba', int: 47862} +- {byte_length: 2, bytes: '0xef76', int: 30447} +- {byte_length: 2, bytes: '0x7e5f', int: 24446} +- {byte_length: 2, bytes: '0x393d', int: 15673} +- {byte_length: 2, bytes: '0xc820', int: 8392} +- {byte_length: 2, bytes: '0x9031', int: 12688} +- {byte_length: 2, bytes: '0x3963', int: 25401} +- {byte_length: 2, bytes: '0x033d', int: 15619} +- {byte_length: 3, bytes: '0x000000', int: 0} +- {byte_length: 3, bytes: '0x010000', int: 1} +- {byte_length: 3, bytes: '0xffffff', int: 16777215} +- {byte_length: 3, bytes: '0x1fdfb2', int: 11722527} +- {byte_length: 3, bytes: '0x2a7504', int: 292138} +- {byte_length: 3, bytes: '0x09fb20', int: 2161417} +- {byte_length: 3, bytes: '0xa4a6b2', int: 11708068} +- {byte_length: 3, bytes: '0x17feb7', int: 12058135} +- {byte_length: 3, bytes: '0x3ad0b1', int: 11653178} +- {byte_length: 3, bytes: '0xbc92c6', int: 13013692} +- {byte_length: 3, bytes: '0xb6c046', int: 4636854} +- {byte_length: 3, bytes: '0x937f00', int: 32659} +- {byte_length: 3, bytes: '0x8266cb', int: 13330050} +- {byte_length: 3, bytes: '0x8136e9', int: 15283841} +- {byte_length: 3, bytes: '0xe9e062', int: 6480105} +- {byte_length: 3, bytes: '0x50d054', int: 5558352} +- {byte_length: 3, bytes: '0xb95340', int: 4215737} +- {byte_length: 3, bytes: '0x779f52', int: 5414775} +- {byte_length: 3, bytes: '0x15aed0', int: 13676053} +- {byte_length: 4, bytes: '0x00000000', int: 0} +- {byte_length: 4, bytes: '0x01000000', int: 1} +- {byte_length: 4, bytes: '0xffffffff', int: 4294967295} +- {byte_length: 4, bytes: '0x389cd0ca', int: 3402669112} +- {byte_length: 4, bytes: '0xfb29dc70', int: 1893476859} +- {byte_length: 4, bytes: '0xf5f5c999', int: 2580149749} +- {byte_length: 4, bytes: '0xf4f0b8d1', int: 3518558452} +- {byte_length: 4, bytes: '0x830de883', int: 2213023107} +- {byte_length: 4, bytes: '0xe3b4e843', int: 1139324131} +- {byte_length: 4, bytes: '0x4c9ce594', int: 2498075724} +- {byte_length: 4, bytes: '0xa9826dab', int: 2876080809} +- {byte_length: 4, bytes: '0xc40aecb7', int: 3085699780} +- {byte_length: 4, bytes: '0x55490416', int: 369379669} +- {byte_length: 4, bytes: '0x4f2eedc5', int: 3320655439} +- {byte_length: 4, bytes: '0xdd07257e', int: 2116356061} +- {byte_length: 4, bytes: '0x481a57e9', int: 3914799688} +- {byte_length: 4, bytes: '0x4556a493', int: 2477020741} +- {byte_length: 4, bytes: '0xccb781ed', int: 3984701388} +- {byte_length: 4, bytes: '0x6b994065', int: 1698732395} +- {byte_length: 8, bytes: '0x0000000000000000', int: 0} +- {byte_length: 8, bytes: '0x0100000000000000', int: 1} +- {byte_length: 8, bytes: '0xffffffff00000000', int: 4294967295} +- {byte_length: 8, bytes: '0x77d6e31400000000', int: 350475895} +- {byte_length: 8, bytes: '0xf3e681bf00000000', int: 3212961523} +- {byte_length: 8, bytes: '0x62fa7bd800000000', int: 3632003682} +- {byte_length: 8, bytes: '0x82c67b4500000000', int: 1165739650} +- {byte_length: 8, bytes: '0x52577fba00000000', int: 3128907602} +- {byte_length: 8, bytes: '0x5eac939b00000000', int: 2610146398} +- {byte_length: 8, bytes: '0x12ba143700000000', int: 924105234} +- {byte_length: 8, bytes: '0x1d3b893a00000000', int: 982072093} +- {byte_length: 8, bytes: '0x8262153000000000', int: 806707842} +- {byte_length: 8, bytes: '0xbb9cc58e00000000', int: 2395315387} +- {byte_length: 8, bytes: '0x76fef6d100000000', int: 3522625142} +- {byte_length: 8, bytes: '0x0fc3d35700000000', int: 1473495823} +- {byte_length: 8, bytes: '0xc7f851de00000000', int: 3729914055} +- {byte_length: 8, bytes: '0x3a1e5cb200000000', int: 2992381498} +- {byte_length: 8, bytes: '0x3b748e3400000000', int: 881751099} +- {byte_length: 8, bytes: '0xdc92479600000000', int: 2521273052} +- {byte_length: 32, bytes: '0x0000000000000000000000000000000000000000000000000000000000000000', + int: 0} +- {byte_length: 32, bytes: '0x0100000000000000000000000000000000000000000000000000000000000000', + int: 1} +- {byte_length: 32, bytes: '0xffffffff00000000000000000000000000000000000000000000000000000000', + int: 4294967295} +- {byte_length: 32, bytes: '0x2395ad4c00000000000000000000000000000000000000000000000000000000', + int: 1286444323} +- {byte_length: 32, bytes: '0x38a735b800000000000000000000000000000000000000000000000000000000', + int: 3090523960} +- {byte_length: 32, bytes: '0x5a9416e100000000000000000000000000000000000000000000000000000000', + int: 3776353370} +- {byte_length: 32, bytes: '0x220f757500000000000000000000000000000000000000000000000000000000', + int: 1970605858} +- {byte_length: 32, bytes: '0x65bf635200000000000000000000000000000000000000000000000000000000', + int: 1382268773} +- {byte_length: 32, bytes: '0x033f902200000000000000000000000000000000000000000000000000000000', + int: 579878659} +- {byte_length: 32, bytes: '0x2b2d58ab00000000000000000000000000000000000000000000000000000000', + int: 2874682667} +- {byte_length: 32, bytes: '0x15af31da00000000000000000000000000000000000000000000000000000000', + int: 3660689173} +- {byte_length: 32, bytes: '0xd260642e00000000000000000000000000000000000000000000000000000000', + int: 778330322} +- {byte_length: 32, bytes: '0xcdf8429700000000000000000000000000000000000000000000000000000000', + int: 2537748685} +- {byte_length: 32, bytes: '0xc9304b0500000000000000000000000000000000000000000000000000000000', + int: 88813769} +- {byte_length: 32, bytes: '0xf7b7ba0200000000000000000000000000000000000000000000000000000000', + int: 45791223} +- {byte_length: 32, bytes: '0x1ee262d900000000000000000000000000000000000000000000000000000000', + int: 3647136286} +- {byte_length: 32, bytes: '0xb34b03d300000000000000000000000000000000000000000000000000000000', + int: 3540208563} +- {byte_length: 32, bytes: '0x3d52db4d00000000000000000000000000000000000000000000000000000000', + int: 1306219069} +- {byte_length: 32, bytes: '0xd86db47900000000000000000000000000000000000000000000000000000000', + int: 2041867736} +- {byte_length: 48, bytes: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 0} +- {byte_length: 48, bytes: '0x010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1} +- {byte_length: 48, bytes: '0xffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 4294967295} +- {byte_length: 48, bytes: '0x61aeae650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1705946721} +- {byte_length: 48, bytes: '0xd1c08fac0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 2895102161} +- {byte_length: 48, bytes: '0x6f36b6c90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3384161903} +- {byte_length: 48, bytes: '0x102f2f3b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 992947984} +- {byte_length: 48, bytes: '0x0f53f9240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 620319503} +- {byte_length: 48, bytes: '0x5c1d46b30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3007716700} +- {byte_length: 48, bytes: '0x955791510000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1368479637} +- {byte_length: 48, bytes: '0xf934170f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 253179129} +- {byte_length: 48, bytes: '0xc1a8b76f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1874307265} +- {byte_length: 48, bytes: '0xdf3f62c20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3261218783} +- {byte_length: 48, bytes: '0xbd741bc50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3306910909} +- {byte_length: 48, bytes: '0xfe5dc5540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1422220798} +- {byte_length: 48, bytes: '0x364f10df0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3742388022} +- {byte_length: 48, bytes: '0x4a3909450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1158232394} +- {byte_length: 48, bytes: '0xe04760380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 945833952} +- {byte_length: 48, bytes: '0x755c78540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1417174133} +- {byte_length: 96, bytes: '0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 0} +- {byte_length: 96, bytes: '0x010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1} +- {byte_length: 96, bytes: '0xffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 4294967295} +- {byte_length: 96, bytes: '0xa3274ee20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3796772771} +- {byte_length: 96, bytes: '0x1658135c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1544771606} +- {byte_length: 96, bytes: '0x2af24fb30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3008361002} +- {byte_length: 96, bytes: '0x9e6bc40a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 180644766} +- {byte_length: 96, bytes: '0x0745b3c50000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3316860167} +- {byte_length: 96, bytes: '0xe1b59f830000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 2208282081} +- {byte_length: 96, bytes: '0x985a9e6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1855871640} +- {byte_length: 96, bytes: '0x3d4e3a090000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 154816061} +- {byte_length: 96, bytes: '0x6f5dfb630000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1677417839} +- {byte_length: 96, bytes: '0x383cdecd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3453893688} +- {byte_length: 96, bytes: '0x38f55ceb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3948737848} +- {byte_length: 96, bytes: '0xcd746f5d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1567585485} +- {byte_length: 96, bytes: '0x3d971e910000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 2434701117} +- {byte_length: 96, bytes: '0x3adff0c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3237011258} +- {byte_length: 96, bytes: '0x5ed40a710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 1896535134} +- {byte_length: 96, bytes: '0x755d2ed40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + int: 3559808373}