Merge pull request #230 from sigp/int_to_bytes
Implement int_to_bytes[n] functions
This commit is contained in:
commit
cb5cd61f2f
@ -9,6 +9,7 @@ members = [
|
|||||||
"eth2/utils/boolean-bitfield",
|
"eth2/utils/boolean-bitfield",
|
||||||
"eth2/utils/hashing",
|
"eth2/utils/hashing",
|
||||||
"eth2/utils/honey-badger-split",
|
"eth2/utils/honey-badger-split",
|
||||||
|
"eth2/utils/int_to_bytes",
|
||||||
"eth2/utils/slot_clock",
|
"eth2/utils/slot_clock",
|
||||||
"eth2/utils/ssz",
|
"eth2/utils/ssz",
|
||||||
"eth2/utils/swap_or_not_shuffle",
|
"eth2/utils/swap_or_not_shuffle",
|
||||||
|
@ -5,6 +5,7 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
slot_clock = { path = "../../eth2/utils/slot_clock" }
|
int_to_bytes = { path = "../utils/int_to_bytes" }
|
||||||
ssz = { path = "../../eth2/utils/ssz" }
|
slot_clock = { path = "../utils/slot_clock" }
|
||||||
types = { path = "../../eth2/types" }
|
ssz = { path = "../utils/ssz" }
|
||||||
|
types = { path = "../types" }
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
pub mod test_utils;
|
pub mod test_utils;
|
||||||
mod traits;
|
mod traits;
|
||||||
|
|
||||||
|
use int_to_bytes::int_to_bytes32;
|
||||||
use slot_clock::SlotClock;
|
use slot_clock::SlotClock;
|
||||||
use ssz::ssz_encode;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{BeaconBlock, ChainSpec, Slot};
|
use types::{BeaconBlock, ChainSpec, Slot};
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
|
|||||||
fn produce_block(&mut self, slot: Slot) -> Result<PollOutcome, Error> {
|
fn produce_block(&mut self, slot: Slot) -> Result<PollOutcome, Error> {
|
||||||
let randao_reveal = {
|
let randao_reveal = {
|
||||||
// TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`.
|
// TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`.
|
||||||
let message = ssz_encode(&slot.epoch(self.spec.epoch_length));
|
let message = int_to_bytes32(slot.epoch(self.spec.epoch_length).as_u64());
|
||||||
|
|
||||||
match self.signer.sign_randao_reveal(&message) {
|
match self.signer.sign_randao_reveal(&message) {
|
||||||
None => return Ok(PollOutcome::SignerRejection(slot)),
|
None => return Ok(PollOutcome::SignerRejection(slot)),
|
||||||
|
@ -6,6 +6,7 @@ edition = "2018"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
hashing = { path = "../utils/hashing" }
|
hashing = { path = "../utils/hashing" }
|
||||||
|
int_to_bytes = { path = "../utils/int_to_bytes" }
|
||||||
integer-sqrt = "0.1"
|
integer-sqrt = "0.1"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
ssz = { path = "../utils/ssz" }
|
ssz = { path = "../utils/ssz" }
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::SlotProcessingError;
|
use crate::SlotProcessingError;
|
||||||
use hashing::hash;
|
use hashing::hash;
|
||||||
|
use int_to_bytes::int_to_bytes32;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use ssz::{ssz_encode, TreeHash};
|
use ssz::{ssz_encode, TreeHash};
|
||||||
use types::{
|
use types::{
|
||||||
@ -110,7 +111,7 @@ fn per_block_processing_signature_optional(
|
|||||||
ensure!(
|
ensure!(
|
||||||
bls_verify(
|
bls_verify(
|
||||||
&block_proposer.pubkey,
|
&block_proposer.pubkey,
|
||||||
&ssz_encode(&state.current_epoch(spec)),
|
&int_to_bytes32(state.current_epoch(spec).as_u64()),
|
||||||
&block.randao_reveal,
|
&block.randao_reveal,
|
||||||
get_domain(&state.fork, state.current_epoch(spec), DOMAIN_RANDAO)
|
get_domain(&state.fork, state.current_epoch(spec), DOMAIN_RANDAO)
|
||||||
),
|
),
|
||||||
|
12
eth2/utils/int_to_bytes/Cargo.toml
Normal file
12
eth2/utils/int_to_bytes/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "int_to_bytes"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Paul Hauner <paul@paulhauner.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
bytes = "0.4"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
yaml-rust = "0.4.2"
|
||||||
|
hex = "0.3"
|
125
eth2/utils/int_to_bytes/src/lib.rs
Normal file
125
eth2/utils/int_to_bytes/src/lib.rs
Normal file
@ -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<u8> {
|
||||||
|
vec![int]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `int` as little-endian bytes with a length of 2.
|
||||||
|
pub fn int_to_bytes2(int: u16) -> Vec<u8> {
|
||||||
|
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<Vec<u8>> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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<u8> {
|
||||||
|
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."),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
215
eth2/utils/int_to_bytes/src/specs/test_vector_int_to_bytes.yml
Normal file
215
eth2/utils/int_to_bytes/src/specs/test_vector_int_to_bytes.yml
Normal file
@ -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}
|
@ -7,7 +7,9 @@ edition = "2018"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bytes = "0.4"
|
bytes = "0.4"
|
||||||
hashing = { path = "../hashing" }
|
hashing = { path = "../hashing" }
|
||||||
|
int_to_bytes = { path = "../int_to_bytes" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
yaml-rust = "0.4.2"
|
yaml-rust = "0.4.2"
|
||||||
hex = "0.3"
|
hex = "0.3"
|
||||||
|
ethereum-types = "0.5"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use bytes::{Buf, BufMut, BytesMut};
|
use bytes::Buf;
|
||||||
use hashing::hash;
|
use hashing::hash;
|
||||||
|
use int_to_bytes::{int_to_bytes1, int_to_bytes4};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
@ -12,14 +13,19 @@ use std::io::Cursor;
|
|||||||
/// Returns `None` under any of the following conditions:
|
/// Returns `None` under any of the following conditions:
|
||||||
/// - `list_size == 0`
|
/// - `list_size == 0`
|
||||||
/// - `index >= list_size`
|
/// - `index >= list_size`
|
||||||
/// - `list_size >= usize::max_value() / 2`
|
/// - `list_size > 2**24`
|
||||||
|
/// - `list_size > usize::max_value() / 2`
|
||||||
pub fn get_permutated_index(
|
pub fn get_permutated_index(
|
||||||
index: usize,
|
index: usize,
|
||||||
list_size: usize,
|
list_size: usize,
|
||||||
seed: &[u8],
|
seed: &[u8],
|
||||||
shuffle_round_count: usize,
|
shuffle_round_count: u8,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
if list_size == 0 || index >= list_size || list_size >= usize::max_value() / 2 {
|
if list_size == 0
|
||||||
|
|| index >= list_size
|
||||||
|
|| list_size > usize::max_value() / 2
|
||||||
|
|| list_size > 2_usize.pow(24)
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +34,7 @@ pub fn get_permutated_index(
|
|||||||
let pivot = bytes_to_int64(&hash_with_round(seed, round)[..]) as usize % list_size;
|
let pivot = bytes_to_int64(&hash_with_round(seed, round)[..]) as usize % list_size;
|
||||||
let flip = (pivot + list_size - index) % list_size;
|
let flip = (pivot + list_size - index) % list_size;
|
||||||
let position = max(index, flip);
|
let position = max(index, flip);
|
||||||
let source = hash_with_round_and_position(seed, round, position);
|
let source = hash_with_round_and_position(seed, round, position)?;
|
||||||
let byte = source[(position % 256) / 8];
|
let byte = source[(position % 256) / 8];
|
||||||
let bit = (byte >> (position % 8)) % 2;
|
let bit = (byte >> (position % 8)) % 2;
|
||||||
index = if bit == 1 { flip } else { index }
|
index = if bit == 1 { flip } else { index }
|
||||||
@ -36,31 +42,23 @@ pub fn get_permutated_index(
|
|||||||
Some(index)
|
Some(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_with_round_and_position(seed: &[u8], round: usize, position: usize) -> Vec<u8> {
|
fn hash_with_round_and_position(seed: &[u8], round: u8, position: usize) -> Option<Vec<u8>> {
|
||||||
let mut seed = seed.to_vec();
|
let mut seed = seed.to_vec();
|
||||||
seed.append(&mut int_to_bytes1(round as u64));
|
seed.append(&mut int_to_bytes1(round));
|
||||||
seed.append(&mut int_to_bytes4(position as u64 / 256));
|
/*
|
||||||
hash(&seed[..])
|
* Note: the specification has an implicit assertion in `int_to_bytes4` that `position / 256 <
|
||||||
|
* 2**24`. For efficiency, we do not check for that here as it is checked in `get_permutated_index`.
|
||||||
|
*/
|
||||||
|
seed.append(&mut int_to_bytes4((position / 256) as u32));
|
||||||
|
Some(hash(&seed[..]))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hash_with_round(seed: &[u8], round: usize) -> Vec<u8> {
|
fn hash_with_round(seed: &[u8], round: u8) -> Vec<u8> {
|
||||||
let mut seed = seed.to_vec();
|
let mut seed = seed.to_vec();
|
||||||
seed.append(&mut int_to_bytes1(round as u64));
|
seed.append(&mut int_to_bytes1(round));
|
||||||
hash(&seed[..])
|
hash(&seed[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn int_to_bytes1(int: u64) -> Vec<u8> {
|
|
||||||
let mut bytes = BytesMut::with_capacity(8);
|
|
||||||
bytes.put_u64_le(int);
|
|
||||||
vec![bytes[0]]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn int_to_bytes4(int: u64) -> Vec<u8> {
|
|
||||||
let mut bytes = BytesMut::with_capacity(8);
|
|
||||||
bytes.put_u64_le(int);
|
|
||||||
bytes[0..4].to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bytes_to_int64(bytes: &[u8]) -> u64 {
|
fn bytes_to_int64(bytes: &[u8]) -> u64 {
|
||||||
let mut cursor = Cursor::new(bytes);
|
let mut cursor = Cursor::new(bytes);
|
||||||
cursor.get_u64_le()
|
cursor.get_u64_le()
|
||||||
@ -69,10 +67,48 @@ fn bytes_to_int64(bytes: &[u8]) -> u64 {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use ethereum_types::H256 as Hash256;
|
||||||
use hex;
|
use hex;
|
||||||
use std::{fs::File, io::prelude::*, path::PathBuf};
|
use std::{fs::File, io::prelude::*, path::PathBuf};
|
||||||
use yaml_rust::yaml;
|
use yaml_rust::yaml;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[ignore]
|
||||||
|
fn fuzz_test() {
|
||||||
|
let max_list_size = 2_usize.pow(24);
|
||||||
|
let test_runs = 1000;
|
||||||
|
|
||||||
|
// Test at max list_size with the end index.
|
||||||
|
for _ in 0..test_runs {
|
||||||
|
let index = max_list_size - 1;
|
||||||
|
let list_size = max_list_size;
|
||||||
|
let seed = Hash256::random();
|
||||||
|
let shuffle_rounds = 90;
|
||||||
|
|
||||||
|
assert!(get_permutated_index(index, list_size, &seed[..], shuffle_rounds).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test at max list_size low indices.
|
||||||
|
for i in 0..test_runs {
|
||||||
|
let index = i;
|
||||||
|
let list_size = max_list_size;
|
||||||
|
let seed = Hash256::random();
|
||||||
|
let shuffle_rounds = 90;
|
||||||
|
|
||||||
|
assert!(get_permutated_index(index, list_size, &seed[..], shuffle_rounds).is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test at max list_size high indices.
|
||||||
|
for i in 0..test_runs {
|
||||||
|
let index = max_list_size - 1 - i;
|
||||||
|
let list_size = max_list_size;
|
||||||
|
let seed = Hash256::random();
|
||||||
|
let shuffle_rounds = 90;
|
||||||
|
|
||||||
|
assert!(get_permutated_index(index, list_size, &seed[..], shuffle_rounds).is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn returns_none_for_zero_length_list() {
|
fn returns_none_for_zero_length_list() {
|
||||||
assert_eq!(None, get_permutated_index(100, 0, &[42, 42], 90));
|
assert_eq!(None, get_permutated_index(100, 0, &[42, 42], 90));
|
||||||
@ -117,10 +153,16 @@ mod tests {
|
|||||||
let index = test_case["index"].as_i64().unwrap() as usize;
|
let index = test_case["index"].as_i64().unwrap() as usize;
|
||||||
let list_size = test_case["list_size"].as_i64().unwrap() as usize;
|
let list_size = test_case["list_size"].as_i64().unwrap() as usize;
|
||||||
let permutated_index = test_case["permutated_index"].as_i64().unwrap() as usize;
|
let permutated_index = test_case["permutated_index"].as_i64().unwrap() as usize;
|
||||||
let shuffle_round_count = test_case["shuffle_round_count"].as_i64().unwrap() as usize;
|
let shuffle_round_count = test_case["shuffle_round_count"].as_i64().unwrap();
|
||||||
let seed_string = test_case["seed"].clone().into_string().unwrap();
|
let seed_string = test_case["seed"].clone().into_string().unwrap();
|
||||||
let seed = hex::decode(seed_string.replace("0x", "")).unwrap();
|
let seed = hex::decode(seed_string.replace("0x", "")).unwrap();
|
||||||
|
|
||||||
|
let shuffle_round_count = if shuffle_round_count < (u8::max_value() as i64) {
|
||||||
|
shuffle_round_count as u8
|
||||||
|
} else {
|
||||||
|
panic!("shuffle_round_count must be a u8")
|
||||||
|
};
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Some(permutated_index),
|
Some(permutated_index),
|
||||||
get_permutated_index(index, list_size, &seed[..], shuffle_round_count),
|
get_permutated_index(index, list_size, &seed[..], shuffle_round_count),
|
||||||
|
Loading…
Reference in New Issue
Block a user