Skip to content

Commit bb8cfde

Browse files
Rust wrapper: add blake2_digest module
1 parent 9cb17a9 commit bb8cfde

3 files changed

Lines changed: 297 additions & 0 deletions

File tree

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright (C) 2006-2026 wolfSSL Inc.
3+
*
4+
* This file is part of wolfSSL.
5+
*
6+
* wolfSSL is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfSSL is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
19+
*/
20+
21+
/*!
22+
RustCrypto `digest` trait implementations for the wolfCrypt BLAKE2 hash
23+
types.
24+
25+
Because BLAKE2b and BLAKE2s have variable digest sizes, this module exposes
26+
typed wrappers that pin the digest size of an underlying [`crate::blake2`]
27+
instance to a specific value, matching the typed aliases provided by the
28+
RustCrypto `blake2` crate (`Blake2b512`, `Blake2b256`, `Blake2s256`, etc.).
29+
30+
Each typed wrapper implements the traits from the `digest` crate
31+
(`HashMarker`, `OutputSizeUser`, `BlockSizeUser`, `Update`, `Reset`,
32+
`FixedOutput`, and `FixedOutputReset`). With these implementations the
33+
`digest::Digest` trait becomes available via its blanket implementation,
34+
allowing these hashers to be used anywhere a RustCrypto `Digest` is
35+
accepted.
36+
37+
Any failure returned by the underlying wolfCrypt call in a trait method
38+
will result in a panic, matching the infallible signatures required by the
39+
RustCrypto traits.
40+
*/
41+
42+
use digest::consts::{U16, U24, U32, U48, U64, U128};
43+
44+
macro_rules! impl_blake2_digest {
45+
(
46+
$(#[$attr:meta])*
47+
$name:ident,
48+
wc_ty = $wc_ty:path,
49+
digest_size = $digest_size:literal,
50+
out = $out_size:ty,
51+
block = $block_size:ty
52+
) => {
53+
$(#[$attr])*
54+
pub struct $name {
55+
blake2: $wc_ty,
56+
}
57+
58+
$(#[$attr])*
59+
impl Default for $name {
60+
fn default() -> Self {
61+
Self {
62+
blake2: <$wc_ty>::new($digest_size)
63+
.expect("wolfCrypt BLAKE2 init failed"),
64+
}
65+
}
66+
}
67+
68+
$(#[$attr])*
69+
impl digest::HashMarker for $name {}
70+
71+
$(#[$attr])*
72+
impl digest::OutputSizeUser for $name {
73+
type OutputSize = $out_size;
74+
}
75+
76+
$(#[$attr])*
77+
impl digest::block_api::BlockSizeUser for $name {
78+
type BlockSize = $block_size;
79+
}
80+
81+
$(#[$attr])*
82+
impl digest::Update for $name {
83+
fn update(&mut self, data: &[u8]) {
84+
<$wc_ty>::update(&mut self.blake2, data)
85+
.expect("wolfCrypt BLAKE2 update failed");
86+
}
87+
}
88+
89+
$(#[$attr])*
90+
impl digest::Reset for $name {
91+
fn reset(&mut self) {
92+
self.blake2 = <$wc_ty>::new($digest_size)
93+
.expect("wolfCrypt BLAKE2 init failed");
94+
}
95+
}
96+
97+
$(#[$attr])*
98+
impl digest::FixedOutput for $name {
99+
fn finalize_into(mut self, out: &mut digest::Output<Self>) {
100+
<$wc_ty>::finalize(&mut self.blake2, out.as_mut_slice())
101+
.expect("wolfCrypt BLAKE2 finalize failed");
102+
}
103+
}
104+
105+
$(#[$attr])*
106+
impl digest::FixedOutputReset for $name {
107+
fn finalize_into_reset(&mut self, out: &mut digest::Output<Self>) {
108+
<$wc_ty>::finalize(&mut self.blake2, out.as_mut_slice())
109+
.expect("wolfCrypt BLAKE2 finalize failed");
110+
self.blake2 = <$wc_ty>::new($digest_size)
111+
.expect("wolfCrypt BLAKE2 init failed");
112+
}
113+
}
114+
};
115+
}
116+
117+
impl_blake2_digest! {
118+
#[cfg(blake2b)]
119+
Blake2b256,
120+
wc_ty = crate::blake2::BLAKE2b,
121+
digest_size = 32,
122+
out = U32,
123+
block = U128
124+
}
125+
126+
impl_blake2_digest! {
127+
#[cfg(blake2b)]
128+
Blake2b384,
129+
wc_ty = crate::blake2::BLAKE2b,
130+
digest_size = 48,
131+
out = U48,
132+
block = U128
133+
}
134+
135+
impl_blake2_digest! {
136+
#[cfg(blake2b)]
137+
Blake2b512,
138+
wc_ty = crate::blake2::BLAKE2b,
139+
digest_size = 64,
140+
out = U64,
141+
block = U128
142+
}
143+
144+
impl_blake2_digest! {
145+
#[cfg(blake2s)]
146+
Blake2s128,
147+
wc_ty = crate::blake2::BLAKE2s,
148+
digest_size = 16,
149+
out = U16,
150+
block = U64
151+
}
152+
153+
impl_blake2_digest! {
154+
#[cfg(blake2s)]
155+
Blake2s192,
156+
wc_ty = crate::blake2::BLAKE2s,
157+
digest_size = 24,
158+
out = U24,
159+
block = U64
160+
}
161+
162+
impl_blake2_digest! {
163+
#[cfg(blake2s)]
164+
Blake2s256,
165+
wc_ty = crate::blake2::BLAKE2s,
166+
digest_size = 32,
167+
out = U32,
168+
block = U64
169+
}

wrapper/rust/wolfssl-wolfcrypt/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ pub(crate) unsafe fn zeroize_raw<T>(val: &mut T) {
4545

4646
pub mod aes;
4747
pub mod blake2;
48+
#[cfg(all(any(blake2b, blake2s), feature = "digest"))]
49+
pub mod blake2_digest;
4850
#[cfg(all(any(blake2b, blake2s), feature = "mac"))]
4951
pub mod blake2_mac;
5052
pub mod chacha20_poly1305;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#![cfg(all(any(blake2b, blake2s), feature = "digest"))]
2+
3+
use digest::{Digest, FixedOutputReset};
4+
use digest::block_api::BlockSizeUser;
5+
6+
mod common;
7+
8+
fn check_digest<D: Digest + BlockSizeUser + FixedOutputReset + Default>(
9+
input: &[u8],
10+
expected: &[u8],
11+
expected_block_size: usize,
12+
) {
13+
assert_eq!(<D as Digest>::output_size(), expected.len());
14+
assert_eq!(<D as BlockSizeUser>::block_size(), expected_block_size);
15+
16+
/* One-shot digest via associated function. */
17+
let out = D::digest(input);
18+
assert_eq!(out.as_slice(), expected);
19+
20+
/* Streaming via Digest::update and finalize. */
21+
let mut hasher = D::new();
22+
Digest::update(&mut hasher, input);
23+
let out = hasher.finalize();
24+
assert_eq!(out.as_slice(), expected);
25+
26+
/* Split update via Default + Update + FixedOutputReset::finalize_reset. */
27+
let mut hasher = D::default();
28+
if input.len() >= 2 {
29+
let mid = input.len() / 2;
30+
Digest::update(&mut hasher, &input[..mid]);
31+
Digest::update(&mut hasher, &input[mid..]);
32+
} else {
33+
Digest::update(&mut hasher, input);
34+
}
35+
let out = hasher.finalize_reset();
36+
assert_eq!(out.as_slice(), expected);
37+
38+
/* After reset, the same hasher should produce the same result. */
39+
Digest::update(&mut hasher, input);
40+
let out = hasher.finalize();
41+
assert_eq!(out.as_slice(), expected);
42+
}
43+
44+
#[test]
45+
#[cfg(blake2b)]
46+
fn test_digest_blake2b_512() {
47+
use wolfssl_wolfcrypt::blake2_digest::Blake2b512;
48+
common::setup();
49+
check_digest::<Blake2b512>(
50+
b"abc",
51+
b"\xBA\x80\xA5\x3F\x98\x1C\x4D\x0D\x6A\x27\x97\xB6\x9F\x12\xF6\xE9\x4C\x21\x2F\x14\x68\x5A\xC4\xB7\x4B\x12\xBB\x6F\xDB\xFF\xA2\xD1\x7D\x87\xC5\x39\x2A\xAB\x79\x2D\xC2\x52\xD5\xDE\x45\x33\xCC\x95\x18\xD3\x8A\xA8\xDB\xF1\x92\x5A\xB9\x23\x86\xED\xD4\x00\x99\x23",
52+
128,
53+
);
54+
}
55+
56+
#[test]
57+
#[cfg(blake2b)]
58+
fn test_digest_blake2b_384() {
59+
use wolfssl_wolfcrypt::blake2::BLAKE2b;
60+
use wolfssl_wolfcrypt::blake2_digest::Blake2b384;
61+
common::setup();
62+
63+
let mut reference = BLAKE2b::new(48).expect("Error with new()");
64+
reference.update(b"abc").expect("Error with update()");
65+
let mut expected = [0u8; 48];
66+
reference.finalize(&mut expected).expect("Error with finalize()");
67+
68+
check_digest::<Blake2b384>(b"abc", &expected, 128);
69+
}
70+
71+
#[test]
72+
#[cfg(blake2b)]
73+
fn test_digest_blake2b_256() {
74+
use wolfssl_wolfcrypt::blake2::BLAKE2b;
75+
use wolfssl_wolfcrypt::blake2_digest::Blake2b256;
76+
common::setup();
77+
78+
let mut reference = BLAKE2b::new(32).expect("Error with new()");
79+
reference.update(b"abc").expect("Error with update()");
80+
let mut expected = [0u8; 32];
81+
reference.finalize(&mut expected).expect("Error with finalize()");
82+
83+
check_digest::<Blake2b256>(b"abc", &expected, 128);
84+
}
85+
86+
#[test]
87+
#[cfg(blake2s)]
88+
fn test_digest_blake2s_256() {
89+
use wolfssl_wolfcrypt::blake2_digest::Blake2s256;
90+
common::setup();
91+
check_digest::<Blake2s256>(
92+
b"abc",
93+
b"\x50\x8C\x5E\x8C\x32\x7C\x14\xE2\xE1\xA7\x2B\xA3\x4E\xEB\x45\x2F\x37\x45\x8B\x20\x9E\xD6\x3A\x29\x4D\x99\x9B\x4C\x86\x67\x59\x82",
94+
64,
95+
);
96+
}
97+
98+
#[test]
99+
#[cfg(blake2s)]
100+
fn test_digest_blake2s_192() {
101+
use wolfssl_wolfcrypt::blake2::BLAKE2s;
102+
use wolfssl_wolfcrypt::blake2_digest::Blake2s192;
103+
common::setup();
104+
105+
let mut reference = BLAKE2s::new(24).expect("Error with new()");
106+
reference.update(b"abc").expect("Error with update()");
107+
let mut expected = [0u8; 24];
108+
reference.finalize(&mut expected).expect("Error with finalize()");
109+
110+
check_digest::<Blake2s192>(b"abc", &expected, 64);
111+
}
112+
113+
#[test]
114+
#[cfg(blake2s)]
115+
fn test_digest_blake2s_128() {
116+
use wolfssl_wolfcrypt::blake2::BLAKE2s;
117+
use wolfssl_wolfcrypt::blake2_digest::Blake2s128;
118+
common::setup();
119+
120+
let mut reference = BLAKE2s::new(16).expect("Error with new()");
121+
reference.update(b"abc").expect("Error with update()");
122+
let mut expected = [0u8; 16];
123+
reference.finalize(&mut expected).expect("Error with finalize()");
124+
125+
check_digest::<Blake2s128>(b"abc", &expected, 64);
126+
}

0 commit comments

Comments
 (0)