Skip to content

Commit 0c3245d

Browse files
add cube hash implementation
This is a port of the Bernstein's "simple" C implementation. https://github.com/floodyberry/supercop/blob/master/crypto_hash/cubehash1632/simple/cubehash.c
1 parent dd2a8a9 commit 0c3245d

File tree

5 files changed

+151
-0
lines changed

5 files changed

+151
-0
lines changed

Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[workspace]
22
members = [
33
"src/certified_map",
4+
"src/cubehash",
45
"src/hashtree",
56
"src/idp_service",
67
]

src/cubehash/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "cubehash"
3+
version = "0.1.0"
4+
edition = "2018"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dev-dependencies]
9+
hex = "0.4"

src/cubehash/src/lib.rs

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
//! This module is a port of Bernstein's CubeHash1632 "simple"
2+
//! implementation in C:
3+
//! https://github.com/floodyberry/supercop/blob/master/crypto_hash/cubehash1632/simple/cubehash.c
4+
use std::num::Wrapping;
5+
6+
const CUBEHASH_INITIAL_ROUNDS: u16 = 10;
7+
const CUBEHASH_FINAL_ROUNDS: u16 = 10;
8+
const CUBEHASH_ROUNDS: u16 = 16;
9+
const CUBEHASH_BLOCKBYTES: u16 = 32;
10+
11+
// CubeHash 10+16/10+32-512
12+
13+
#[inline]
14+
fn rotate(a: Wrapping<u32>, b: usize) -> Wrapping<u32> {
15+
(a << b) | (a >> (32 - b))
16+
}
17+
18+
fn transform(state: &mut [Wrapping<u32>; 32]) {
19+
let mut y: [Wrapping<u32>; 16] = [Wrapping(0); 16];
20+
21+
for _round in 0..CUBEHASH_ROUNDS {
22+
for i in 0..16 {
23+
state[i + 16] += state[i];
24+
}
25+
for i in 0..16 {
26+
y[i ^ 8] = state[i];
27+
}
28+
for i in 0..16 {
29+
state[i] = rotate(y[i], 7);
30+
}
31+
for i in 0..16 {
32+
state[i] ^= state[i + 16];
33+
}
34+
for i in 0..16 {
35+
y[i ^ 2] = state[i + 16];
36+
}
37+
for i in 0..16 {
38+
state[i + 16] = y[i];
39+
}
40+
for i in 0..16 {
41+
state[i + 16] += state[i];
42+
}
43+
for i in 0..16 {
44+
y[i ^ 4] = state[i];
45+
}
46+
for i in 0..16 {
47+
state[i] = rotate(y[i], 11);
48+
}
49+
for i in 0..16 {
50+
state[i] ^= state[i + 16];
51+
}
52+
for i in 0..16 {
53+
y[i ^ 1] = state[i + 16];
54+
}
55+
for i in 0..16 {
56+
state[i + 16] = y[i];
57+
}
58+
}
59+
}
60+
61+
pub struct CubeHash {
62+
state: [Wrapping<u32>; 32],
63+
hash_bytes: u16,
64+
pos: u16,
65+
}
66+
67+
impl CubeHash {
68+
/// Constructs a new CubeHash state that produces a hash of the
69+
/// specified length.
70+
///
71+
/// Panics if hash_bytes > 64
72+
pub fn new(hash_bytes: u16) -> Self {
73+
assert!(hash_bytes <= 64);
74+
75+
let mut state = [Wrapping(0); 32];
76+
state[0] = Wrapping(hash_bytes as u32);
77+
state[1] = Wrapping(CUBEHASH_BLOCKBYTES as u32);
78+
state[2] = Wrapping(CUBEHASH_ROUNDS as u32);
79+
80+
for _i in 0..CUBEHASH_INITIAL_ROUNDS {
81+
transform(&mut state);
82+
}
83+
84+
Self {
85+
state,
86+
hash_bytes,
87+
pos: 0,
88+
}
89+
}
90+
91+
pub fn update(&mut self, data: &[u8]) {
92+
for b in data.iter() {
93+
let u = Wrapping(*b as u32) << (8 * (self.pos % 4) as usize);
94+
self.state[(self.pos / 4) as usize] ^= u;
95+
self.pos += 1;
96+
if self.pos == CUBEHASH_BLOCKBYTES {
97+
transform(&mut self.state);
98+
self.pos = 0;
99+
}
100+
}
101+
}
102+
103+
pub fn finalize(mut self) -> Vec<u8> {
104+
let mut buf = vec![0; self.hash_bytes as usize];
105+
106+
let u = Wrapping(128u32) << (8 * (self.pos % 4) as usize);
107+
self.state[(self.pos / 4) as usize] ^= u;
108+
transform(&mut self.state);
109+
self.state[31] ^= Wrapping(1);
110+
for _ in 0..CUBEHASH_FINAL_ROUNDS {
111+
transform(&mut self.state);
112+
}
113+
for i in 0..self.hash_bytes as usize {
114+
buf[i] = (self.state[i / 4] >> (8 * (i % 4))).0 as u8;
115+
}
116+
buf
117+
}
118+
}
119+
120+
#[cfg(test)]
121+
mod test;

src/cubehash/src/test.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use super::*;
2+
3+
fn hash64(data: &[u8]) -> String {
4+
let mut h = CubeHash::new(64);
5+
h.update(data);
6+
hex::encode(&h.finalize())
7+
}
8+
9+
#[test]
10+
fn test_hello() {
11+
assert_eq!(hash64(b"hello"), "f7acd519f51a6caa5387ae730ed999c4c31766d8477e4e1eef4275e9df07dc4c08adc4b64c9dc8359d711020f78627a4d1bcfecadd28a5263c05faf75e96555a".to_string());
12+
assert_eq!(hash64(b"Hello"), "dcc0503aae279a3c8c95fa1181d37c418783204e2e3048a081392fd61bace883a1f7c4c96b16b4060c42104f1ce45a622f1a9abaeb994beb107fed53a78f588c".to_string());
13+
}

0 commit comments

Comments
 (0)