Skip to content

Commit 6adbaba

Browse files
committed
no_std md6 implementation
1 parent 1d959af commit 6adbaba

11 files changed

+781
-591
lines changed

Cargo.lock

+9
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ members = [
1212
"md2",
1313
"md4",
1414
"md5",
15+
"md6",
1516
"ripemd",
1617
"sha1",
1718
"sha1-checked",

md6/.gitignore

-1
This file was deleted.

md6/Cargo.toml

+27
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,33 @@
11
[package]
22
name = "md6"
33
version = "0.1.0"
4+
description = "MD6 hash function"
5+
authors = ["RustCrypto Developers"]
6+
license = "MIT OR Apache-2.0"
7+
readme = "README.md"
48
edition = "2021"
9+
repository = "https://github.com/RustCrypto/hashes"
10+
keywords = ["crypto", "md5", "hash", "digest"]
11+
categories = ["cryptography", "no-std"]
12+
rust-version = "1.81"
13+
14+
[lib]
15+
name = "md6"
516

617
[dependencies]
18+
digest = "=0.11.0-pre.9"
19+
20+
[dev-dependencies]
21+
digest = { version = "=0.11.0-pre.9", features = ["dev"] }
22+
hex-literal = "0.4"
23+
base16ct = { version = "0.2", features = ["alloc"] }
24+
25+
[features]
26+
default = ["oid", "std"]
27+
std = ["digest/std"]
28+
oid = ["digest/oid"]
29+
zeroize = ["digest/zeroize"]
30+
31+
[package.metadata.docs.rs]
32+
all-features = true
33+
rustdoc-args = ["--cfg", "docsrs"]

md6/README.md

Whitespace-only changes.

md6/src/compress.rs

+233
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
use crate::consts::*;
2+
3+
const W: usize = MD6_W; // number of bits in a word (64)
4+
const C: usize = MD6_C; // size of compression output in words (16)
5+
const N: usize = MD6_N; // size of compression input block in words (89)
6+
const Q: usize = MD6_Q; // Q words in a compression block (>= 0) (15)
7+
const K: usize = MD6_K; // key words per compression block (>= 0) (8)
8+
const U: usize = MD6_U; // words for unique node ID (0 or 64/w)
9+
const V: usize = MD6_V; // words for control word (0 or 64/w)
10+
const B: usize = MD6_B; // data words per compression block (> 0) (64)
11+
12+
const T0: usize = 17; // index for linear feedback
13+
const T1: usize = 18; // index for first input to first and
14+
const T2: usize = 21; // index for second input to first and
15+
const T3: usize = 31; // index for first input to second and
16+
const T4: usize = 67; // index for second input to second and
17+
const T5: usize = 89; // last tap
18+
19+
macro_rules! call_loop_bodies {
20+
($w: ident, $s: expr, $i: expr) => {
21+
if $w == 64 {
22+
loop_body!(10, 11, 0, $s, $i);
23+
loop_body!(5, 24, 1, $s, $i);
24+
loop_body!(13, 9, 2, $s, $i);
25+
loop_body!(10, 16, 3, $s, $i);
26+
loop_body!(11, 15, 4, $s, $i);
27+
loop_body!(12, 9, 5, $s, $i);
28+
loop_body!(2, 27, 6, $s, $i);
29+
loop_body!(7, 15, 7, $s, $i);
30+
loop_body!(14, 6, 8, $s, $i);
31+
loop_body!(15, 2, 9, $s, $i);
32+
loop_body!(7, 29, 10, $s, $i);
33+
loop_body!(13, 8, 11, $s, $i);
34+
loop_body!(11, 15, 12, $s, $i);
35+
loop_body!(7, 5, 13, $s, $i);
36+
loop_body!(6, 31, 14, $s, $i);
37+
loop_body!(12, 9, 15, $s, $i);
38+
} else if $w == 32 {
39+
loop_body!(5, 4, 0, $s, $i);
40+
loop_body!(3, 7, 1, $s, $i);
41+
loop_body!(6, 7, 2, $s, $i);
42+
loop_body!(5, 9, 3, $s, $i);
43+
loop_body!(4, 13, 4, $s, $i);
44+
loop_body!(6, 8, 5, $s, $i);
45+
loop_body!(7, 4, 6, $s, $i);
46+
loop_body!(3, 14, 7, $s, $i);
47+
loop_body!(5, 7, 8, $s, $i);
48+
loop_body!(6, 4, 9, $s, $i);
49+
loop_body!(5, 8, 10, $s, $i);
50+
loop_body!(5, 11, 11, $s, $i);
51+
loop_body!(4, 5, 12, $s, $i);
52+
loop_body!(6, 8, 13, $s, $i);
53+
loop_body!(7, 2, 14, $s, $i);
54+
loop_body!(5, 11, 15, $s, $i);
55+
} else if $w == 16 {
56+
loop_body!(5, 6, 0, $s, $i);
57+
loop_body!(4, 7, 1, $s, $i);
58+
loop_body!(3, 2, 2, $s, $i);
59+
loop_body!(5, 4, 3, $s, $i);
60+
loop_body!(7, 2, 4, $s, $i);
61+
loop_body!(5, 6, 5, $s, $i);
62+
loop_body!(5, 3, 6, $s, $i);
63+
loop_body!(2, 7, 7, $s, $i);
64+
loop_body!(4, 5, 8, $s, $i);
65+
loop_body!(3, 7, 9, $s, $i);
66+
loop_body!(4, 6, 10, $s, $i);
67+
loop_body!(3, 5, 11, $s, $i);
68+
loop_body!(4, 5, 12, $s, $i);
69+
loop_body!(7, 6, 13, $s, $i);
70+
loop_body!(7, 4, 14, $s, $i);
71+
loop_body!(2, 3, 15, $s, $i);
72+
} else if $w == 8 {
73+
loop_body!(3, 2, 0, $s, $i);
74+
loop_body!(3, 4, 1, $s, $i);
75+
loop_body!(3, 2, 2, $s, $i);
76+
loop_body!(4, 3, 3, $s, $i);
77+
loop_body!(3, 2, 4, $s, $i);
78+
loop_body!(3, 2, 5, $s, $i);
79+
loop_body!(3, 2, 6, $s, $i);
80+
loop_body!(3, 4, 7, $s, $i);
81+
loop_body!(2, 3, 8, $s, $i);
82+
loop_body!(2, 3, 9, $s, $i);
83+
loop_body!(3, 2, 10, $s, $i);
84+
loop_body!(2, 3, 11, $s, $i);
85+
loop_body!(2, 3, 12, $s, $i);
86+
loop_body!(3, 4, 13, $s, $i);
87+
loop_body!(2, 3, 14, $s, $i);
88+
loop_body!(3, 4, 15, $s, $i);
89+
}
90+
};
91+
}
92+
93+
fn get_s_constants(ws: usize) -> (Md6Word, Md6Word) {
94+
match ws {
95+
64 => (0x0123456789abcdef, 0x7311c2812425cfa0),
96+
32 => (0x01234567, 0x7311c281),
97+
16 => (0x01234, 0x7311),
98+
8 => (0x01, 0x73),
99+
_ => panic!("bad w"),
100+
}
101+
}
102+
103+
fn main_compression_loop(a: &mut [Md6Word], r: usize) {
104+
macro_rules! loop_body {
105+
($rs: expr, $ls: expr, $step: expr, $s: expr, $i: expr) => {
106+
let mut x = $s; // feedback constant
107+
x ^= a[$i + $step - T5]; // end-around feedback
108+
x ^= a[$i + $step - T0]; // linear feedback
109+
x ^= (a[$i + $step - T1] & a[$i + $step - T2]); // first quadratic term
110+
x ^= (a[$i + $step - T3] & a[$i + $step - T4]); // second quadratic term
111+
x ^= x >> $rs; // right shift
112+
a[$i + $step] = x ^ (x << $ls); // left shift
113+
};
114+
}
115+
116+
// Get the initial values for `s` and `smask` based on the width `w`.
117+
let (mut s, smask) = get_s_constants(W);
118+
119+
let mut i = N;
120+
let mut j = 0;
121+
122+
while j < r * C {
123+
// Call the loop bodies based on the value of `w`.
124+
// This will perform the main computation for each step in the compression loop.
125+
call_loop_bodies!(W, s, i);
126+
127+
// Advance round constant s to the next round constant.
128+
s = (s << 1) ^ (s >> (W - 1)) ^ (s & smask);
129+
i += 16;
130+
j += C;
131+
}
132+
}
133+
134+
pub fn compress(c: &mut [Md6Word], n: &mut [Md6Word], r: usize, a: &mut [Md6Word]) {
135+
// check that the input is sensible
136+
assert!(!n.is_empty());
137+
assert!(!n.is_empty());
138+
assert!(r <= MD6_MAX_R);
139+
assert!(!a.is_empty());
140+
141+
a[..n.len()].copy_from_slice(n); // copy n to front of a
142+
143+
main_compression_loop(a, r); // do the main computation
144+
145+
c.copy_from_slice(&a[((r - 1) * C + N)..((r - 1) * C + N + C)]); // output into c
146+
}
147+
148+
fn make_control_word(
149+
r: usize,
150+
l: usize,
151+
z: usize,
152+
p: usize,
153+
keylen: usize,
154+
d: usize,
155+
) -> Md6ControlWord {
156+
(0 as Md6ControlWord) << 60 // reserved width 4 bits
157+
| (r as Md6ControlWord) << 48 // r width 12 bits
158+
| (l as Md6ControlWord) << 40 // L width 8 bits
159+
| (z as Md6ControlWord) << 36 // z width 4 bits
160+
| (p as Md6ControlWord) << 20 // p width 16 bits
161+
| (keylen as Md6ControlWord) << 12 // keylen width 8 bits
162+
| (d as Md6ControlWord) // d width 12 bits
163+
}
164+
165+
pub fn make_node_id(ell: usize, i: Md6Word) -> Md6NodeID {
166+
(ell as Md6NodeID) << 56 | i // ell width 8 bits, i width 56 bits
167+
}
168+
169+
pub fn pack(
170+
n: &mut [Md6Word],
171+
q: &[Md6Word],
172+
k: [Md6Word; K],
173+
ell: usize,
174+
i: Md6Word,
175+
r: usize,
176+
l: usize,
177+
z: usize,
178+
p: usize,
179+
keylen: usize,
180+
d: usize,
181+
b: [Md6Word; 64],
182+
) {
183+
let mut ni = 0;
184+
185+
n[ni..ni + Q].copy_from_slice(&q[..Q]); // q: q in words 0--14
186+
ni += Q;
187+
188+
n[ni..ni + K].copy_from_slice(&k[..K]); // k: key in words 15--22
189+
ni += K;
190+
191+
let u = make_node_id(ell, i); // u: unique node ID in 23
192+
n[ni] = u;
193+
ni += U;
194+
195+
let v = make_control_word(r, l, z, p, keylen, d); // v: control word in 24
196+
n[ni] = v;
197+
ni += V;
198+
199+
n[ni..ni + B].copy_from_slice(&b[..B]); // b: data words 25--88
200+
}
201+
202+
pub fn standard_compress(
203+
c: &mut [Md6Word],
204+
q: &[Md6Word],
205+
k: [Md6Word; K],
206+
ell: usize,
207+
i: Md6Word,
208+
r: usize,
209+
l: usize,
210+
z: usize,
211+
p: usize,
212+
keylen: usize,
213+
d: usize,
214+
b: [Md6Word; 64],
215+
) {
216+
let mut n = [0; MD6_N];
217+
let mut a = [0; 5000];
218+
219+
// check that the input values are sensible
220+
assert!(!c.is_empty());
221+
assert!(!q.is_empty());
222+
assert!(!b.is_empty());
223+
assert!(r <= MD6_MAX_R);
224+
assert!(l <= 255);
225+
assert!(ell <= 255);
226+
assert!(p <= B * W);
227+
assert!(d <= C * W / 2);
228+
assert!(!k.is_empty());
229+
230+
pack(&mut n, q, k, ell, i, r, l, z, p, keylen, d, b); // pack input data into N
231+
232+
compress(c, &mut n, r, &mut a); // compress
233+
}

md6/src/consts.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/// MD6 constants related to standard mode of operation
2+
3+
pub(crate) type Md6Word = u64;
4+
pub(crate) type Md6ControlWord = u64;
5+
pub(crate) type Md6NodeID = u64;
6+
7+
pub(crate) const MD6_MAX_STACK_HEIGHT: usize = 29; // maximum stack height
8+
pub(crate) const MD6_MAX_R: usize = 255; // maximum number of rounds
9+
pub(crate) const MD6_DEFAULT_L: usize = 64; // large so that MD6 is fully hierarchical
10+
11+
pub(crate) const MD6_W: usize = 64; // number of bits in a word
12+
pub(crate) const MD6_C: usize = 16; // size of compression output in words
13+
pub(crate) const MD6_N: usize = 89; // size of compression input block in words
14+
15+
/// These five values give lengths of the components of compression
16+
/// input block; they should sum to MD6_N.
17+
pub(crate) const MD6_Q: usize = 15; // Q words in a compression block (>= 0)
18+
pub(crate) const MD6_K: usize = 8; // key words per compression block (>= 0)
19+
pub(crate) const MD6_U: usize = 64 / MD6_W; // words for unique node ID (0 or 64/w)
20+
pub(crate) const MD6_V: usize = 64 / MD6_W; // words for control word (0 or 64/w)
21+
pub(crate) const MD6_B: usize = 64; // data words per compression block (> 0)

md6/src/lib.rs

+34-9
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,38 @@
1-
// Adapted from the original C code: https://github.com/brbsh/samp-plugin-md6
1+
#![no_std]
2+
#![doc = include_str!("../README.md")]
3+
#![doc(
4+
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5+
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6+
)]
7+
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
8+
#![warn(missing_docs, rust_2018_idioms)]
29

10+
mod compress;
11+
pub(crate) mod consts;
12+
mod md6;
313

4-
#![allow(non_snake_case)]
5-
#![allow(non_upper_case_globals)]
6-
#![allow(non_camel_case_types)]
14+
use digest::{
15+
consts::{U16, U28, U32, U48, U64, U8},
16+
core_api::{CoreWrapper, CtVariableCoreWrapper, RtVariableCoreWrapper},
17+
};
718

8-
mod md6;
9-
mod md6_compress;
10-
mod md6_consts;
19+
pub use digest::{Digest, Update, VariableOutput};
20+
21+
use crate::md6::Md6VarCore;
1122

12-
pub use md6::*;
13-
pub use md6_compress::*;
23+
/// Md6 which allows variable output size at runtime
24+
pub type Md6Var = RtVariableCoreWrapper<Md6VarCore>;
25+
/// Core hash function for Md6 generic over output size
26+
pub type Md6Core<OutSize> = CtVariableCoreWrapper<Md6VarCore, OutSize>;
27+
/// Md6 with 64-bit output
28+
pub type Md6_64 = CoreWrapper<Md6Core<U8>>;
29+
/// Md6 with 128-bit output
30+
pub type Md6_128 = CoreWrapper<Md6Core<U16>>;
31+
/// Md6 with 224-bit output
32+
pub type Md6_224 = CoreWrapper<Md6Core<U28>>;
33+
/// Md6 with 256-bit output
34+
pub type Md6_256 = CoreWrapper<Md6Core<U32>>;
35+
/// Md6 with 384-bit output
36+
pub type Md6_384 = CoreWrapper<Md6Core<U48>>;
37+
/// Md6 with 512-bit output
38+
pub type Md6_512 = CoreWrapper<Md6Core<U64>>;

0 commit comments

Comments
 (0)