Add blake2_f precompile (#11017)
* feat: implement eip1108 * doc nit: price per point pair Co-Authored-By: David <dvdplm@gmail.com> * fix: test-build * fix: update chain specs * fix: basic_authority.json chain spec * fix: change `eip_transition == 0x7fffffffffffff` * Merge na-eip1108 * Pre-compile plumbing * Use type alias instead of struct * Extract the data from incoming EVM call and forward it to blake2_f * Fetch parity-common from git for now * Fix broken cost impl Add remaining test vectors * cleanup * Trailing comma in json spec * Update ethcore/builtin/src/lib.rs Co-Authored-By: Andronik Ordian <write@reusable.software> * Update ethcore/builtin/src/lib.rs Co-Authored-By: Andronik Ordian <write@reusable.software> * Rename pricer to be Blake2-specific Return a cost of u32::MAX if conversion fails Fix docs and todos * Fix error handling in cost() * fix chainspec * EIP-152 crate * Update ethcore/builtin/src/lib.rs Co-Authored-By: Seun LanLege <seunlanlege@gmail.com> * Address grumbles * Update ethcore/builtin/src/lib.rs Co-Authored-By: Niklas Adolfsson <niklasadolfsson1@gmail.com> * Switch tests to use hex! * remove parity-crypto from git * Sort out the SIGMA * Prefer arrays to vecs * Update util/EIP-152/src/lib.rs Co-Authored-By: Niklas Adolfsson <niklasadolfsson1@gmail.com> * Update json/src/spec/builtin.rs Co-Authored-By: Andronik Ordian <write@reusable.software> * Update json/src/spec/builtin.rs Co-Authored-By: Andronik Ordian <write@reusable.software> * Review feedback * Do not change chainspecs yet * Do not assume endianess: precompile output is LE
This commit is contained in:
parent
80f0e4b58f
commit
d8d7abc848
17
Cargo.lock
generated
17
Cargo.lock
generated
@ -789,6 +789,13 @@ name = "edit-distance"
|
|||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eip-152"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eip-712"
|
name = "eip-712"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -1110,15 +1117,17 @@ name = "ethcore-builtin"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
|
"bn 0.4.4 (git+https://github.com/paritytech/bn)",
|
||||||
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"eip-152 0.1.0",
|
||||||
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethjson 0.1.0",
|
"ethjson 0.1.0",
|
||||||
"ethkey 0.3.0",
|
"ethkey 0.3.0",
|
||||||
|
"hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-crypto 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parity-crypto 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1592,7 +1601,7 @@ dependencies = [
|
|||||||
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1911,7 +1920,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex-literal"
|
name = "hex-literal"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hex-literal-impl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hex-literal-impl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -5276,7 +5285,7 @@ dependencies = [
|
|||||||
"checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a"
|
"checksum hashmap_core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8e04cb7a5051270ef3fa79f8c7604d581ecfa73d520e74f554e45541c4b5881a"
|
||||||
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
|
"checksum heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1679e6ea370dee694f91f1dc469bf94cf8f52051d147aec3e1f9497c6fc22461"
|
||||||
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
|
"checksum heck 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea04fa3ead4e05e51a7c806fc07271fdbde4e246a6c6d1efd52e72230b771b82"
|
||||||
"checksum hex-literal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c3da68162fdd2147e66682e78e729bd77f93b4c99656db058c5782d8c6b6225a"
|
"checksum hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0"
|
||||||
"checksum hex-literal-impl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06095d08c7c05760f11a071b3e1d4c5b723761c01bd8d7201c30a9536668a612"
|
"checksum hex-literal-impl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06095d08c7c05760f11a071b3e1d4c5b723761c01bd8d7201c30a9536668a612"
|
||||||
"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771"
|
"checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771"
|
||||||
"checksum home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff"
|
"checksum home 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "80dff82fb58cfbbc617fb9a9184b010be0529201553cda50ad04372bc2333aff"
|
||||||
|
@ -14,7 +14,9 @@ keccak-hash = "0.2.0"
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
num = { version = "0.1", default-features = false, features = ["bigint"] }
|
num = { version = "0.1", default-features = false, features = ["bigint"] }
|
||||||
parity-bytes = "0.1"
|
parity-bytes = "0.1"
|
||||||
|
eip-152 = { path = "../../util/EIP-152" }
|
||||||
parity-crypto = "0.4.0"
|
parity-crypto = "0.4.0"
|
||||||
|
byteorder = "1.3.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
rustc-hex = "1.0"
|
hex-literal = "0.2.1"
|
||||||
|
@ -18,10 +18,12 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{max, min},
|
cmp::{max, min},
|
||||||
io::{self, Read},
|
io::{self, Read, Cursor},
|
||||||
|
mem::size_of,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bn;
|
use bn;
|
||||||
|
use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
|
||||||
use ethereum_types::{H256, U256};
|
use ethereum_types::{H256, U256};
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use ethkey::{Signature, recover as ec_recover};
|
use ethkey::{Signature, recover as ec_recover};
|
||||||
@ -30,6 +32,7 @@ use log::{warn, trace};
|
|||||||
use num::{BigUint, Zero, One};
|
use num::{BigUint, Zero, One};
|
||||||
use parity_bytes::BytesRef;
|
use parity_bytes::BytesRef;
|
||||||
use parity_crypto::digest;
|
use parity_crypto::digest;
|
||||||
|
use eip_152::compress;
|
||||||
|
|
||||||
/// Native implementation of a built-in contract.
|
/// Native implementation of a built-in contract.
|
||||||
trait Implementation: Send + Sync {
|
trait Implementation: Send + Sync {
|
||||||
@ -44,6 +47,22 @@ trait Pricer: Send + Sync {
|
|||||||
fn cost(&self, input: &[u8], at: u64) -> U256;
|
fn cost(&self, input: &[u8], at: u64) -> U256;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pricing for the Blake2 compression function (aka "F").
|
||||||
|
/// Computes the price as a fixed cost per round where the number of rounds is part of the input
|
||||||
|
/// byte slice.
|
||||||
|
pub type Blake2FPricer = u64;
|
||||||
|
|
||||||
|
impl Pricer for Blake2FPricer {
|
||||||
|
fn cost(&self, input: &[u8], _at: u64) -> U256 {
|
||||||
|
use std::convert::TryInto;
|
||||||
|
let (rounds_bytes, _) = input.split_at(std::mem::size_of::<u32>());
|
||||||
|
// Returning zero if the conversion fails is fine because `execute()` will check the length
|
||||||
|
// and bail with the appropriate error.
|
||||||
|
let rounds = u32::from_be_bytes(rounds_bytes.try_into().unwrap_or([0u8; 4]));
|
||||||
|
U256::from(*self as u128 * rounds as u128)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A linear pricing model. This computes a price using a base cost and a cost per-word.
|
/// A linear pricing model. This computes a price using a base cost and a cost per-word.
|
||||||
struct Linear {
|
struct Linear {
|
||||||
base: usize,
|
base: usize,
|
||||||
@ -199,6 +218,9 @@ impl Builtin {
|
|||||||
impl From<ethjson::spec::Builtin> for Builtin {
|
impl From<ethjson::spec::Builtin> for Builtin {
|
||||||
fn from(b: ethjson::spec::Builtin) -> Self {
|
fn from(b: ethjson::spec::Builtin) -> Self {
|
||||||
let pricer: Box<dyn Pricer> = match b.pricing {
|
let pricer: Box<dyn Pricer> = match b.pricing {
|
||||||
|
ethjson::spec::Pricing::Blake2F(cost_per_round) => {
|
||||||
|
Box::new(cost_per_round)
|
||||||
|
},
|
||||||
ethjson::spec::Pricing::Linear(linear) => {
|
ethjson::spec::Pricing::Linear(linear) => {
|
||||||
Box::new(Linear {
|
Box::new(Linear {
|
||||||
base: linear.base,
|
base: linear.base,
|
||||||
@ -208,7 +230,7 @@ impl From<ethjson::spec::Builtin> for Builtin {
|
|||||||
ethjson::spec::Pricing::Modexp(exp) => {
|
ethjson::spec::Pricing::Modexp(exp) => {
|
||||||
Box::new(ModexpPricer {
|
Box::new(ModexpPricer {
|
||||||
divisor: if exp.divisor == 0 {
|
divisor: if exp.divisor == 0 {
|
||||||
warn!("Zero modexp divisor specified. Falling back to default.");
|
warn!(target: "builtin", "Zero modexp divisor specified. Falling back to default.");
|
||||||
10
|
10
|
||||||
} else {
|
} else {
|
||||||
exp.divisor
|
exp.divisor
|
||||||
@ -256,6 +278,7 @@ fn ethereum_builtin(name: &str) -> Box<dyn Implementation> {
|
|||||||
"alt_bn128_add" => Box::new(Bn128Add) as Box<dyn Implementation>,
|
"alt_bn128_add" => Box::new(Bn128Add) as Box<dyn Implementation>,
|
||||||
"alt_bn128_mul" => Box::new(Bn128Mul) as Box<dyn Implementation>,
|
"alt_bn128_mul" => Box::new(Bn128Mul) as Box<dyn Implementation>,
|
||||||
"alt_bn128_pairing" => Box::new(Bn128Pairing) as Box<dyn Implementation>,
|
"alt_bn128_pairing" => Box::new(Bn128Pairing) as Box<dyn Implementation>,
|
||||||
|
"blake2_f" => Box::new(Blake2F) as Box<dyn Implementation>,
|
||||||
_ => panic!("invalid builtin name: {}", name),
|
_ => panic!("invalid builtin name: {}", name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,6 +290,10 @@ fn ethereum_builtin(name: &str) -> Box<dyn Implementation> {
|
|||||||
// - sha256
|
// - sha256
|
||||||
// - ripemd160
|
// - ripemd160
|
||||||
// - modexp (EIP198)
|
// - modexp (EIP198)
|
||||||
|
// - alt_bn128_add
|
||||||
|
// - alt_bn128_mul
|
||||||
|
// - alt_bn128_pairing
|
||||||
|
// - blake2_f (The Blake2 compression function F, EIP-152)
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Identity;
|
struct Identity;
|
||||||
@ -292,6 +319,9 @@ struct Bn128Mul;
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Bn128Pairing;
|
struct Bn128Pairing;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct Blake2F;
|
||||||
|
|
||||||
impl Implementation for Identity {
|
impl Implementation for Identity {
|
||||||
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> {
|
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> {
|
||||||
output.write(0, input);
|
output.write(0, input);
|
||||||
@ -337,6 +367,60 @@ impl Implementation for Sha256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Implementation for Blake2F {
|
||||||
|
/// Format of `input`:
|
||||||
|
/// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 byte for f]
|
||||||
|
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> {
|
||||||
|
const BLAKE2_F_ARG_LEN: usize = 213;
|
||||||
|
const PROOF: &str = "Checked the length of the input above; qed";
|
||||||
|
|
||||||
|
if input.len() != BLAKE2_F_ARG_LEN {
|
||||||
|
trace!(target: "builtin", "input length for Blake2 F precompile should be exactly 213 bytes, was {}", input.len());
|
||||||
|
return Err("input length for Blake2 F precompile should be exactly 213 bytes")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut cursor = Cursor::new(input);
|
||||||
|
let rounds = cursor.read_u32::<BigEndian>().expect(PROOF);
|
||||||
|
|
||||||
|
// state vector, h
|
||||||
|
let mut h = [0u64; 8];
|
||||||
|
for state_word in h.iter_mut() {
|
||||||
|
*state_word = cursor.read_u64::<LittleEndian>().expect(PROOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// message block vector, m
|
||||||
|
let mut m = [0u64; 16];
|
||||||
|
for msg_word in m.iter_mut() {
|
||||||
|
*msg_word = cursor.read_u64::<LittleEndian>().expect(PROOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2w-bit offset counter, t
|
||||||
|
let t = [
|
||||||
|
cursor.read_u64::<LittleEndian>().expect(PROOF),
|
||||||
|
cursor.read_u64::<LittleEndian>().expect(PROOF),
|
||||||
|
];
|
||||||
|
|
||||||
|
// final block indicator flag, "f"
|
||||||
|
let f = match input.last() {
|
||||||
|
Some(1) => true,
|
||||||
|
Some(0) => false,
|
||||||
|
_ => {
|
||||||
|
trace!(target: "builtin", "incorrect final block indicator flag, was: {:?}", input.last());
|
||||||
|
return Err("incorrect final block indicator flag")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
compress(&mut h, m, t, f, rounds as usize);
|
||||||
|
|
||||||
|
let mut output_buf = [0u8; 8 * size_of::<u64>()];
|
||||||
|
for (i, state_word) in h.iter().enumerate() {
|
||||||
|
output_buf[i*8..(i+1)*8].copy_from_slice(&state_word.to_le_bytes());
|
||||||
|
}
|
||||||
|
output.write(0, &output_buf[..]);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Implementation for Ripemd160 {
|
impl Implementation for Ripemd160 {
|
||||||
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> {
|
fn execute(&self, input: &[u8], output: &mut BytesRef) -> Result<(), &'static str> {
|
||||||
let hash = digest::ripemd160(input);
|
let hash = digest::ripemd160(input);
|
||||||
@ -526,7 +610,7 @@ impl Implementation for Bn128Pairing {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = self.execute_with_error(input, output) {
|
if let Err(err) = self.execute_with_error(input, output) {
|
||||||
trace!("Pairining error: {:?}", err);
|
trace!(target: "builtin", "Pairing error: {:?}", err);
|
||||||
return Err(err)
|
return Err(err)
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -599,9 +683,117 @@ mod tests {
|
|||||||
use ethjson::uint::Uint;
|
use ethjson::uint::Uint;
|
||||||
use num::{BigUint, Zero, One};
|
use num::{BigUint, Zero, One};
|
||||||
use parity_bytes::BytesRef;
|
use parity_bytes::BytesRef;
|
||||||
use rustc_hex::FromHex;
|
use hex_literal::hex;
|
||||||
use super::{Builtin, Linear, ethereum_builtin, Pricer, ModexpPricer, modexp as me};
|
use super::{Builtin, Linear, ethereum_builtin, Pricer, ModexpPricer, modexp as me};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2f_cost() {
|
||||||
|
let f = Builtin {
|
||||||
|
pricer: Box::new(123),
|
||||||
|
native: ethereum_builtin("blake2_f"),
|
||||||
|
activate_at: 0,
|
||||||
|
};
|
||||||
|
// 5 rounds
|
||||||
|
let input = hex!("0000000548c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let mut output = [0u8; 64];
|
||||||
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(f.cost(&input[..], 0), U256::from(123*5));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_is_err_on_invalid_length() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 1 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-1
|
||||||
|
let input = hex!("00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
|
||||||
|
let result = blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..]));
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.unwrap_err(), "input length for Blake2 F precompile should be exactly 213 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_is_err_on_invalid_length_2() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 2 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-2
|
||||||
|
let input = hex!("000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
|
||||||
|
let result = blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..]));
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.unwrap_err(), "input length for Blake2 F precompile should be exactly 213 bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_is_err_on_bad_finalization_flag() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 3 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-3
|
||||||
|
let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
|
||||||
|
let result = blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..]));
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.unwrap_err(), "incorrect final block indicator flag");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_zero_rounds_is_ok_test_vector_4() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 4 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-4
|
||||||
|
let input = hex!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let expected = hex!("08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b");
|
||||||
|
let mut output = [0u8; 64];
|
||||||
|
blake2.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).unwrap();
|
||||||
|
assert_eq!(&output[..], &expected[..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_test_vector_5() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 5 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-5
|
||||||
|
let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let expected = hex!("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..])).unwrap();
|
||||||
|
assert_eq!(&out[..], &expected[..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_test_vector_6() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 6 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-6
|
||||||
|
let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000");
|
||||||
|
let expected = hex!("75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..])).unwrap();
|
||||||
|
assert_eq!(&out[..], &expected[..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_test_vector_7() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 7 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-7
|
||||||
|
let input = hex!("0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let expected = hex!("b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..])).unwrap();
|
||||||
|
assert_eq!(&out[..], &expected[..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[ignore]
|
||||||
|
#[test]
|
||||||
|
fn blake2_f_test_vector_8() {
|
||||||
|
let blake2 = ethereum_builtin("blake2_f");
|
||||||
|
// Test vector 8 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-8
|
||||||
|
// Note this test is slow, 4294967295/0xffffffff rounds take a while.
|
||||||
|
let input = hex!("ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001");
|
||||||
|
let expected = hex!("fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615");
|
||||||
|
let mut out = [0u8; 64];
|
||||||
|
blake2.execute(&input[..], &mut BytesRef::Fixed(&mut out[..])).unwrap();
|
||||||
|
assert_eq!(&out[..], &expected[..]);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn modexp_func() {
|
fn modexp_func() {
|
||||||
// n^0 % m == 1
|
// n^0 % m == 1
|
||||||
@ -663,19 +855,19 @@ mod tests {
|
|||||||
|
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]);
|
assert_eq!(&o[..], hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"));
|
||||||
|
|
||||||
let mut o8 = [255u8; 8];
|
let mut o8 = [255u8; 8];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o8[..], &(FromHex::from_hex("e3b0c44298fc1c14").unwrap())[..]);
|
assert_eq!(&o8[..], hex!("e3b0c44298fc1c14"));
|
||||||
|
|
||||||
let mut o34 = [255u8; 34];
|
let mut o34 = [255u8; 34];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o34[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff").unwrap())[..]);
|
assert_eq!(&o34[..], &hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855ffff")[..]);
|
||||||
|
|
||||||
let mut ov = vec![];
|
let mut ov = vec![];
|
||||||
f.execute(&i[..], &mut BytesRef::Flexible(&mut ov)).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Flexible(&mut ov)).expect("Builtin should not fail");
|
||||||
assert_eq!(&ov[..], &(FromHex::from_hex("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855").unwrap())[..]);
|
assert_eq!(&ov[..], &hex!("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -686,59 +878,59 @@ mod tests {
|
|||||||
|
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31")[..]);
|
||||||
|
|
||||||
let mut o8 = [255u8; 8];
|
let mut o8 = [255u8; 8];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
|
assert_eq!(&o8[..], &hex!("0000000000000000")[..]);
|
||||||
|
|
||||||
let mut o34 = [255u8; 34];
|
let mut o34 = [255u8; 34];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o34[..], &(FromHex::from_hex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff").unwrap())[..]);
|
assert_eq!(&o34[..], &hex!("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31ffff")[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn ecrecover() {
|
fn ecrecover() {
|
||||||
let f = ethereum_builtin("ecrecover");
|
let f = ethereum_builtin("ecrecover");
|
||||||
|
|
||||||
let i = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
|
let i = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03");
|
||||||
|
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("000000000000000000000000c08b5542d177ac6686946920409741463a15dddb")[..]);
|
||||||
|
|
||||||
let mut o8 = [255u8; 8];
|
let mut o8 = [255u8; 8];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o8[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o8[..], &(FromHex::from_hex("0000000000000000").unwrap())[..]);
|
assert_eq!(&o8[..], &hex!("0000000000000000")[..]);
|
||||||
|
|
||||||
let mut o34 = [255u8; 34];
|
let mut o34 = [255u8; 34];
|
||||||
f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail");
|
f.execute(&i[..], &mut BytesRef::Fixed(&mut o34[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o34[..], &(FromHex::from_hex("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff").unwrap())[..]);
|
assert_eq!(&o34[..], &hex!("000000000000000000000000c08b5542d177ac6686946920409741463a15dddbffff")[..]);
|
||||||
|
|
||||||
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
|
let i_bad = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001a650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03");
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[..]);
|
||||||
|
|
||||||
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let i_bad = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[..]);
|
||||||
|
|
||||||
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b").unwrap();
|
let i_bad = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001b");
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[..]);
|
||||||
|
|
||||||
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b").unwrap();
|
let i_bad = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000000000001b");
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[..]);
|
||||||
|
|
||||||
let i_bad = FromHex::from_hex("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap();
|
let i_bad = hex!("47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001bffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
|
||||||
let mut o = [255u8; 32];
|
let mut o = [255u8; 32];
|
||||||
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
f.execute(&i_bad[..], &mut BytesRef::Fixed(&mut o[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(&o[..], &(FromHex::from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap())[..]);
|
assert_eq!(&o[..], &hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")[..]);
|
||||||
|
|
||||||
// TODO: Should this (corrupted version of the above) fail rather than returning some address?
|
// TODO: Should this (corrupted version of the above) fail rather than returning some address?
|
||||||
/* let i_bad = FromHex::from_hex("48173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
|
/* let i_bad = FromHex::from_hex("48173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad000000000000000000000000000000000000000000000000000000000000001b650acf9d3f5f0a2c799776a1254355d5f4061762a237396a99a0e0e3fc2bcd6729514a0dacb2e623ac4abd157cb18163ff942280db4d5caad66ddf941ba12e03").unwrap();
|
||||||
@ -758,21 +950,21 @@ mod tests {
|
|||||||
|
|
||||||
// test for potential gas cost multiplication overflow
|
// test for potential gas cost multiplication overflow
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b27bafd00000000000000000000000000000000000000000000000000000000503c8ac3").unwrap();
|
let input = hex!("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b27bafd00000000000000000000000000000000000000000000000000000000503c8ac3");
|
||||||
let expected_cost = U256::max_value();
|
let expected_cost = U256::max_value();
|
||||||
assert_eq!(f.cost(&input[..], 0), expected_cost.into());
|
assert_eq!(f.cost(&input[..], 0), expected_cost.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
// test for potential exp len overflow
|
// test for potential exp len overflow
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
00000000000000000000000000000000000000000000000000000000000000ff\
|
00000000000000000000000000000000000000000000000000000000000000ff
|
||||||
2a1e530000000000000000000000000000000000000000000000000000000000\
|
2a1e530000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000"
|
0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 32];
|
let mut output = vec![0u8; 32];
|
||||||
let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = hex!("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
let expected_cost = U256::max_value();
|
let expected_cost = U256::max_value();
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should fail");
|
||||||
@ -782,17 +974,17 @@ mod tests {
|
|||||||
|
|
||||||
// fermat's little theorem example.
|
// fermat's little theorem example.
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000001\
|
0000000000000000000000000000000000000000000000000000000000000001
|
||||||
0000000000000000000000000000000000000000000000000000000000000020\
|
0000000000000000000000000000000000000000000000000000000000000020
|
||||||
0000000000000000000000000000000000000000000000000000000000000020\
|
0000000000000000000000000000000000000000000000000000000000000020
|
||||||
03\
|
03
|
||||||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e\
|
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e
|
||||||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 32];
|
let mut output = vec![0u8; 32];
|
||||||
let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
|
let expected = hex!("0000000000000000000000000000000000000000000000000000000000000001");
|
||||||
let expected_cost = 13056;
|
let expected_cost = 13056;
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
||||||
@ -802,16 +994,16 @@ mod tests {
|
|||||||
|
|
||||||
// second example from EIP: zero base.
|
// second example from EIP: zero base.
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000020\
|
0000000000000000000000000000000000000000000000000000000000000020
|
||||||
0000000000000000000000000000000000000000000000000000000000000020\
|
0000000000000000000000000000000000000000000000000000000000000020
|
||||||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e\
|
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e
|
||||||
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 32];
|
let mut output = vec![0u8; 32];
|
||||||
let expected = FromHex::from_hex("0000000000000000000000000000000000000000000000000000000000000000").unwrap();
|
let expected = hex!("0000000000000000000000000000000000000000000000000000000000000000");
|
||||||
let expected_cost = 13056;
|
let expected_cost = 13056;
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
||||||
@ -821,17 +1013,17 @@ mod tests {
|
|||||||
|
|
||||||
// another example from EIP: zero-padding
|
// another example from EIP: zero-padding
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000001\
|
0000000000000000000000000000000000000000000000000000000000000001
|
||||||
0000000000000000000000000000000000000000000000000000000000000002\
|
0000000000000000000000000000000000000000000000000000000000000002
|
||||||
0000000000000000000000000000000000000000000000000000000000000020\
|
0000000000000000000000000000000000000000000000000000000000000020
|
||||||
03\
|
03
|
||||||
ffff\
|
ffff
|
||||||
80"
|
80"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 32];
|
let mut output = vec![0u8; 32];
|
||||||
let expected = FromHex::from_hex("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab").unwrap();
|
let expected = hex!("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab");
|
||||||
let expected_cost = 768;
|
let expected_cost = 768;
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
||||||
@ -841,13 +1033,13 @@ mod tests {
|
|||||||
|
|
||||||
// zero-length modulus.
|
// zero-length modulus.
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000001\
|
0000000000000000000000000000000000000000000000000000000000000001
|
||||||
0000000000000000000000000000000000000000000000000000000000000002\
|
0000000000000000000000000000000000000000000000000000000000000002
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
03\
|
03
|
||||||
ffff"
|
ffff"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![];
|
let mut output = vec![];
|
||||||
let expected_cost = 0;
|
let expected_cost = 0;
|
||||||
@ -869,21 +1061,21 @@ mod tests {
|
|||||||
|
|
||||||
// zero-points additions
|
// zero-points additions
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000"
|
0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 64];
|
let mut output = vec![0u8; 64];
|
||||||
let expected = FromHex::from_hex("\
|
let expected = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000"
|
0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, &expected[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// no input, should not fail
|
// no input, should not fail
|
||||||
@ -892,23 +1084,23 @@ mod tests {
|
|||||||
let input = BytesRef::Fixed(&mut empty);
|
let input = BytesRef::Fixed(&mut empty);
|
||||||
|
|
||||||
let mut output = vec![0u8; 64];
|
let mut output = vec![0u8; 64];
|
||||||
let expected = FromHex::from_hex("\
|
let expected = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000"
|
0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, &expected[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should fail - point not on curve
|
// should fail - point not on curve
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111"
|
1111111111111111111111111111111111111111111111111111111111111111"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 64];
|
let mut output = vec![0u8; 64];
|
||||||
|
|
||||||
@ -928,29 +1120,29 @@ mod tests {
|
|||||||
|
|
||||||
// zero-point multiplication
|
// zero-point multiplication
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0200000000000000000000000000000000000000000000000000000000000000"
|
0200000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 64];
|
let mut output = vec![0u8; 64];
|
||||||
let expected = FromHex::from_hex("\
|
let expected = hex!("
|
||||||
0000000000000000000000000000000000000000000000000000000000000000\
|
0000000000000000000000000000000000000000000000000000000000000000
|
||||||
0000000000000000000000000000000000000000000000000000000000000000"
|
0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
f.execute(&input[..], &mut BytesRef::Fixed(&mut output[..])).expect("Builtin should not fail");
|
||||||
assert_eq!(output, expected);
|
assert_eq!(output, &expected[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// should fail - point not on curve
|
// should fail - point not on curve
|
||||||
{
|
{
|
||||||
let input = FromHex::from_hex("\
|
let input = hex!("
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
0f00000000000000000000000000000000000000000000000000000000000000"
|
0f00000000000000000000000000000000000000000000000000000000000000"
|
||||||
).unwrap();
|
);
|
||||||
|
|
||||||
let mut output = vec![0u8; 64];
|
let mut output = vec![0u8; 64];
|
||||||
|
|
||||||
@ -991,16 +1183,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bytes(s: &'static str) -> Vec<u8> {
|
|
||||||
FromHex::from_hex(s).expect("static str should contain valid hex bytes")
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bn128_pairing_empty() {
|
fn bn128_pairing_empty() {
|
||||||
// should not fail, because empty input is a valid input of 0 elements
|
// should not fail, because empty input is a valid input of 0 elements
|
||||||
empty_test(
|
empty_test(
|
||||||
builtin_pairing(),
|
builtin_pairing(),
|
||||||
bytes("0000000000000000000000000000000000000000000000000000000000000001"),
|
hex!("0000000000000000000000000000000000000000000000000000000000000001").to_vec(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1009,12 +1197,12 @@ mod tests {
|
|||||||
// should fail - point not on curve
|
// should fail - point not on curve
|
||||||
error_test(
|
error_test(
|
||||||
builtin_pairing(),
|
builtin_pairing(),
|
||||||
&bytes("\
|
&hex!("
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111"
|
1111111111111111111111111111111111111111111111111111111111111111"
|
||||||
),
|
),
|
||||||
Some("not on curve"),
|
Some("not on curve"),
|
||||||
@ -1026,9 +1214,9 @@ mod tests {
|
|||||||
// should fail - input length is invalid
|
// should fail - input length is invalid
|
||||||
error_test(
|
error_test(
|
||||||
builtin_pairing(),
|
builtin_pairing(),
|
||||||
&bytes("\
|
&hex!("
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
1111111111111111111111111111111111111111111111111111111111111111\
|
1111111111111111111111111111111111111111111111111111111111111111
|
||||||
111111111111111111111111111111"
|
111111111111111111111111111111"
|
||||||
),
|
),
|
||||||
Some("Invalid input length"),
|
Some("Invalid input length"),
|
||||||
|
@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
use uint::Uint;
|
use uint::Uint;
|
||||||
|
|
||||||
|
/// Price per round of Blake2 compression.
|
||||||
|
pub type Blake2F = u64;
|
||||||
|
|
||||||
/// Linear pricing.
|
/// Linear pricing.
|
||||||
#[derive(Debug, PartialEq, Deserialize, Clone)]
|
#[derive(Debug, PartialEq, Deserialize, Clone)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@ -65,6 +68,8 @@ pub struct AltBn128Pairing {
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Pricing {
|
pub enum Pricing {
|
||||||
|
/// Pricing for Blake2 compression function: each call costs the same amount per round.
|
||||||
|
Blake2F(Blake2F),
|
||||||
/// Linear pricing.
|
/// Linear pricing.
|
||||||
Linear(Linear),
|
Linear(Linear),
|
||||||
/// Pricing for modular exponentiation.
|
/// Pricing for modular exponentiation.
|
||||||
@ -107,6 +112,19 @@ mod tests {
|
|||||||
assert!(deserialized.activate_at.is_none());
|
assert!(deserialized.activate_at.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialization_blake2_f_builtin() {
|
||||||
|
let s = r#"{
|
||||||
|
"name": "blake2_f",
|
||||||
|
"activate_at": "0xffffff",
|
||||||
|
"pricing": { "blake2_f": 123 }
|
||||||
|
}"#;
|
||||||
|
let deserialized: Builtin = serde_json::from_str(s).unwrap();
|
||||||
|
assert_eq!(deserialized.name, "blake2_f");
|
||||||
|
assert_eq!(deserialized.pricing, Pricing::Blake2F(123));
|
||||||
|
assert!(deserialized.activate_at.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn activate_at() {
|
fn activate_at() {
|
||||||
let s = r#"{
|
let s = r#"{
|
||||||
|
14
util/EIP-152/Cargo.toml
Normal file
14
util/EIP-152/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "eip-152"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
|
repository = "https://github.com/paritytech/parity-ethereum"
|
||||||
|
documentation = "https://docs.rs/eip-152"
|
||||||
|
readme = "README.md"
|
||||||
|
description = "eip-512 blake2 F compression function"
|
||||||
|
keywords = ["eip-152", "eip152", "eip"]
|
||||||
|
license = "GPL-3.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rustc-hex = "2.0.1"
|
192
util/EIP-152/src/lib.rs
Normal file
192
util/EIP-152/src/lib.rs
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
/// The precomputed values for BLAKE2b [from the spec](https://tools.ietf.org/html/rfc7693#section-2.7)
|
||||||
|
/// There are 10 16-byte arrays - one for each round
|
||||||
|
/// the entries are calculated from the sigma constants.
|
||||||
|
const SIGMA: [[usize; 16]; 10] = [
|
||||||
|
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||||
|
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
|
||||||
|
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
|
||||||
|
[ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
|
||||||
|
[ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
|
||||||
|
[ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
|
||||||
|
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
|
||||||
|
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
|
||||||
|
[ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
|
||||||
|
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
/// IV is the initialization vector for BLAKE2b. See https://tools.ietf.org/html/rfc7693#section-2.6
|
||||||
|
/// for details.
|
||||||
|
const IV: [u64; 8] = [
|
||||||
|
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||||
|
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
/// The G mixing function. See https://tools.ietf.org/html/rfc7693#section-3.1
|
||||||
|
fn g(v: &mut [u64], a: usize, b: usize, c: usize, d: usize, x: u64, y: u64) {
|
||||||
|
v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
|
||||||
|
v[d] = (v[d] ^ v[a]).rotate_right(32);
|
||||||
|
v[c] = v[c].wrapping_add(v[d]);
|
||||||
|
v[b] = (v[b] ^ v[c]).rotate_right(24);
|
||||||
|
v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
|
||||||
|
v[d] = (v[d] ^ v[a]).rotate_right(16);
|
||||||
|
v[c] = v[c].wrapping_add(v[d]);
|
||||||
|
v[b] = (v[b] ^ v[c]).rotate_right(63);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The Blake2 compression function F. See https://tools.ietf.org/html/rfc7693#section-3.2
|
||||||
|
/// Takes as an argument the state vector `h`, message block vector `m`, offset counter `t`, final
|
||||||
|
/// block indicator flag `f`, and number of rounds `rounds`. The state vector provided as the first
|
||||||
|
/// parameter is modified by the function.
|
||||||
|
pub fn compress(h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool, rounds: usize) {
|
||||||
|
let mut v = [0u64; 16];
|
||||||
|
v[..h.len()].copy_from_slice(h); // First half from state.
|
||||||
|
v[h.len()..].copy_from_slice(&IV); // Second half from IV.
|
||||||
|
|
||||||
|
v[12] ^= t[0];
|
||||||
|
v[13] ^= t[1];
|
||||||
|
|
||||||
|
if f {
|
||||||
|
v[14] = !v[14] // Invert all bits if the last-block-flag is set.
|
||||||
|
}
|
||||||
|
for i in 0..rounds {
|
||||||
|
// Message word selection permutation for this round.
|
||||||
|
let s = &SIGMA[i % 10];
|
||||||
|
g(&mut v, 0, 4, 8, 12, m[s[0]], m[s[1]]);
|
||||||
|
g(&mut v, 1, 5, 9, 13, m[s[2]], m[s[3]]);
|
||||||
|
g(&mut v, 2, 6, 10, 14, m[s[4]], m[s[5]]);
|
||||||
|
g(&mut v, 3, 7, 11, 15, m[s[6]], m[s[7]]);
|
||||||
|
|
||||||
|
g(&mut v, 0, 5, 10, 15, m[s[8]], m[s[9]]);
|
||||||
|
g(&mut v, 1, 6, 11, 12, m[s[10]], m[s[11]]);
|
||||||
|
g(&mut v, 2, 7, 8, 13, m[s[12]], m[s[13]]);
|
||||||
|
g(&mut v, 3, 4, 9, 14, m[s[14]], m[s[15]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in 0..8 {
|
||||||
|
h[i] ^= v[i] ^ v[i + 8];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::compress;
|
||||||
|
use rustc_hex::FromHex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blake2_f() {
|
||||||
|
// test from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#example-usage-in-solidity
|
||||||
|
let mut h_in = [
|
||||||
|
0x6a09e667f2bdc948_u64, 0xbb67ae8584caa73b_u64,
|
||||||
|
0x3c6ef372fe94f82b_u64, 0xa54ff53a5f1d36f1_u64,
|
||||||
|
0x510e527fade682d1_u64, 0x9b05688c2b3e6c1f_u64,
|
||||||
|
0x1f83d9abfb41bd6b_u64, 0x5be0cd19137e2179_u64,
|
||||||
|
];
|
||||||
|
|
||||||
|
let m = [
|
||||||
|
0x0000000000636261_u64, 0x0000000000000000_u64, 0x0000000000000000_u64,
|
||||||
|
0x0000000000000000_u64, 0x0000000000000000_u64, 0x0000000000000000_u64,
|
||||||
|
0x0000000000000000_u64, 0x0000000000000000_u64, 0x0000000000000000_u64,
|
||||||
|
0x0000000000000000_u64, 0x0000000000000000_u64, 0x0000000000000000_u64,
|
||||||
|
0x0000000000000000_u64, 0x0000000000000000_u64, 0x0000000000000000_u64,
|
||||||
|
0x0000000000000000_u64,
|
||||||
|
];
|
||||||
|
let c = [3, 0];
|
||||||
|
let f = true;
|
||||||
|
let rounds = 12;
|
||||||
|
let h_out: [u64; 8] = [
|
||||||
|
0x0D4D1C983FA580BA_u64, 0xE9F6129FB697276A_u64, 0xB7C45A68142F214C_u64,
|
||||||
|
0xD1A2FFDB6FBB124B_u64, 0x2D79AB2A39C5877D_u64, 0x95CC3345DED552C2_u64,
|
||||||
|
0x5A92F1DBA88AD318_u64, 0x239900D4ED8623B9_u64,
|
||||||
|
];
|
||||||
|
|
||||||
|
compress(&mut h_in, m, c, f, rounds);
|
||||||
|
|
||||||
|
assert_eq!(h_in, h_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_u64_slice(vec: &[u8], slice: &mut [u64]) {
|
||||||
|
vec.chunks(8).enumerate().for_each(|(index, val)| {
|
||||||
|
slice[index] = u64::from_le_bytes([val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7]])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vectors_from_eip() {
|
||||||
|
let vec = vec![
|
||||||
|
(
|
||||||
|
// Test vector 4
|
||||||
|
"0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||||
|
"08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b",
|
||||||
|
),
|
||||||
|
( // test vector 5
|
||||||
|
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||||
|
"ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
// Test vector 6
|
||||||
|
"0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000",
|
||||||
|
"75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
// Test vector 7
|
||||||
|
"0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||||
|
"b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421",
|
||||||
|
),
|
||||||
|
// Test vector 8 – u32::MAX rounds – too slow to run
|
||||||
|
// (
|
||||||
|
// "ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001",
|
||||||
|
// "fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615",
|
||||||
|
// ),
|
||||||
|
];
|
||||||
|
for (hex, output) in vec {
|
||||||
|
let hex = hex;
|
||||||
|
let bytes: Vec<u8> = hex.from_hex().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(bytes.len(), 213);
|
||||||
|
|
||||||
|
let mut h = [0u64; 8];
|
||||||
|
let mut m = [0u64; 16];
|
||||||
|
let mut t = [0u64; 2];
|
||||||
|
|
||||||
|
let rounds = u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]);
|
||||||
|
let f = match bytes[212] {
|
||||||
|
1 => true,
|
||||||
|
0 => false,
|
||||||
|
_ => unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
to_u64_slice(&bytes[4..68], &mut h);
|
||||||
|
to_u64_slice(&bytes[68..196], &mut m);
|
||||||
|
to_u64_slice(&bytes[196..212], &mut t);
|
||||||
|
|
||||||
|
compress(&mut h, m, t, f, rounds as usize);
|
||||||
|
|
||||||
|
let output: Vec<u8> = output.from_hex().unwrap();
|
||||||
|
|
||||||
|
let mut out = [0u64; 8];
|
||||||
|
to_u64_slice(&output[..], &mut out);
|
||||||
|
|
||||||
|
assert_eq!(out, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user