-
Notifications
You must be signed in to change notification settings - Fork 258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implementation of md6 in pure rust #636
base: master
Are you sure you want to change the base?
Changes from 7 commits
1d959af
6adbaba
9b0923b
d623751
c88621c
42edfa8
332fb95
d7939a7
5096398
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,6 +12,7 @@ members = [ | |
"md2", | ||
"md4", | ||
"md5", | ||
"md6", | ||
"ripemd", | ||
"sha1", | ||
"sha1-checked", | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[package] | ||
name = "md6" | ||
version = "0.1.0" | ||
description = "MD6 hash function" | ||
authors = ["RustCrypto Developers"] | ||
license = "MIT OR Apache-2.0" | ||
readme = "README.md" | ||
edition = "2021" | ||
repository = "https://github.com/RustCrypto/hashes" | ||
keywords = ["crypto", "md6", "hash", "digest"] | ||
categories = ["cryptography", "no-std"] | ||
rust-version = "1.81" | ||
|
||
[lib] | ||
name = "md6" | ||
|
||
[dependencies] | ||
digest = "=0.11.0-pre.9" | ||
|
||
[dev-dependencies] | ||
digest = { version = "=0.11.0-pre.9", features = ["dev"] } | ||
hex-literal = "0.4" | ||
base16ct = { version = "0.2", features = ["alloc"] } | ||
|
||
[features] | ||
default = ["oid", "std"] | ||
std = ["digest/std"] | ||
oid = ["digest/oid"] | ||
zeroize = ["digest/zeroize"] | ||
|
||
[package.metadata.docs.rs] | ||
all-features = true | ||
rustdoc-args = ["--cfg", "docsrs"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# RustCrypto: MD6 | ||
|
||
Pure Rust implementation of the MD6 hash function. | ||
|
||
## Example | ||
|
||
### Fixed output size | ||
|
||
```rust | ||
use md6::Md6_256; | ||
use digest::Digest; | ||
use hex_literal::hex; | ||
|
||
// create a Md6_256 object | ||
let mut hasher = Md6_256::new(); | ||
|
||
// write input message | ||
hasher.update(b"hello world"); | ||
|
||
// read hash digest and consume hasher | ||
let hash = hasher.finalize(); | ||
assert_eq!(hash.to_vec(), hex!( | ||
"9ae602639631cc2c60adaa7a952aae8756141f31a7e6a9b76adc1de121db2230" | ||
)); | ||
``` | ||
|
||
Also, see the [examples section] in the RustCrypto/hashes readme. | ||
|
||
### Variable output size | ||
|
||
This implementation supports run and compile time variable sizes. | ||
|
||
Output size set at run time: | ||
```rust | ||
use md6::Md6Var; | ||
use digest::{Update, VariableOutput}; | ||
use hex_literal::hex; | ||
|
||
let mut hasher = Md6Var::new(12).unwrap(); | ||
hasher.update(b"hello rust"); | ||
let mut buf = [0u8; 12]; | ||
hasher.finalize_variable(&mut buf).unwrap(); | ||
assert_eq!(buf, hex!("9c5b8d9744898ec981bcc573")); | ||
``` | ||
|
||
Output size set at compile time: | ||
```rust | ||
use md6::Md6; | ||
use digest::{Digest, consts::U20}; | ||
use hex_literal::hex; | ||
|
||
type Md6_160 = Md6<U20>; | ||
|
||
let mut hasher = Md6_160::new(); | ||
hasher.update(b"hello rust"); | ||
let res = hasher.finalize(); | ||
assert_eq!(res, hex!("576d736a93a555a1c868973cfdd2d21838a26623")); | ||
``` | ||
|
||
## Minimum Supported Rust Version | ||
|
||
Rust **1.81** or higher. | ||
|
||
Minimum supported Rust version can be changed in the future, but it will be | ||
done with a minor version bump. | ||
|
||
## SemVer Policy | ||
|
||
- All on-by-default features of this library are covered by SemVer | ||
- MSRV is considered exempt from SemVer as noted above | ||
|
||
## License | ||
|
||
The crate is licensed under either of: | ||
|
||
* [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) | ||
* [MIT license](http://opensource.org/licenses/MIT) | ||
|
||
## Contributing | ||
|
||
Unless you explicitly state otherwise, any contribution intentionally submitted | ||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be | ||
dual licensed as above, without any additional terms or conditions. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#![feature(test)] | ||
extern crate test; | ||
|
||
use digest::bench_update; | ||
use md6::{Md6_128, Md6_224, Md6_256, Md6_384, Md6_512, Md6_64}; | ||
use test::Bencher; | ||
|
||
bench_update!( | ||
Md6_64::default(); | ||
md6_64_10 10; | ||
md6_64_100 100; | ||
md6_64_1000 1000; | ||
md6_64_10000 10000; | ||
); | ||
|
||
bench_update!( | ||
Md6_128::default(); | ||
md6_128_10 10; | ||
md6_128_100 100; | ||
md6_128_1000 1000; | ||
md6_128_10000 10000; | ||
); | ||
|
||
bench_update!( | ||
Md6_224::default(); | ||
md6_224_10 10; | ||
md6_224_100 100; | ||
md6_224_1000 1000; | ||
md6_224_10000 10000; | ||
); | ||
|
||
bench_update!( | ||
Md6_256::default(); | ||
md6_256_10 10; | ||
md6_256_100 100; | ||
md6_256_1000 1000; | ||
md6_256_10000 10000; | ||
); | ||
|
||
bench_update!( | ||
Md6_384::default(); | ||
md6_384_10 10; | ||
md6_384_100 100; | ||
md6_384_1000 1000; | ||
md6_384_10000 10000; | ||
); | ||
|
||
bench_update!( | ||
Md6_512::default(); | ||
md6_512_10 10; | ||
md6_512_100 100; | ||
md6_512_1000 1000; | ||
md6_512_10000 10000; | ||
); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
use crate::consts::*; | ||
|
||
const W: usize = MD6_W; // number of bits in a word (64) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can simply rename these constants in the |
||
const C: usize = MD6_C; // size of compression output in words (16) | ||
const N: usize = MD6_N; // size of compression input block in words (89) | ||
const Q: usize = MD6_Q; // Q words in a compression block (>= 0) (15) | ||
const K: usize = MD6_K; // key words per compression block (>= 0) (8) | ||
const U: usize = MD6_U; // words for unique node ID (0 or 64/w) | ||
const V: usize = MD6_V; // words for control word (0 or 64/w) | ||
const B: usize = MD6_B; // data words per compression block (> 0) (64) | ||
|
||
const T0: usize = 17; // index for linear feedback | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's worth to move these constants to the |
||
const T1: usize = 18; // index for first input to first and | ||
const T2: usize = 21; // index for second input to first and | ||
const T3: usize = 31; // index for first input to second and | ||
const T4: usize = 67; // index for second input to second and | ||
const T5: usize = 89; // last tap | ||
|
||
macro_rules! call_loop_bodies { | ||
($w: ident, $s: expr, $i: expr) => { | ||
if $w == 64 { | ||
loop_body!(10, 11, 0, $s, $i); | ||
loop_body!(5, 24, 1, $s, $i); | ||
loop_body!(13, 9, 2, $s, $i); | ||
loop_body!(10, 16, 3, $s, $i); | ||
loop_body!(11, 15, 4, $s, $i); | ||
loop_body!(12, 9, 5, $s, $i); | ||
loop_body!(2, 27, 6, $s, $i); | ||
loop_body!(7, 15, 7, $s, $i); | ||
loop_body!(14, 6, 8, $s, $i); | ||
loop_body!(15, 2, 9, $s, $i); | ||
loop_body!(7, 29, 10, $s, $i); | ||
loop_body!(13, 8, 11, $s, $i); | ||
loop_body!(11, 15, 12, $s, $i); | ||
loop_body!(7, 5, 13, $s, $i); | ||
loop_body!(6, 31, 14, $s, $i); | ||
loop_body!(12, 9, 15, $s, $i); | ||
} else if $w == 32 { | ||
loop_body!(5, 4, 0, $s, $i); | ||
loop_body!(3, 7, 1, $s, $i); | ||
loop_body!(6, 7, 2, $s, $i); | ||
loop_body!(5, 9, 3, $s, $i); | ||
loop_body!(4, 13, 4, $s, $i); | ||
loop_body!(6, 8, 5, $s, $i); | ||
loop_body!(7, 4, 6, $s, $i); | ||
loop_body!(3, 14, 7, $s, $i); | ||
loop_body!(5, 7, 8, $s, $i); | ||
loop_body!(6, 4, 9, $s, $i); | ||
loop_body!(5, 8, 10, $s, $i); | ||
loop_body!(5, 11, 11, $s, $i); | ||
loop_body!(4, 5, 12, $s, $i); | ||
loop_body!(6, 8, 13, $s, $i); | ||
loop_body!(7, 2, 14, $s, $i); | ||
loop_body!(5, 11, 15, $s, $i); | ||
} else if $w == 16 { | ||
loop_body!(5, 6, 0, $s, $i); | ||
loop_body!(4, 7, 1, $s, $i); | ||
loop_body!(3, 2, 2, $s, $i); | ||
loop_body!(5, 4, 3, $s, $i); | ||
loop_body!(7, 2, 4, $s, $i); | ||
loop_body!(5, 6, 5, $s, $i); | ||
loop_body!(5, 3, 6, $s, $i); | ||
loop_body!(2, 7, 7, $s, $i); | ||
loop_body!(4, 5, 8, $s, $i); | ||
loop_body!(3, 7, 9, $s, $i); | ||
loop_body!(4, 6, 10, $s, $i); | ||
loop_body!(3, 5, 11, $s, $i); | ||
loop_body!(4, 5, 12, $s, $i); | ||
loop_body!(7, 6, 13, $s, $i); | ||
loop_body!(7, 4, 14, $s, $i); | ||
loop_body!(2, 3, 15, $s, $i); | ||
} else if $w == 8 { | ||
loop_body!(3, 2, 0, $s, $i); | ||
loop_body!(3, 4, 1, $s, $i); | ||
loop_body!(3, 2, 2, $s, $i); | ||
loop_body!(4, 3, 3, $s, $i); | ||
loop_body!(3, 2, 4, $s, $i); | ||
loop_body!(3, 2, 5, $s, $i); | ||
loop_body!(3, 2, 6, $s, $i); | ||
loop_body!(3, 4, 7, $s, $i); | ||
loop_body!(2, 3, 8, $s, $i); | ||
loop_body!(2, 3, 9, $s, $i); | ||
loop_body!(3, 2, 10, $s, $i); | ||
loop_body!(2, 3, 11, $s, $i); | ||
loop_body!(2, 3, 12, $s, $i); | ||
loop_body!(3, 4, 13, $s, $i); | ||
loop_body!(2, 3, 14, $s, $i); | ||
loop_body!(3, 4, 15, $s, $i); | ||
} | ||
}; | ||
} | ||
|
||
fn get_s_constants(ws: usize) -> (Md6Word, Md6Word) { | ||
match ws { | ||
64 => (0x0123456789abcdef, 0x7311c2812425cfa0), | ||
32 => (0x01234567, 0x7311c281), | ||
16 => (0x01234, 0x7311), | ||
8 => (0x01, 0x73), | ||
_ => panic!("bad w"), | ||
} | ||
} | ||
|
||
fn main_compression_loop(a: &mut [Md6Word], r: usize) { | ||
macro_rules! loop_body { | ||
($rs: expr, $ls: expr, $step: expr, $s: expr, $i: expr) => { | ||
let mut x = $s; // feedback constant | ||
x ^= a[$i + $step - T5]; // end-around feedback | ||
x ^= a[$i + $step - T0]; // linear feedback | ||
x ^= (a[$i + $step - T1] & a[$i + $step - T2]); // first quadratic term | ||
x ^= (a[$i + $step - T3] & a[$i + $step - T4]); // second quadratic term | ||
x ^= x >> $rs; // right shift | ||
a[$i + $step] = x ^ (x << $ls); // left shift | ||
}; | ||
} | ||
|
||
// Get the initial values for `s` and `smask` based on the width `w`. | ||
let (mut s, smask) = get_s_constants(W); | ||
|
||
let mut i = N; | ||
let mut j = 0; | ||
|
||
while j < r * C { | ||
// Call the loop bodies based on the value of `w`. | ||
// This will perform the main computation for each step in the compression loop. | ||
call_loop_bodies!(W, s, i); | ||
|
||
// Advance round constant s to the next round constant. | ||
s = (s << 1) ^ (s >> (W - 1)) ^ (s & smask); | ||
i += 16; | ||
j += C; | ||
} | ||
} | ||
|
||
pub fn compress(c: &mut [Md6Word], n: &mut [Md6Word], r: usize, a: &mut [Md6Word]) { | ||
// check that the input is sensible | ||
assert!(!n.is_empty()); | ||
assert!(!n.is_empty()); | ||
assert!(r <= MD6_MAX_R); | ||
assert!(!a.is_empty()); | ||
|
||
a[..n.len()].copy_from_slice(n); // copy n to front of a | ||
|
||
main_compression_loop(a, r); // do the main computation | ||
|
||
c.copy_from_slice(&a[((r - 1) * C + N)..((r - 1) * C + N + C)]); // output into c | ||
} | ||
|
||
pub fn make_control_word( | ||
r: usize, | ||
l: usize, | ||
z: usize, | ||
p: usize, | ||
keylen: usize, | ||
d: usize, | ||
) -> Md6ControlWord { | ||
(0 as Md6ControlWord) << 60 // reserved width 4 bits | ||
| (r as Md6ControlWord) << 48 // r width 12 bits | ||
| (l as Md6ControlWord) << 40 // L width 8 bits | ||
| (z as Md6ControlWord) << 36 // z width 4 bits | ||
| (p as Md6ControlWord) << 20 // p width 16 bits | ||
| (keylen as Md6ControlWord) << 12 // keylen width 8 bits | ||
| (d as Md6ControlWord) // d width 12 bits | ||
} | ||
|
||
pub fn make_node_id(ell: usize, i: Md6Word) -> Md6NodeID { | ||
(ell as Md6NodeID) << 56 | i // ell width 8 bits, i width 56 bits | ||
} | ||
|
||
pub fn pack( | ||
n: &mut [Md6Word], | ||
q: &[Md6Word], | ||
k: [Md6Word; K], | ||
b: [Md6Word; 64], | ||
u: Md6NodeID, | ||
v: Md6ControlWord, | ||
) { | ||
let mut ni = 0; | ||
|
||
n[ni..ni + Q].copy_from_slice(&q[..Q]); // q: q in words 0--14 | ||
ni += Q; | ||
|
||
n[ni..ni + K].copy_from_slice(&k[..K]); // k: key in words 15--22 | ||
ni += K; | ||
|
||
// u: unique node ID in 23 | ||
n[ni] = u; | ||
ni += U; | ||
|
||
// v: control word in 24 | ||
n[ni] = v; | ||
ni += V; | ||
|
||
n[ni..ni + B].copy_from_slice(&b[..B]); // b: data words 25--88 | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These two lines are not needed.