Hashable::sha3 -> fn keccak for ethcore-util
This commit is contained in:
18
util/hash/Cargo.toml
Normal file
18
util/hash/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
description = "Rust bindings for tinykeccak C library"
|
||||
homepage = "http://parity.io"
|
||||
license = "GPL-3.0"
|
||||
name = "hash"
|
||||
version = "0.1.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
ethcore-bigint = { path = "../bigint" }
|
||||
tiny-keccak = "1.3"
|
||||
|
||||
[build-dependencies]
|
||||
gcc = "0.3"
|
||||
|
||||
[dev-dependencies]
|
||||
tempdir = "0.3"
|
||||
26
util/hash/build.rs
Normal file
26
util/hash/build.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// build.rs
|
||||
|
||||
// Bring in a dependency on an externally maintained `gcc` package which manages
|
||||
// invoking the C compiler.
|
||||
extern crate gcc;
|
||||
|
||||
fn main() {
|
||||
gcc::compile_library("libtinykeccak.a", &["src/tinykeccak.c"]);
|
||||
}
|
||||
|
||||
106
util/hash/src/lib.rs
Normal file
106
util/hash/src/lib.rs
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
extern crate ethcore_bigint as bigint;
|
||||
extern crate tiny_keccak;
|
||||
|
||||
use std::io;
|
||||
use tiny_keccak::Keccak;
|
||||
pub use bigint::hash::H256;
|
||||
|
||||
/// Get the KECCAK (i.e. Keccak) hash of the empty bytes string.
|
||||
pub const KECCAK_EMPTY: H256 = H256( [0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6, 0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70] );
|
||||
|
||||
/// The KECCAK of the RLP encoding of empty data.
|
||||
pub const KECCAK_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] );
|
||||
|
||||
/// The KECCAK of the RLP encoding of empty list.
|
||||
pub const KECCAK_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45, 0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47] );
|
||||
|
||||
extern {
|
||||
pub fn keccak_256(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32;
|
||||
pub fn keccak_512(out: *mut u8, outlen: usize, input: *const u8, inputlen: usize) -> i32;
|
||||
}
|
||||
|
||||
pub fn keccak<T: AsRef<[u8]>>(s: T) -> H256 {
|
||||
let mut result = [0u8; 32];
|
||||
keccak_into(s, &mut result);
|
||||
H256(result)
|
||||
}
|
||||
|
||||
pub fn keccak_into<T: AsRef<[u8]>>(s: T, dest: &mut [u8]) {
|
||||
let input = s.as_ref();
|
||||
unsafe {
|
||||
keccak_256(dest.as_mut_ptr(), dest.len(), input.as_ptr(), input.len());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keccak_buffer(r: &mut io::BufRead) -> Result<H256, io::Error> {
|
||||
let mut output = [0u8; 32];
|
||||
let mut input = [0u8; 1024];
|
||||
let mut keccak = Keccak::new_keccak256();
|
||||
|
||||
// read file
|
||||
loop {
|
||||
let some = r.read(&mut input)?;
|
||||
if some == 0 {
|
||||
break;
|
||||
}
|
||||
keccak.update(&input[0..some]);
|
||||
}
|
||||
|
||||
keccak.finalize(&mut output);
|
||||
Ok(output.into())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
extern crate tempdir;
|
||||
|
||||
use std::fs;
|
||||
use std::io::{Write, BufReader};
|
||||
use self::tempdir::TempDir;
|
||||
use super::{keccak, keccak_buffer, KECCAK_EMPTY};
|
||||
|
||||
#[test]
|
||||
fn keccak_empty() {
|
||||
assert_eq!(keccak([0u8; 0]), KECCAK_EMPTY);
|
||||
}
|
||||
#[test]
|
||||
fn keccak_as() {
|
||||
assert_eq!(keccak([0x41u8; 32]), From::from("59cad5948673622c1d64e2322488bf01619f7ff45789741b15a9f782ce9290a8"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_keccak_a_file() {
|
||||
// given
|
||||
let tempdir = TempDir::new("keccak").unwrap();
|
||||
let mut path = tempdir.path().to_owned();
|
||||
path.push("should_keccak_a_file");
|
||||
// Prepare file
|
||||
{
|
||||
let mut file = fs::File::create(&path).unwrap();
|
||||
file.write_all(b"something").unwrap();
|
||||
}
|
||||
|
||||
let mut file = BufReader::new(fs::File::open(&path).unwrap());
|
||||
// when
|
||||
let hash = keccak_buffer(&mut file).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(format!("{:?}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87");
|
||||
}
|
||||
}
|
||||
177
util/hash/src/tinykeccak.c
Normal file
177
util/hash/src/tinykeccak.c
Normal file
@@ -0,0 +1,177 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
/** libkeccak-tiny
|
||||
*
|
||||
* A single-file implementation of SHA-3 and SHAKE.
|
||||
*
|
||||
* Implementor: David Leon Gil
|
||||
* License: CC0, attribution kindly requested. Blame taken too,
|
||||
* but not liability.
|
||||
*/
|
||||
|
||||
#define decshake(bits) \
|
||||
int shake##bits(uint8_t*, size_t, const uint8_t*, size_t);
|
||||
|
||||
#define deckeccak(bits) \
|
||||
int keccak_##bits(uint8_t*, size_t, const uint8_t*, size_t);
|
||||
|
||||
decshake(128)
|
||||
decshake(256)
|
||||
deckeccak(224)
|
||||
deckeccak(256)
|
||||
deckeccak(384)
|
||||
deckeccak(512)
|
||||
|
||||
/******** The Keccak-f[1600] permutation ********/
|
||||
|
||||
/*** Constants. ***/
|
||||
static const uint8_t rho[24] = \
|
||||
{ 1, 3, 6, 10, 15, 21,
|
||||
28, 36, 45, 55, 2, 14,
|
||||
27, 41, 56, 8, 25, 43,
|
||||
62, 18, 39, 61, 20, 44};
|
||||
static const uint8_t pi[24] = \
|
||||
{10, 7, 11, 17, 18, 3,
|
||||
5, 16, 8, 21, 24, 4,
|
||||
15, 23, 19, 13, 12, 2,
|
||||
20, 14, 22, 9, 6, 1};
|
||||
static const uint64_t RC[24] = \
|
||||
{1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL,
|
||||
0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL,
|
||||
0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL,
|
||||
0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL,
|
||||
0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL,
|
||||
0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL};
|
||||
|
||||
/*** Helper macros to unroll the permutation. ***/
|
||||
#define rol(x, s) (((x) << s) | ((x) >> (64 - s)))
|
||||
#define REPEAT6(e) e e e e e e
|
||||
#define REPEAT24(e) REPEAT6(e e e e)
|
||||
#define REPEAT5(e) e e e e e
|
||||
#define FOR5(v, s, e) \
|
||||
v = 0; \
|
||||
REPEAT5(e; v += s;)
|
||||
|
||||
/*** Keccak-f[1600] ***/
|
||||
static inline void keccakf(void* state) {
|
||||
uint64_t* a = (uint64_t*)state;
|
||||
uint64_t b[5] = {0};
|
||||
uint64_t t = 0;
|
||||
uint8_t x, y;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 24; i++) {
|
||||
// Theta
|
||||
FOR5(x, 1,
|
||||
b[x] = 0;
|
||||
FOR5(y, 5,
|
||||
b[x] ^= a[x + y]; ))
|
||||
FOR5(x, 1,
|
||||
FOR5(y, 5,
|
||||
a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); ))
|
||||
// Rho and pi
|
||||
t = a[1];
|
||||
x = 0;
|
||||
REPEAT24(b[0] = a[pi[x]];
|
||||
a[pi[x]] = rol(t, rho[x]);
|
||||
t = b[0];
|
||||
x++; )
|
||||
// Chi
|
||||
FOR5(y,
|
||||
5,
|
||||
FOR5(x, 1,
|
||||
b[x] = a[y + x];)
|
||||
FOR5(x, 1,
|
||||
a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); ))
|
||||
// Iota
|
||||
a[0] ^= RC[i];
|
||||
}
|
||||
}
|
||||
|
||||
/******** The FIPS202-defined functions. ********/
|
||||
|
||||
/*** Some helper macros. ***/
|
||||
|
||||
#define _(S) do { S } while (0)
|
||||
#define FOR(i, ST, L, S) \
|
||||
_({size_t i; for (i = 0; i < L; i += ST) { S; }})
|
||||
#define mkapply_ds(NAME, S) \
|
||||
static inline void NAME(uint8_t* dst, \
|
||||
const uint8_t* src, \
|
||||
size_t len) { \
|
||||
FOR(i, 1, len, S); \
|
||||
}
|
||||
#define mkapply_sd(NAME, S) \
|
||||
static inline void NAME(const uint8_t* src, \
|
||||
uint8_t* dst, \
|
||||
size_t len) { \
|
||||
FOR(i, 1, len, S); \
|
||||
}
|
||||
|
||||
mkapply_ds(xorin, dst[i] ^= src[i]) // xorin
|
||||
mkapply_sd(setout, dst[i] = src[i]) // setout
|
||||
|
||||
#define P keccakf
|
||||
#define Plen 200
|
||||
|
||||
// Fold P*F over the full blocks of an input.
|
||||
#define foldP(I, L, F) \
|
||||
while (L >= rate) { \
|
||||
F(a, I, rate); \
|
||||
P(a); \
|
||||
I += rate; \
|
||||
L -= rate; \
|
||||
}
|
||||
|
||||
/** The sponge-based hash construction. **/
|
||||
static inline int hash(uint8_t* out, size_t outlen,
|
||||
const uint8_t* in, size_t inlen,
|
||||
size_t rate, uint8_t delim) {
|
||||
if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) {
|
||||
return -1;
|
||||
}
|
||||
uint8_t a[Plen] = {0};
|
||||
// Absorb input.
|
||||
foldP(in, inlen, xorin);
|
||||
// Xor in the DS and pad frame.
|
||||
a[inlen] ^= delim;
|
||||
a[rate - 1] ^= 0x80;
|
||||
// Xor in the last block.
|
||||
xorin(a, in, inlen);
|
||||
// Apply P
|
||||
P(a);
|
||||
// Squeeze output.
|
||||
foldP(out, outlen, setout);
|
||||
setout(a, out, outlen);
|
||||
memset(a, 0, 200);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Helper macros to define SHA3 and SHAKE instances. ***/
|
||||
#define defshake(bits) \
|
||||
int shake##bits(uint8_t* out, size_t outlen, \
|
||||
const uint8_t* in, size_t inlen) { \
|
||||
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x1f); \
|
||||
}
|
||||
#define defkeccak(bits) \
|
||||
int keccak_##bits(uint8_t* out, size_t outlen, \
|
||||
const uint8_t* in, size_t inlen) { \
|
||||
if (outlen > (bits/8)) { \
|
||||
return -1; \
|
||||
} \
|
||||
return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \
|
||||
}
|
||||
|
||||
/*** FIPS202 SHAKE VOFs ***/
|
||||
defshake(128)
|
||||
defshake(256)
|
||||
|
||||
/*** FIPS202 SHA3 FOFs ***/
|
||||
defkeccak(224)
|
||||
defkeccak(256)
|
||||
defkeccak(384)
|
||||
defkeccak(512)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user