From f3fd9838728b8565915e0a5cb68fbbe8fc3874c7 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Tue, 28 Apr 2020 10:22:53 +0800 Subject: [PATCH 1/9] Blake2 compression function. --- blake2/Cargo.toml | 3 +- blake2/src/f.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++ blake2/src/lib.rs | 36 +++++++++------- 3 files changed, 129 insertions(+), 15 deletions(-) create mode 100644 blake2/src/f.rs diff --git a/blake2/Cargo.toml b/blake2/Cargo.toml index 9207d69..bb51c15 100644 --- a/blake2/Cargo.toml +++ b/blake2/Cargo.toml @@ -9,8 +9,9 @@ publish = false edition = "2018" [dependencies] -blake2 = "0.7" +byteorder = "1.3.4" ewasm_api = "0.9" +arr_macro = "0.1.3" [lib] crate-type = ["cdylib"] diff --git a/blake2/src/f.rs b/blake2/src/f.rs new file mode 100644 index 0000000..508fe55 --- /dev/null +++ b/blake2/src/f.rs @@ -0,0 +1,105 @@ + +const SIGMA: [[usize; 16]; 10] = [ + [0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15], + [14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3], + [11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4], + [7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8], + [9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13], + [2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9], + [12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11], + [13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10], + [6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5], + [10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0], +]; + + +/// IV is an initialization vector for BLAKE2b +const IV: [u64; 8] = [ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, +]; + +pub fn compress(rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { + let mut v = Vec::new(); + v.extend(h.iter().cloned()); + v.extend_from_slice(&IV); + + v[12] ^= t[0]; + v[13] ^= t[1]; + + if f { + v[14] = !v[14] + } + + for i in 0..rounds as usize { + let s = &SIGMA[i % 10]; + v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[0]]); + v[12] = (v[12] ^ v[0]).rotate_right(32); + v[8] = v[8].wrapping_add(v[12]); + v[4] = (v[4] ^ v[8]).rotate_right(24); + v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[1]]); + v[12] = (v[12] ^ v[0]).rotate_right(16); + v[8] = v[8].wrapping_add(v[12]); + v[4] = (v[4] ^ v[8]).rotate_right(63); + v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[2]]); + v[13] = (v[13] ^ v[1]).rotate_right(32); + v[9] = v[9].wrapping_add(v[13]); + v[5] = (v[5] ^ v[9]).rotate_right(24); + v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[3]]); + v[13] = (v[13] ^ v[1]).rotate_right(16); + v[9] = v[9].wrapping_add(v[13]); + v[5] = (v[5] ^ v[9]).rotate_right(63); + v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[4]]); + v[14] = (v[14] ^ v[2]).rotate_right(32); + v[10] = v[10].wrapping_add(v[14]); + v[6] = (v[6] ^ v[10]).rotate_right(24); + v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[5]]); + v[14] = (v[14] ^ v[2]).rotate_right(16); + v[10] = v[10].wrapping_add(v[14]); + v[6] = (v[6] ^ v[10]).rotate_right(63); + v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[6]]); + v[15] = (v[15] ^ v[3]).rotate_right(32); + v[11] = v[11].wrapping_add(v[15]); + v[7] = (v[7] ^ v[11]).rotate_right(24); + v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[7]]); + v[15] = (v[15] ^ v[3]).rotate_right(16); + v[11] = v[11].wrapping_add(v[15]); + v[7] = (v[7] ^ v[11]).rotate_right(63); + v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[8]]); + v[15] = (v[15] ^ v[0]).rotate_right(32); + v[10] = v[10].wrapping_add(v[15]); + v[5] = (v[5] ^ v[10]).rotate_right(24); + v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[9]]); + v[15] = (v[15] ^ v[0]).rotate_right(16); + v[10] = v[10].wrapping_add(v[15]); + v[5] = (v[5] ^ v[10]).rotate_right(63); + v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[10]]); + v[12] = (v[12] ^ v[1]).rotate_right(32); + v[11] = v[11].wrapping_add(v[12]); + v[6] = (v[6] ^ v[11]).rotate_right(24); + v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[11]]); + v[12] = (v[12] ^ v[1]).rotate_right(16); + v[11] = v[11].wrapping_add(v[12]); + v[6] = (v[6] ^ v[11]).rotate_right(63); + v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[12]]); + v[13] = (v[13] ^ v[2]).rotate_right(32); + v[8] = v[8].wrapping_add(v[13]); + v[7] = (v[7] ^ v[8]).rotate_right(24); + v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[13]]); + v[13] = (v[13] ^ v[2]).rotate_right(16); + v[8] = v[8].wrapping_add(v[13]); + v[7] = (v[7] ^ v[8]).rotate_right(63); + v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[14]]); + v[14] = (v[14] ^ v[3]).rotate_right(32); + v[9] = v[9].wrapping_add(v[14]); + v[4] = (v[4] ^ v[9]).rotate_right(24); + v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[15]]); + v[14] = (v[14] ^ v[3]).rotate_right(16); + v[9] = v[9].wrapping_add(v[14]); + v[4] = (v[4] ^ v[9]).rotate_right(63); + } + + for i in 0..8 { + h[i] ^= v[i] ^ v[i + 8]; + } +} \ No newline at end of file diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index 2f7535f..b011546 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -1,25 +1,33 @@ -extern crate blake2; extern crate ewasm_api; +mod f; + +use std::io::Cursor; +use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; +use arr_macro::arr; + #[cfg(not(test))] #[no_mangle] pub extern "C" fn main() { - use blake2::{Blake2b, Digest}; - - let length = ewasm_api::calldata_size(); + if ewasm_api::calldata_size() != 213 { + ewasm_api::revert() + } - // charge a base fee plus a word fee for every 256-bit word - let base_fee = 60; - let word_fee = 12; - let total_cost = base_fee + ((length + 31) / 32) * word_fee; + let mut data = Cursor::new(ewasm_api::calldata_acquire()); + let rounds = data.read_u32::().expect("Calldata size is invalid."); + let mut h = arr![data.read_u64::().expect("Calldata size is invalid."); 8]; + let m = arr![data.read_u64::().expect("Calldata size is invalid."); 16]; + let t = arr![data.read_u64::().expect("Calldata size is invalid."); 2]; + let f = data.read_u8().expect("Calldata size is invalid.") == 1; - ewasm_api::consume_gas(total_cost as u64); + ewasm_api::consume_gas(rounds as u64); - let data = ewasm_api::calldata_acquire(); + f::compress(rounds, &mut h, m, t, f); - let mut hasher = Blake2b::default(); - hasher.input(&data); - let hash = hasher.result(); + let mut h_bytes = vec![]; + for i in 0..8 { + h_bytes.write_u64::(h[i]).expect("Unable to write h.") + } - ewasm_api::finish_data(&hash) + ewasm_api::finish_data(h_bytes.as_slice()) } From 185c4261247b20a930e1a345cde96e0780c32b5b Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Tue, 28 Apr 2020 10:23:31 +0800 Subject: [PATCH 2/9] Formatting. --- blake2/src/f.rs | 190 +++++++++++++++++++++++----------------------- blake2/src/lib.rs | 12 ++- 2 files changed, 105 insertions(+), 97 deletions(-) diff --git a/blake2/src/f.rs b/blake2/src/f.rs index 508fe55..c3aaba3 100644 --- a/blake2/src/f.rs +++ b/blake2/src/f.rs @@ -1,105 +1,109 @@ - const SIGMA: [[usize; 16]; 10] = [ - [0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15], - [14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3], - [11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4], - [7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8], - [9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13], - [2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9], - [12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11], - [13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10], - [6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5], - [10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0], + [0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15], + [14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3], + [11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4], + [7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8], + [9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13], + [2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9], + [12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11], + [13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10], + [6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5], + [10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0], ]; - /// IV is an initialization vector for BLAKE2b const IV: [u64; 8] = [ - 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, - 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, + 0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179, ]; pub fn compress(rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { - let mut v = Vec::new(); - v.extend(h.iter().cloned()); - v.extend_from_slice(&IV); + let mut v = Vec::new(); + v.extend(h.iter().cloned()); + v.extend_from_slice(&IV); - v[12] ^= t[0]; - v[13] ^= t[1]; + v[12] ^= t[0]; + v[13] ^= t[1]; - if f { - v[14] = !v[14] - } + if f { + v[14] = !v[14] + } - for i in 0..rounds as usize { - let s = &SIGMA[i % 10]; - v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[0]]); - v[12] = (v[12] ^ v[0]).rotate_right(32); - v[8] = v[8].wrapping_add(v[12]); - v[4] = (v[4] ^ v[8]).rotate_right(24); - v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[1]]); - v[12] = (v[12] ^ v[0]).rotate_right(16); - v[8] = v[8].wrapping_add(v[12]); - v[4] = (v[4] ^ v[8]).rotate_right(63); - v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[2]]); - v[13] = (v[13] ^ v[1]).rotate_right(32); - v[9] = v[9].wrapping_add(v[13]); - v[5] = (v[5] ^ v[9]).rotate_right(24); - v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[3]]); - v[13] = (v[13] ^ v[1]).rotate_right(16); - v[9] = v[9].wrapping_add(v[13]); - v[5] = (v[5] ^ v[9]).rotate_right(63); - v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[4]]); - v[14] = (v[14] ^ v[2]).rotate_right(32); - v[10] = v[10].wrapping_add(v[14]); - v[6] = (v[6] ^ v[10]).rotate_right(24); - v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[5]]); - v[14] = (v[14] ^ v[2]).rotate_right(16); - v[10] = v[10].wrapping_add(v[14]); - v[6] = (v[6] ^ v[10]).rotate_right(63); - v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[6]]); - v[15] = (v[15] ^ v[3]).rotate_right(32); - v[11] = v[11].wrapping_add(v[15]); - v[7] = (v[7] ^ v[11]).rotate_right(24); - v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[7]]); - v[15] = (v[15] ^ v[3]).rotate_right(16); - v[11] = v[11].wrapping_add(v[15]); - v[7] = (v[7] ^ v[11]).rotate_right(63); - v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[8]]); - v[15] = (v[15] ^ v[0]).rotate_right(32); - v[10] = v[10].wrapping_add(v[15]); - v[5] = (v[5] ^ v[10]).rotate_right(24); - v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[9]]); - v[15] = (v[15] ^ v[0]).rotate_right(16); - v[10] = v[10].wrapping_add(v[15]); - v[5] = (v[5] ^ v[10]).rotate_right(63); - v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[10]]); - v[12] = (v[12] ^ v[1]).rotate_right(32); - v[11] = v[11].wrapping_add(v[12]); - v[6] = (v[6] ^ v[11]).rotate_right(24); - v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[11]]); - v[12] = (v[12] ^ v[1]).rotate_right(16); - v[11] = v[11].wrapping_add(v[12]); - v[6] = (v[6] ^ v[11]).rotate_right(63); - v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[12]]); - v[13] = (v[13] ^ v[2]).rotate_right(32); - v[8] = v[8].wrapping_add(v[13]); - v[7] = (v[7] ^ v[8]).rotate_right(24); - v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[13]]); - v[13] = (v[13] ^ v[2]).rotate_right(16); - v[8] = v[8].wrapping_add(v[13]); - v[7] = (v[7] ^ v[8]).rotate_right(63); - v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[14]]); - v[14] = (v[14] ^ v[3]).rotate_right(32); - v[9] = v[9].wrapping_add(v[14]); - v[4] = (v[4] ^ v[9]).rotate_right(24); - v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[15]]); - v[14] = (v[14] ^ v[3]).rotate_right(16); - v[9] = v[9].wrapping_add(v[14]); - v[4] = (v[4] ^ v[9]).rotate_right(63); - } + for i in 0..rounds as usize { + let s = &SIGMA[i % 10]; + v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[0]]); + v[12] = (v[12] ^ v[0]).rotate_right(32); + v[8] = v[8].wrapping_add(v[12]); + v[4] = (v[4] ^ v[8]).rotate_right(24); + v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[1]]); + v[12] = (v[12] ^ v[0]).rotate_right(16); + v[8] = v[8].wrapping_add(v[12]); + v[4] = (v[4] ^ v[8]).rotate_right(63); + v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[2]]); + v[13] = (v[13] ^ v[1]).rotate_right(32); + v[9] = v[9].wrapping_add(v[13]); + v[5] = (v[5] ^ v[9]).rotate_right(24); + v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[3]]); + v[13] = (v[13] ^ v[1]).rotate_right(16); + v[9] = v[9].wrapping_add(v[13]); + v[5] = (v[5] ^ v[9]).rotate_right(63); + v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[4]]); + v[14] = (v[14] ^ v[2]).rotate_right(32); + v[10] = v[10].wrapping_add(v[14]); + v[6] = (v[6] ^ v[10]).rotate_right(24); + v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[5]]); + v[14] = (v[14] ^ v[2]).rotate_right(16); + v[10] = v[10].wrapping_add(v[14]); + v[6] = (v[6] ^ v[10]).rotate_right(63); + v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[6]]); + v[15] = (v[15] ^ v[3]).rotate_right(32); + v[11] = v[11].wrapping_add(v[15]); + v[7] = (v[7] ^ v[11]).rotate_right(24); + v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[7]]); + v[15] = (v[15] ^ v[3]).rotate_right(16); + v[11] = v[11].wrapping_add(v[15]); + v[7] = (v[7] ^ v[11]).rotate_right(63); + v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[8]]); + v[15] = (v[15] ^ v[0]).rotate_right(32); + v[10] = v[10].wrapping_add(v[15]); + v[5] = (v[5] ^ v[10]).rotate_right(24); + v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[9]]); + v[15] = (v[15] ^ v[0]).rotate_right(16); + v[10] = v[10].wrapping_add(v[15]); + v[5] = (v[5] ^ v[10]).rotate_right(63); + v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[10]]); + v[12] = (v[12] ^ v[1]).rotate_right(32); + v[11] = v[11].wrapping_add(v[12]); + v[6] = (v[6] ^ v[11]).rotate_right(24); + v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[11]]); + v[12] = (v[12] ^ v[1]).rotate_right(16); + v[11] = v[11].wrapping_add(v[12]); + v[6] = (v[6] ^ v[11]).rotate_right(63); + v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[12]]); + v[13] = (v[13] ^ v[2]).rotate_right(32); + v[8] = v[8].wrapping_add(v[13]); + v[7] = (v[7] ^ v[8]).rotate_right(24); + v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[13]]); + v[13] = (v[13] ^ v[2]).rotate_right(16); + v[8] = v[8].wrapping_add(v[13]); + v[7] = (v[7] ^ v[8]).rotate_right(63); + v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[14]]); + v[14] = (v[14] ^ v[3]).rotate_right(32); + v[9] = v[9].wrapping_add(v[14]); + v[4] = (v[4] ^ v[9]).rotate_right(24); + v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[15]]); + v[14] = (v[14] ^ v[3]).rotate_right(16); + v[9] = v[9].wrapping_add(v[14]); + v[4] = (v[4] ^ v[9]).rotate_right(63); + } - for i in 0..8 { - h[i] ^= v[i] ^ v[i + 8]; - } -} \ No newline at end of file + for i in 0..8 { + h[i] ^= v[i] ^ v[i + 8]; + } +} diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index b011546..e0fe7a4 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -2,9 +2,9 @@ extern crate ewasm_api; mod f; -use std::io::Cursor; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; use arr_macro::arr; +use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::io::Cursor; #[cfg(not(test))] #[no_mangle] @@ -14,7 +14,9 @@ pub extern "C" fn main() { } let mut data = Cursor::new(ewasm_api::calldata_acquire()); - let rounds = data.read_u32::().expect("Calldata size is invalid."); + let rounds = data + .read_u32::() + .expect("Calldata size is invalid."); let mut h = arr![data.read_u64::().expect("Calldata size is invalid."); 8]; let m = arr![data.read_u64::().expect("Calldata size is invalid."); 16]; let t = arr![data.read_u64::().expect("Calldata size is invalid."); 2]; @@ -26,7 +28,9 @@ pub extern "C" fn main() { let mut h_bytes = vec![]; for i in 0..8 { - h_bytes.write_u64::(h[i]).expect("Unable to write h.") + h_bytes + .write_u64::(h[i]) + .expect("Unable to write h.") } ewasm_api::finish_data(h_bytes.as_slice()) From 7e679509c764b65da34b2688f338b3aa54d4d0c1 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Tue, 28 Apr 2020 22:45:16 +0800 Subject: [PATCH 3/9] Tests, fixes, and cleanup. --- blake2/Cargo.toml | 7 +- blake2/src/f.rs | 26 ++++---- blake2/src/lib.rs | 158 +++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 163 insertions(+), 28 deletions(-) diff --git a/blake2/Cargo.toml b/blake2/Cargo.toml index bb51c15..e04169e 100644 --- a/blake2/Cargo.toml +++ b/blake2/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "ewasm-precompile-blake2" version = "0.2.0" -authors = ["Alex Beregszaszi "] +authors = ["Grant Wuerker "] license = "Apache-2.0" repository = "https://github.com/ewasm/ewasm-precompiles" -description = "Ethereum Blake2 precompile in Rust" +description = "Ethereum Blake2 compression function precompile in Rust" publish = false edition = "2018" @@ -13,5 +13,8 @@ byteorder = "1.3.4" ewasm_api = "0.9" arr_macro = "0.1.3" +[dev-dependencies] +hex = "0.3.1" + [lib] crate-type = ["cdylib"] diff --git a/blake2/src/f.rs b/blake2/src/f.rs index c3aaba3..02d6d22 100644 --- a/blake2/src/f.rs +++ b/blake2/src/f.rs @@ -1,17 +1,21 @@ +///! Implementation of blake2 compression function F. +///! +///! This was copied from here: https://gist.github.com/seunlanlege/fa848401d316c52919f6e554fba6870b +///! with some modifications. It was initially written by Seun Lanlege and has no explicit license. + const SIGMA: [[usize; 16]; 10] = [ - [0, 2, 4, 6, 1, 3, 5, 7, 8, 10, 12, 14, 9, 11, 13, 15], - [14, 4, 9, 13, 10, 8, 15, 6, 1, 0, 11, 5, 12, 2, 7, 3], - [11, 12, 5, 15, 8, 0, 2, 13, 10, 3, 7, 9, 14, 6, 1, 4], - [7, 3, 13, 11, 9, 1, 12, 14, 2, 5, 4, 15, 6, 10, 0, 8], - [9, 5, 2, 10, 0, 7, 4, 15, 14, 11, 6, 3, 1, 12, 8, 13], - [2, 6, 0, 8, 12, 10, 11, 3, 4, 7, 15, 1, 13, 5, 14, 9], - [12, 1, 14, 4, 5, 15, 13, 10, 0, 6, 9, 8, 7, 3, 2, 11], - [13, 7, 12, 3, 11, 14, 1, 9, 5, 15, 8, 2, 0, 4, 6, 10], - [6, 14, 11, 0, 15, 9, 3, 8, 12, 13, 1, 10, 2, 7, 4, 5], - [10, 8, 7, 1, 2, 4, 6, 5, 15, 9, 3, 13, 11, 14, 12, 0], + [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 an initialization vector for BLAKE2b const IV: [u64; 8] = [ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index e0fe7a4..d3fe25d 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -9,29 +9,157 @@ use std::io::Cursor; #[cfg(not(test))] #[no_mangle] pub extern "C" fn main() { - if ewasm_api::calldata_size() != 213 { - ewasm_api::revert() + match blake2_f(ewasm_api::calldata_acquire()) { + Ok((gas_used, data)) => { + ewasm_api::consume_gas(gas_used); + ewasm_api::finish_data(data.as_slice()) + }, + Err(err) => ewasm_api::revert_data(err.as_bytes()), + } +} + +pub fn blake2_f(data: Vec) -> Result<(u64, Vec), &'static str> { + if data.len() == 213 { + let (rounds, mut h, m, t, f) = read_data(data)?; + f::compress(rounds, &mut h, m, t, f); + + return Ok((rounds as u64, write_data(h))); } - let mut data = Cursor::new(ewasm_api::calldata_acquire()); - let rounds = data + Err("input length for BLAKE2 F precompile should be exactly 213 bytes") +} + +fn read_data(data: Vec) -> Result<(u32, [u64; 8], [u64; 16], [u64; 2], bool), &'static str> { + let mut reader = Cursor::new(data); + + let rounds = reader .read_u32::() - .expect("Calldata size is invalid."); - let mut h = arr![data.read_u64::().expect("Calldata size is invalid."); 8]; - let m = arr![data.read_u64::().expect("Calldata size is invalid."); 16]; - let t = arr![data.read_u64::().expect("Calldata size is invalid."); 2]; - let f = data.read_u8().expect("Calldata size is invalid.") == 1; + .expect("Unable to read data."); + let h = arr![reader.read_u64::().expect("Unable to read data."); 8]; + let m = arr![reader.read_u64::().expect("Unable to read data."); 16]; + let t = arr![reader.read_u64::().expect("Unable to read data."); 2]; + let f = match reader.read_u8().expect("Unable to read data.") { + 0 => false, + 1 => true, + _ => return Err("incorrect final block indicator flag") + }; - ewasm_api::consume_gas(rounds as u64); + Ok((rounds, h, m, t, f)) +} - f::compress(rounds, &mut h, m, t, f); +fn write_data(h: [u64; 8]) -> Vec { + let mut data = vec![]; - let mut h_bytes = vec![]; for i in 0..8 { - h_bytes + data .write_u64::(h[i]) - .expect("Unable to write h.") + .expect("Unable to write data.") + } + + data +} + +/// See test cases at https://eips.ethereum.org/EIPS/eip-152. +#[cfg(test)] +mod tests { + extern crate hex; + use crate::blake2_f; + + const INPUTS: [&str; 9] = [ + "", + "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", + "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000", + "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + ]; + + + const OUTPUTS: [&str; 9] = [ + "", + "", + "", + "", + "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b", + "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735", + "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421", + "fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615", + ]; + + #[test] + fn case0() { + assert_eq!( + blake2_f(hex::decode(INPUTS[0]).unwrap()), + Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), + ) + } + + #[test] + fn case1() { + assert_eq!( + blake2_f(hex::decode(INPUTS[1]).unwrap()), + Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), + ) + } + + #[test] + fn case2() { + assert_eq!( + blake2_f(hex::decode(INPUTS[2]).unwrap()), + Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), + ) + } + + #[test] + fn case3() { + assert_eq!( + blake2_f(hex::decode(INPUTS[3]).unwrap()), + Err("incorrect final block indicator flag"), + ) + } + + #[test] + fn case4() { + assert_eq!( + blake2_f(hex::decode(INPUTS[4]).unwrap()), + Ok((0, hex::decode(OUTPUTS[4]).unwrap())), + ) + } + + #[test] + fn case5() { + assert_eq!( + blake2_f(hex::decode(INPUTS[5]).unwrap()), + Ok((12, hex::decode(OUTPUTS[5]).unwrap())), + ) + } + + #[test] + fn case6() { + assert_eq!( + blake2_f(hex::decode(INPUTS[6]).unwrap()), + Ok((12, hex::decode(OUTPUTS[6]).unwrap())), + ) + } + + #[test] + fn case7() { + assert_eq!( + blake2_f(hex::decode(INPUTS[7]).unwrap()), + Ok((1, hex::decode(OUTPUTS[7]).unwrap())), + ) } - ewasm_api::finish_data(h_bytes.as_slice()) + // This test is too slow at the moment. + // #[test] + // fn case8() { + // assert_eq!( + // blake2_f(hex::decode(inputs[8]).unwrap()), + // Ok((4294967295, hex::decode(outputs[8]).unwrap())), + // ) + // } } From 308bac0d21c378685dae80454ee05b6372a8d539 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Wed, 29 Apr 2020 14:18:36 +0800 Subject: [PATCH 4/9] Inline docs. --- blake2/src/f.rs | 20 +++++++++++++++++++- blake2/src/lib.rs | 11 +++++++---- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/blake2/src/f.rs b/blake2/src/f.rs index 02d6d22..2f58a40 100644 --- a/blake2/src/f.rs +++ b/blake2/src/f.rs @@ -1,8 +1,13 @@ ///! Implementation of blake2 compression function F. ///! -///! This was copied from here: https://gist.github.com/seunlanlege/fa848401d316c52919f6e554fba6870b +///! This was copied from https://gist.github.com/seunlanlege/fa848401d316c52919f6e554fba6870b ///! with some modifications. It was initially written by Seun Lanlege and has no explicit license. +/// Message word schedule permutations for each round of both BLAKE2b and BLAKE2s are defined by +/// SIGMA. For BLAKE2b, the two extra permutations for rounds 10 and 11 are +/// SIGMA[10..11] = SIGMA[0..1]. +/// +/// https://tools.ietf.org/html/rfc7693#section-2.7 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], @@ -14,8 +19,14 @@ const SIGMA: [[usize; 16]; 10] = [ [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[i] = floor(2**w * frac(sqrt(prime(i+1)))), where prime(i) is the i:th prime number +/// ( 2, 3, 5, 7, 11, 13, 17, 19 ) and sqrt(x) is the square root of x. +/// +/// https://tools.ietf.org/html/rfc7693#section-2.6 const IV: [u64; 8] = [ 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, @@ -27,6 +38,13 @@ const IV: [u64; 8] = [ 0x5be0cd19137e2179, ]; +/// Compression function F takes as an argument the state vector "h", message block vector "m" +/// (last block is padded with zeros to full block size, if required), 2w-bit offset counter "t", +/// and final block indicator flag "f". Local vector v[0..15] is used in processing. F returns a +/// new state vector. The number of rounds, "r", is 12 for BLAKE2b and 10 for BLAKE2s. +/// Rounds are numbered from 0 to r - 1. +/// +/// https://tools.ietf.org/html/rfc7693#section-3.2 pub fn compress(rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { let mut v = Vec::new(); v.extend(h.iter().cloned()); diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index d3fe25d..a59438c 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -18,6 +18,7 @@ pub extern "C" fn main() { } } +/// The Blake2F precompile written as Result returning function. pub fn blake2_f(data: Vec) -> Result<(u64, Vec), &'static str> { if data.len() == 213 { let (rounds, mut h, m, t, f) = read_data(data)?; @@ -60,6 +61,9 @@ fn write_data(h: [u64; 8]) -> Vec { } /// See test cases at https://eips.ethereum.org/EIPS/eip-152. +/// +/// You will most likely need to specify a target to run these tests. +/// Example: `cargo test --target x86_64-unknown-linux-gnu` #[cfg(test)] mod tests { extern crate hex; @@ -154,12 +158,11 @@ mod tests { ) } - // This test is too slow at the moment. // #[test] // fn case8() { // assert_eq!( - // blake2_f(hex::decode(inputs[8]).unwrap()), - // Ok((4294967295, hex::decode(outputs[8]).unwrap())), - // ) + // blake2_f(hex::decode(INPUTS[8]).unwrap()), + // Ok((4294967295, hex::decode(OUTPUTS[8]).unwrap())), + // ); // } } From df8a8e4aa5a7ee6024cdfef058111fd396d41854 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Wed, 29 Apr 2020 14:20:21 +0800 Subject: [PATCH 5/9] Formatting. --- blake2/src/f.rs | 2 -- blake2/src/lib.rs | 8 +++----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/blake2/src/f.rs b/blake2/src/f.rs index 2f58a40..6b5875f 100644 --- a/blake2/src/f.rs +++ b/blake2/src/f.rs @@ -19,10 +19,8 @@ const SIGMA: [[usize; 16]; 10] = [ [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[i] = floor(2**w * frac(sqrt(prime(i+1)))), where prime(i) is the i:th prime number /// ( 2, 3, 5, 7, 11, 13, 17, 19 ) and sqrt(x) is the square root of x. /// diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index a59438c..48b169a 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -13,7 +13,7 @@ pub extern "C" fn main() { Ok((gas_used, data)) => { ewasm_api::consume_gas(gas_used); ewasm_api::finish_data(data.as_slice()) - }, + } Err(err) => ewasm_api::revert_data(err.as_bytes()), } } @@ -42,7 +42,7 @@ fn read_data(data: Vec) -> Result<(u32, [u64; 8], [u64; 16], [u64; 2], bool) let f = match reader.read_u8().expect("Unable to read data.") { 0 => false, 1 => true, - _ => return Err("incorrect final block indicator flag") + _ => return Err("incorrect final block indicator flag"), }; Ok((rounds, h, m, t, f)) @@ -52,8 +52,7 @@ fn write_data(h: [u64; 8]) -> Vec { let mut data = vec![]; for i in 0..8 { - data - .write_u64::(h[i]) + data.write_u64::(h[i]) .expect("Unable to write data.") } @@ -81,7 +80,6 @@ mod tests { "ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", ]; - const OUTPUTS: [&str; 9] = [ "", "", From 0b67cb2dcf242dd50909039292405eea5be94575 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Wed, 29 Apr 2020 19:57:36 +0800 Subject: [PATCH 6/9] Benchmarking test. --- blake2/src/lib.rs | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index 48b169a..80fd341 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -61,12 +61,14 @@ fn write_data(h: [u64; 8]) -> Vec { /// See test cases at https://eips.ethereum.org/EIPS/eip-152. /// -/// You will most likely need to specify a target to run these tests. -/// Example: `cargo test --target x86_64-unknown-linux-gnu` +/// You will most likely need to override the default target like so: +/// Example: `cargo test --target x86_64-unknown-linux-gnu --release` #[cfg(test)] mod tests { extern crate hex; + use crate::blake2_f; + use std::time::Instant; const INPUTS: [&str; 9] = [ "", @@ -92,6 +94,9 @@ mod tests { "fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615", ]; + /// 1200 rounds + const BENCH_INPUT: &str = "000004B048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"; + #[test] fn case0() { assert_eq!( @@ -156,6 +161,8 @@ mod tests { ) } + // This test takes excessively long. + // // #[test] // fn case8() { // assert_eq!( @@ -163,4 +170,19 @@ mod tests { // Ok((4294967295, hex::decode(OUTPUTS[8]).unwrap())), // ); // } + + /// run with `-- --nocapture` + #[test] + fn benchmark() { + let n = 1000; + let mut sum = 0; + + for _ in 0..n { + let now = Instant::now(); + blake2_f(hex::decode(BENCH_INPUT).unwrap()).expect("Couldn't compress BENCH_INPUT."); + sum += now.elapsed().as_nanos(); + } + + println!("Average elapsed time for 1200 rounds: {}ns", sum / n) + } } From 50444b56e87ad2a3fd6413eaa77e539f684ab648 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Tue, 12 May 2020 11:22:37 +0800 Subject: [PATCH 7/9] Readded blake2 precompile. squash --- blake2/Cargo.toml | 10 +- blake2/src/lib.rs | 189 +++-------------------------------- blake2f/Cargo.toml | 20 ++++ {blake2 => blake2f}/src/f.rs | 8 +- blake2f/src/lib.rs | 188 ++++++++++++++++++++++++++++++++++ 5 files changed, 228 insertions(+), 187 deletions(-) create mode 100644 blake2f/Cargo.toml rename {blake2 => blake2f}/src/f.rs (95%) create mode 100644 blake2f/src/lib.rs diff --git a/blake2/Cargo.toml b/blake2/Cargo.toml index e04169e..9207d69 100644 --- a/blake2/Cargo.toml +++ b/blake2/Cargo.toml @@ -1,20 +1,16 @@ [package] name = "ewasm-precompile-blake2" version = "0.2.0" -authors = ["Grant Wuerker "] +authors = ["Alex Beregszaszi "] license = "Apache-2.0" repository = "https://github.com/ewasm/ewasm-precompiles" -description = "Ethereum Blake2 compression function precompile in Rust" +description = "Ethereum Blake2 precompile in Rust" publish = false edition = "2018" [dependencies] -byteorder = "1.3.4" +blake2 = "0.7" ewasm_api = "0.9" -arr_macro = "0.1.3" - -[dev-dependencies] -hex = "0.3.1" [lib] crate-type = ["cdylib"] diff --git a/blake2/src/lib.rs b/blake2/src/lib.rs index 80fd341..2f7535f 100644 --- a/blake2/src/lib.rs +++ b/blake2/src/lib.rs @@ -1,188 +1,25 @@ +extern crate blake2; extern crate ewasm_api; -mod f; - -use arr_macro::arr; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::io::Cursor; - #[cfg(not(test))] #[no_mangle] pub extern "C" fn main() { - match blake2_f(ewasm_api::calldata_acquire()) { - Ok((gas_used, data)) => { - ewasm_api::consume_gas(gas_used); - ewasm_api::finish_data(data.as_slice()) - } - Err(err) => ewasm_api::revert_data(err.as_bytes()), - } -} - -/// The Blake2F precompile written as Result returning function. -pub fn blake2_f(data: Vec) -> Result<(u64, Vec), &'static str> { - if data.len() == 213 { - let (rounds, mut h, m, t, f) = read_data(data)?; - f::compress(rounds, &mut h, m, t, f); - - return Ok((rounds as u64, write_data(h))); - } - - Err("input length for BLAKE2 F precompile should be exactly 213 bytes") -} - -fn read_data(data: Vec) -> Result<(u32, [u64; 8], [u64; 16], [u64; 2], bool), &'static str> { - let mut reader = Cursor::new(data); - - let rounds = reader - .read_u32::() - .expect("Unable to read data."); - let h = arr![reader.read_u64::().expect("Unable to read data."); 8]; - let m = arr![reader.read_u64::().expect("Unable to read data."); 16]; - let t = arr![reader.read_u64::().expect("Unable to read data."); 2]; - let f = match reader.read_u8().expect("Unable to read data.") { - 0 => false, - 1 => true, - _ => return Err("incorrect final block indicator flag"), - }; - - Ok((rounds, h, m, t, f)) -} - -fn write_data(h: [u64; 8]) -> Vec { - let mut data = vec![]; - - for i in 0..8 { - data.write_u64::(h[i]) - .expect("Unable to write data.") - } - - data -} - -/// See test cases at https://eips.ethereum.org/EIPS/eip-152. -/// -/// You will most likely need to override the default target like so: -/// Example: `cargo test --target x86_64-unknown-linux-gnu --release` -#[cfg(test)] -mod tests { - extern crate hex; - - use crate::blake2_f; - use std::time::Instant; - - const INPUTS: [&str; 9] = [ - "", - "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", - "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", - "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", - "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", - "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", - "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000", - "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", - "ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", - ]; - - const OUTPUTS: [&str; 9] = [ - "", - "", - "", - "", - "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b", - "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", - "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735", - "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421", - "fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615", - ]; - - /// 1200 rounds - const BENCH_INPUT: &str = "000004B048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"; - - #[test] - fn case0() { - assert_eq!( - blake2_f(hex::decode(INPUTS[0]).unwrap()), - Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), - ) - } - - #[test] - fn case1() { - assert_eq!( - blake2_f(hex::decode(INPUTS[1]).unwrap()), - Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), - ) - } - - #[test] - fn case2() { - assert_eq!( - blake2_f(hex::decode(INPUTS[2]).unwrap()), - Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), - ) - } - - #[test] - fn case3() { - assert_eq!( - blake2_f(hex::decode(INPUTS[3]).unwrap()), - Err("incorrect final block indicator flag"), - ) - } - - #[test] - fn case4() { - assert_eq!( - blake2_f(hex::decode(INPUTS[4]).unwrap()), - Ok((0, hex::decode(OUTPUTS[4]).unwrap())), - ) - } - - #[test] - fn case5() { - assert_eq!( - blake2_f(hex::decode(INPUTS[5]).unwrap()), - Ok((12, hex::decode(OUTPUTS[5]).unwrap())), - ) - } + use blake2::{Blake2b, Digest}; - #[test] - fn case6() { - assert_eq!( - blake2_f(hex::decode(INPUTS[6]).unwrap()), - Ok((12, hex::decode(OUTPUTS[6]).unwrap())), - ) - } + let length = ewasm_api::calldata_size(); - #[test] - fn case7() { - assert_eq!( - blake2_f(hex::decode(INPUTS[7]).unwrap()), - Ok((1, hex::decode(OUTPUTS[7]).unwrap())), - ) - } + // charge a base fee plus a word fee for every 256-bit word + let base_fee = 60; + let word_fee = 12; + let total_cost = base_fee + ((length + 31) / 32) * word_fee; - // This test takes excessively long. - // - // #[test] - // fn case8() { - // assert_eq!( - // blake2_f(hex::decode(INPUTS[8]).unwrap()), - // Ok((4294967295, hex::decode(OUTPUTS[8]).unwrap())), - // ); - // } + ewasm_api::consume_gas(total_cost as u64); - /// run with `-- --nocapture` - #[test] - fn benchmark() { - let n = 1000; - let mut sum = 0; + let data = ewasm_api::calldata_acquire(); - for _ in 0..n { - let now = Instant::now(); - blake2_f(hex::decode(BENCH_INPUT).unwrap()).expect("Couldn't compress BENCH_INPUT."); - sum += now.elapsed().as_nanos(); - } + let mut hasher = Blake2b::default(); + hasher.input(&data); + let hash = hasher.result(); - println!("Average elapsed time for 1200 rounds: {}ns", sum / n) - } + ewasm_api::finish_data(&hash) } diff --git a/blake2f/Cargo.toml b/blake2f/Cargo.toml new file mode 100644 index 0000000..3e75b06 --- /dev/null +++ b/blake2f/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "ewasm-precompile-blake2f" +version = "0.2.0" +authors = ["Grant Wuerker "] +license = "Apache-2.0" +repository = "https://github.com/ewasm/ewasm-precompiles" +description = "Ethereum Blake2 compression function precompile in Rust" +publish = false +edition = "2018" + +[dependencies] +byteorder = "1.3.4" +ewasm_api = "0.9" +arr_macro = "0.1.3" + +[dev-dependencies] +hex = "0.3.1" + +[lib] +crate-type = ["cdylib"] diff --git a/blake2/src/f.rs b/blake2f/src/f.rs similarity index 95% rename from blake2/src/f.rs rename to blake2f/src/f.rs index 6b5875f..5b6eab5 100644 --- a/blake2/src/f.rs +++ b/blake2f/src/f.rs @@ -1,7 +1,7 @@ -///! Implementation of blake2 compression function F. -///! -///! This was copied from https://gist.github.com/seunlanlege/fa848401d316c52919f6e554fba6870b -///! with some modifications. It was initially written by Seun Lanlege and has no explicit license. +//! Implementation of blake2 compression function F. +//! +//! This was copied from https://gist.github.com/seunlanlege/fa848401d316c52919f6e554fba6870b +//! with some modifications. It was initially written by Seun Lanlege and has no explicit license. /// Message word schedule permutations for each round of both BLAKE2b and BLAKE2s are defined by /// SIGMA. For BLAKE2b, the two extra permutations for rounds 10 and 11 are diff --git a/blake2f/src/lib.rs b/blake2f/src/lib.rs new file mode 100644 index 0000000..9722c7a --- /dev/null +++ b/blake2f/src/lib.rs @@ -0,0 +1,188 @@ +extern crate ewasm_api; + +mod f; + +use arr_macro::arr; +use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::io::Cursor; + +#[cfg(not(test))] +#[no_mangle] +pub extern "C" fn main() { + match blake2_f(ewasm_api::calldata_acquire()) { + Ok((gas_used, data)) => { + ewasm_api::consume_gas(gas_used); + ewasm_api::finish_data(data.as_slice()) + } + Err(err) => ewasm_api::revert_data(err.as_bytes()), + } +} + +/// The Blake2F precompile written as a Result returning function. +pub fn blake2_f(data: Vec) -> Result<(u64, Vec), &'static str> { + if data.len() == 213 { + let (rounds, mut h, m, t, f) = read_data(data)?; + f::compress(rounds, &mut h, m, t, f); + + return Ok((rounds as u64, write_data(h))); + } + + Err("input length for BLAKE2 F precompile should be exactly 213 bytes") +} + +fn read_data(data: Vec) -> Result<(u32, [u64; 8], [u64; 16], [u64; 2], bool), &'static str> { + let mut reader = Cursor::new(data); + + let rounds = reader + .read_u32::() + .expect("Unable to read data."); + let h = arr![reader.read_u64::().expect("Unable to read data."); 8]; + let m = arr![reader.read_u64::().expect("Unable to read data."); 16]; + let t = arr![reader.read_u64::().expect("Unable to read data."); 2]; + let f = match reader.read_u8().expect("Unable to read data.") { + 0 => false, + 1 => true, + _ => return Err("incorrect final block indicator flag"), + }; + + Ok((rounds, h, m, t, f)) +} + +fn write_data(h: [u64; 8]) -> Vec { + let mut data = vec![]; + + for i in 0..8 { + data.write_u64::(h[i]) + .expect("Unable to write data.") + } + + data +} + +/// See test cases at https://eips.ethereum.org/EIPS/eip-152. +/// +/// You will most likely need to override the default target like so: +/// Example: `cargo test --target x86_64-unknown-linux-gnu --release` +#[cfg(test)] +mod tests { + extern crate hex; + + use crate::blake2_f; + use std::time::Instant; + + const INPUTS: [&str; 9] = [ + "", + "00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002", + "0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000", + "0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + "ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001", + ]; + + const OUTPUTS: [&str; 9] = [ + "", + "", + "", + "", + "08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b", + "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + "75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735", + "b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421", + "fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615", + ]; + + /// 1200 rounds + const BENCH_INPUT: &str = "000004B048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"; + + #[test] + fn case0() { + assert_eq!( + blake2_f(hex::decode(INPUTS[0]).unwrap()), + Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), + ) + } + + #[test] + fn case1() { + assert_eq!( + blake2_f(hex::decode(INPUTS[1]).unwrap()), + Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), + ) + } + + #[test] + fn case2() { + assert_eq!( + blake2_f(hex::decode(INPUTS[2]).unwrap()), + Err("input length for BLAKE2 F precompile should be exactly 213 bytes"), + ) + } + + #[test] + fn case3() { + assert_eq!( + blake2_f(hex::decode(INPUTS[3]).unwrap()), + Err("incorrect final block indicator flag"), + ) + } + + #[test] + fn case4() { + assert_eq!( + blake2_f(hex::decode(INPUTS[4]).unwrap()), + Ok((0, hex::decode(OUTPUTS[4]).unwrap())), + ) + } + + #[test] + fn case5() { + assert_eq!( + blake2_f(hex::decode(INPUTS[5]).unwrap()), + Ok((12, hex::decode(OUTPUTS[5]).unwrap())), + ) + } + + #[test] + fn case6() { + assert_eq!( + blake2_f(hex::decode(INPUTS[6]).unwrap()), + Ok((12, hex::decode(OUTPUTS[6]).unwrap())), + ) + } + + #[test] + fn case7() { + assert_eq!( + blake2_f(hex::decode(INPUTS[7]).unwrap()), + Ok((1, hex::decode(OUTPUTS[7]).unwrap())), + ) + } + + // This test takes excessively long. + // + // #[test] + // fn case8() { + // assert_eq!( + // blake2_f(hex::decode(INPUTS[8]).unwrap()), + // Ok((4294967295, hex::decode(OUTPUTS[8]).unwrap())), + // ); + // } + + /// run with `-- --nocapture` + #[test] + fn benchmark() { + let n = 1000; + let mut sum = 0; + + for _ in 0..n { + let now = Instant::now(); + blake2_f(hex::decode(BENCH_INPUT).unwrap()).expect("Couldn't compress BENCH_INPUT."); + sum += now.elapsed().as_nanos(); + } + + println!("Average elapsed time for 1200 rounds: {}ns", sum / n) + } +} From 66a7a22e4ca1bf45ab9ff5c41475c1ad639c3f30 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Fri, 15 May 2020 22:39:59 +0800 Subject: [PATCH 8/9] Blake2f license. s --- Cargo.toml | 1 + blake2f/LICENSE | 25 +++++++++ blake2f/src/f.rs | 134 +++++++++++++++------------------------------ blake2f/src/lib.rs | 4 +- 4 files changed, 73 insertions(+), 91 deletions(-) create mode 100644 blake2f/LICENSE diff --git a/Cargo.toml b/Cargo.toml index 59d1561..a1bd4ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "blake2", + "blake2f", "bls12pairing", "ecadd", "ecmul", diff --git a/blake2f/LICENSE b/blake2f/LICENSE new file mode 100644 index 0000000..09df722 --- /dev/null +++ b/blake2f/LICENSE @@ -0,0 +1,25 @@ +This program is copyright 2020 Parity Technologies Limited and its licensors. + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + +Some portions of the program (“the Software”) are Copyright (c) 2018 Jack O'Connor +and the following relates solely to such portions: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/blake2f/src/f.rs b/blake2f/src/f.rs index 5b6eab5..5eef104 100644 --- a/blake2f/src/f.rs +++ b/blake2f/src/f.rs @@ -1,13 +1,12 @@ -//! Implementation of blake2 compression function F. -//! -//! This was copied from https://gist.github.com/seunlanlege/fa848401d316c52919f6e554fba6870b -//! with some modifications. It was initially written by Seun Lanlege and has no explicit license. - -/// Message word schedule permutations for each round of both BLAKE2b and BLAKE2s are defined by -/// SIGMA. For BLAKE2b, the two extra permutations for rounds 10 and 11 are -/// SIGMA[10..11] = SIGMA[0..1]. +/// The following code has been copied from the OpenEthereum project, which is distributed under +/// the terms of the GNU General Public License. A copy of its license has been included in this +/// crate. /// -/// https://tools.ietf.org/html/rfc7693#section-2.7 +/// https://github.com/openethereum/openethereum/tree/master/util/EIP-152 + +/// 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], @@ -21,10 +20,8 @@ const SIGMA: [[usize; 16]; 10] = [ [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0], ]; -/// IV[i] = floor(2**w * frac(sqrt(prime(i+1)))), where prime(i) is the i:th prime number -/// ( 2, 3, 5, 7, 11, 13, 17, 19 ) and sqrt(x) is the square root of x. -/// -/// https://tools.ietf.org/html/rfc7693#section-2.6 +/// 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, @@ -36,91 +33,48 @@ const IV: [u64; 8] = [ 0x5be0cd19137e2179, ]; -/// Compression function F takes as an argument the state vector "h", message block vector "m" -/// (last block is padded with zeros to full block size, if required), 2w-bit offset counter "t", -/// and final block indicator flag "f". Local vector v[0..15] is used in processing. F returns a -/// new state vector. The number of rounds, "r", is 12 for BLAKE2b and 10 for BLAKE2s. -/// Rounds are numbered from 0 to r - 1. -/// -/// https://tools.ietf.org/html/rfc7693#section-3.2 -pub fn compress(rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { - let mut v = Vec::new(); - v.extend(h.iter().cloned()); - v.extend_from_slice(&IV); +/// The G mixing function. See https://tools.ietf.org/html/rfc7693#section-3.1 +#[inline(always)] +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 Blake2b 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(rounds: usize, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { + let mut v = [0u64; 16]; + v[..8].copy_from_slice(h); // First half from state. + v[8..].copy_from_slice(&IV); // Second half from IV. v[12] ^= t[0]; v[13] ^= t[1]; if f { - v[14] = !v[14] + v[14] = !v[14]; // Invert all bits if the last-block-flag is set. } - for i in 0..rounds as usize { + for i in 0..rounds { + // Message word selection permutation for this round. let s = &SIGMA[i % 10]; - v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[0]]); - v[12] = (v[12] ^ v[0]).rotate_right(32); - v[8] = v[8].wrapping_add(v[12]); - v[4] = (v[4] ^ v[8]).rotate_right(24); - v[0] = v[0].wrapping_add(v[4]).wrapping_add(m[s[1]]); - v[12] = (v[12] ^ v[0]).rotate_right(16); - v[8] = v[8].wrapping_add(v[12]); - v[4] = (v[4] ^ v[8]).rotate_right(63); - v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[2]]); - v[13] = (v[13] ^ v[1]).rotate_right(32); - v[9] = v[9].wrapping_add(v[13]); - v[5] = (v[5] ^ v[9]).rotate_right(24); - v[1] = v[1].wrapping_add(v[5]).wrapping_add(m[s[3]]); - v[13] = (v[13] ^ v[1]).rotate_right(16); - v[9] = v[9].wrapping_add(v[13]); - v[5] = (v[5] ^ v[9]).rotate_right(63); - v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[4]]); - v[14] = (v[14] ^ v[2]).rotate_right(32); - v[10] = v[10].wrapping_add(v[14]); - v[6] = (v[6] ^ v[10]).rotate_right(24); - v[2] = v[2].wrapping_add(v[6]).wrapping_add(m[s[5]]); - v[14] = (v[14] ^ v[2]).rotate_right(16); - v[10] = v[10].wrapping_add(v[14]); - v[6] = (v[6] ^ v[10]).rotate_right(63); - v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[6]]); - v[15] = (v[15] ^ v[3]).rotate_right(32); - v[11] = v[11].wrapping_add(v[15]); - v[7] = (v[7] ^ v[11]).rotate_right(24); - v[3] = v[3].wrapping_add(v[7]).wrapping_add(m[s[7]]); - v[15] = (v[15] ^ v[3]).rotate_right(16); - v[11] = v[11].wrapping_add(v[15]); - v[7] = (v[7] ^ v[11]).rotate_right(63); - v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[8]]); - v[15] = (v[15] ^ v[0]).rotate_right(32); - v[10] = v[10].wrapping_add(v[15]); - v[5] = (v[5] ^ v[10]).rotate_right(24); - v[0] = v[0].wrapping_add(v[5]).wrapping_add(m[s[9]]); - v[15] = (v[15] ^ v[0]).rotate_right(16); - v[10] = v[10].wrapping_add(v[15]); - v[5] = (v[5] ^ v[10]).rotate_right(63); - v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[10]]); - v[12] = (v[12] ^ v[1]).rotate_right(32); - v[11] = v[11].wrapping_add(v[12]); - v[6] = (v[6] ^ v[11]).rotate_right(24); - v[1] = v[1].wrapping_add(v[6]).wrapping_add(m[s[11]]); - v[12] = (v[12] ^ v[1]).rotate_right(16); - v[11] = v[11].wrapping_add(v[12]); - v[6] = (v[6] ^ v[11]).rotate_right(63); - v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[12]]); - v[13] = (v[13] ^ v[2]).rotate_right(32); - v[8] = v[8].wrapping_add(v[13]); - v[7] = (v[7] ^ v[8]).rotate_right(24); - v[2] = v[2].wrapping_add(v[7]).wrapping_add(m[s[13]]); - v[13] = (v[13] ^ v[2]).rotate_right(16); - v[8] = v[8].wrapping_add(v[13]); - v[7] = (v[7] ^ v[8]).rotate_right(63); - v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[14]]); - v[14] = (v[14] ^ v[3]).rotate_right(32); - v[9] = v[9].wrapping_add(v[14]); - v[4] = (v[4] ^ v[9]).rotate_right(24); - v[3] = v[3].wrapping_add(v[4]).wrapping_add(m[s[15]]); - v[14] = (v[14] ^ v[3]).rotate_right(16); - v[9] = v[9].wrapping_add(v[14]); - v[4] = (v[4] ^ v[9]).rotate_right(63); + 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 { diff --git a/blake2f/src/lib.rs b/blake2f/src/lib.rs index 9722c7a..763e513 100644 --- a/blake2f/src/lib.rs +++ b/blake2f/src/lib.rs @@ -1,3 +1,5 @@ +//! Blake2f precompile as described in EIP-152 + extern crate ewasm_api; mod f; @@ -22,7 +24,7 @@ pub extern "C" fn main() { pub fn blake2_f(data: Vec) -> Result<(u64, Vec), &'static str> { if data.len() == 213 { let (rounds, mut h, m, t, f) = read_data(data)?; - f::compress(rounds, &mut h, m, t, f); + f::compress(rounds as usize, &mut h, m, t, f); return Ok((rounds as u64, write_data(h))); } From 983158abb0d77d51a8014f5b9733d534d92adc25 Mon Sep 17 00:00:00 2001 From: Grant Wuerker Date: Sat, 16 May 2020 15:56:30 +0800 Subject: [PATCH 9/9] Blake2f added to chisel.yaml --- chisel.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/chisel.yml b/chisel.yml index d5fd0d8..4095dd3 100644 --- a/chisel.yml +++ b/chisel.yml @@ -13,6 +13,21 @@ blake2: repack: preset: "ewasm" +blake2f: + file: "target/wasm32-unknown-unknown/release/ewasm_precompile_blake2f.wasm" + remapimports: + preset: "ewasm" + trimexports: + preset: "ewasm" + verifyimports: + preset: "ewasm" + verifyexports: + preset: "ewasm" + snip: + preset: "ewasm" + repack: + preset: "ewasm" + bls12pairing: file: "target/wasm32-unknown-unknown/release/ewasm_precompile_bls12pairing.wasm" remapimports: