Skip to content
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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ members = [
"md2",
"md4",
"md5",
"md6",
"ripemd",
"sha1",
"sha1-checked",
Expand Down
26 changes: 26 additions & 0 deletions md6/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[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"

[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"]
83 changes: 83 additions & 0 deletions md6/README.md
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.
54 changes: 54 additions & 0 deletions md6/benches/mod.rs
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;
);
178 changes: 178 additions & 0 deletions md6/src/compress.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
use crate::consts::*;

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
}
Loading
Loading