Skip to content

Commit 718f57e

Browse files
committed
blake2bp/blake2sp
1 parent f50ebb3 commit 718f57e

File tree

11 files changed

+286
-1
lines changed

11 files changed

+286
-1
lines changed

blake2/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "blake2"
3-
version = "0.8.0"
3+
version = "0.8.1"
44
authors = ["RustCrypto Developers"]
55
license = "MIT OR Apache-2.0"
66
description = "BLAKE2 hash functions"

blake2/benches/blake2bp.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![no_std]
2+
#![feature(test)]
3+
#[macro_use]
4+
extern crate digest;
5+
extern crate blake2;
6+
7+
bench!(blake2::Blake2bp);

blake2/benches/blake2sp.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#![no_std]
2+
#![feature(test)]
3+
#[macro_use]
4+
extern crate digest;
5+
extern crate blake2;
6+
7+
bench!(blake2::Blake2sp);

blake2/src/as_bytes.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ unsafe impl Safe for i8 {}
4141
unsafe impl Safe for i16 {}
4242
unsafe impl Safe for i32 {}
4343
unsafe impl Safe for i64 {}
44+
unsafe impl<T: Safe> Safe for [T; 8] {}
45+
unsafe impl<T: Safe> Safe for [T; 16] {}

blake2/src/blake2.rs

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,3 +464,251 @@ macro_rules! blake2_impl {
464464
impl_write!($fix_state);
465465
}
466466
}
467+
468+
macro_rules! blake2_p_impl {
469+
(
470+
$state:ident, $fix_state:ident, $compressor:ident, $builder:ident, $word:ident, $bytes:ident, $fanout:expr,
471+
$vardoc:expr, $doc:expr,
472+
) => {
473+
474+
use $crate::as_bytes::AsBytes;
475+
476+
use digest::{Input, BlockInput, FixedOutput, VariableOutput, Reset};
477+
use digest::InvalidOutputSize;
478+
use digest::generic_array::GenericArray;
479+
use digest::generic_array::typenum::Unsigned;
480+
use core::cmp;
481+
use byte_tools::{copy, zero};
482+
use crypto_mac::{Mac, MacResult, InvalidKeyLength};
483+
484+
type Output = GenericArray<u8, $bytes>;
485+
486+
#[derive(Clone)]
487+
#[doc=$vardoc]
488+
pub struct $state {
489+
n: usize,
490+
m0: [$word; 16],
491+
t0: u64,
492+
h0: $builder,
493+
h: [$compressor; $fanout],
494+
m: [[$word; 16]; $fanout],
495+
t: u64,
496+
}
497+
498+
impl $state {
499+
/// Creates a new hashing context with a key.
500+
///
501+
/// **WARNING!** If you plan to use it for variable output MAC, then
502+
/// make sure to compare codes in constant time! It can be done
503+
/// for example by using `subtle` crate.
504+
pub fn new_keyed(key: &[u8], output_size: usize) -> Self {
505+
let mut h0 = $builder::new();
506+
h0.key(key.len());
507+
h0.out(output_size);
508+
h0.fanout($fanout);
509+
h0.depth(2);
510+
h0.inner_length($bytes::to_u8());
511+
let mut m0 = [0; 16];
512+
let mut t0 = 0;
513+
if !key.is_empty() {
514+
copy(key, m0.as_mut_bytes());
515+
t0 = 2 * $bytes::to_u64() * $fanout;
516+
}
517+
let mut state = $state {
518+
n: output_size,
519+
h0,
520+
t0,
521+
m0,
522+
// everything else set up by reset()
523+
h: Default::default(),
524+
m: Default::default(),
525+
t: Default::default(),
526+
};
527+
state.reset();
528+
state
529+
}
530+
531+
/// Updates the hashing context with more data.
532+
fn update(&mut self, mut data: &[u8]) {
533+
const BLOCK: usize = 2 * $bytes::USIZE;
534+
const RING: usize = BLOCK * $fanout;
535+
536+
if self.t < RING as u64 {
537+
// initial ring fill
538+
let (d0, d1) = data.split_at(cmp::min(data.len(), RING - self.t as usize));
539+
self.m.as_mut_bytes()[self.t as usize..self.t as usize + d0.len()].copy_from_slice(d0);
540+
self.t += d0.len() as u64;
541+
data = d1;
542+
} else if self.t as usize % BLOCK != 0 {
543+
// complete partial block
544+
let (d0, d1) = data.split_at(cmp::min(data.len(), BLOCK - self.t as usize % BLOCK));
545+
let ri = self.t as usize % RING;
546+
self.m.as_mut_bytes()[ri..ri + d0.len()].copy_from_slice(d0);
547+
self.t += d0.len() as u64;
548+
data = d1;
549+
}
550+
551+
// if there's data remaining, the ring is full of whole blocks
552+
for b in data.chunks(BLOCK) {
553+
let i = self.t as usize / BLOCK % $fanout;
554+
self.h[i].compress(&mut self.m[i], 0, 0, self.t / RING as u64 * BLOCK as u64);
555+
self.m[i].as_mut_bytes()[..b.len()].copy_from_slice(b);
556+
self.t += b.len() as u64;
557+
}
558+
}
559+
560+
fn finalize(mut self) -> Output {
561+
const BLOCK: usize = 2 * $bytes::USIZE;
562+
const RING: usize = BLOCK * $fanout;
563+
564+
self.h0.node_offset(0);
565+
self.h0.node_depth(1);
566+
let mut root = self.h0.build();
567+
568+
let mut ri = self.t as usize % RING;
569+
let trb = self.t / RING as u64 * BLOCK as u64;
570+
if ri % BLOCK != 0 {
571+
let ni = ((self.t as usize & !(BLOCK - 1)) + BLOCK) % RING;
572+
zero(&mut self.m.as_mut_bytes()[ri..ni]);
573+
}
574+
let mut inter = [0; 16];
575+
for i in 0..$fanout {
576+
if i != 0 && i & 1 == 0 {
577+
root.compress(&inter, 0, 0, i as u64 * $bytes::to_u64());
578+
}
579+
let len = cmp::min(ri, BLOCK);
580+
ri -= len;
581+
let f1 = if i == $fanout - 1 { !0 } else { 0 };
582+
let ix0 = (i & 1) * $bytes::to_usize();
583+
let ix1 = ((i & 1) + 1) * $bytes::to_usize();
584+
self.h[i].finalize_into_slice(&mut inter.as_mut_bytes()[ix0..ix1], &self.m[i], f1, trb + len as u64);
585+
}
586+
let mut out = GenericArray::default();
587+
root.finalize(&mut out, &inter, !0, $fanout * $bytes::to_u64());
588+
out
589+
}
590+
}
591+
592+
impl Default for $state {
593+
fn default() -> Self { Self::new_keyed(&[], $bytes::to_usize()) }
594+
}
595+
596+
impl BlockInput for $state {
597+
type BlockSize = $bytes;
598+
}
599+
600+
impl Input for $state {
601+
fn input<B: AsRef<[u8]>>(&mut self, data: B) {
602+
self.update(data.as_ref());
603+
}
604+
}
605+
606+
impl VariableOutput for $state {
607+
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
608+
if output_size == 0 || output_size > $bytes::to_usize() {
609+
return Err(InvalidOutputSize);
610+
}
611+
Ok(Self::new_keyed(&[], output_size))
612+
}
613+
614+
fn output_size(&self) -> usize {
615+
self.n
616+
}
617+
618+
fn variable_result<F: FnOnce(&[u8])>(self, f: F) {
619+
let n = self.n;
620+
let res = self.finalize();
621+
f(&res[..n]);
622+
}
623+
}
624+
625+
impl Reset for $state {
626+
fn reset(&mut self) {
627+
self.h0.node_depth(0);
628+
for (i, h) in self.h.iter_mut().enumerate() {
629+
self.h0.node_offset(i);
630+
*h = self.h0.build();
631+
}
632+
633+
for m in self.m.iter_mut() {
634+
m.copy_from_slice(&self.m0);
635+
}
636+
637+
self.t = self.t0;
638+
}
639+
}
640+
641+
impl_opaque_debug!($state);
642+
impl_write!($state);
643+
644+
645+
#[derive(Clone)]
646+
#[doc=$doc]
647+
pub struct $fix_state {
648+
state: $state,
649+
}
650+
651+
impl Default for $fix_state {
652+
fn default() -> Self {
653+
let state = $state::new_keyed(&[], $bytes::to_usize());
654+
Self { state }
655+
}
656+
}
657+
658+
impl BlockInput for $fix_state {
659+
type BlockSize = $bytes;
660+
}
661+
662+
impl Input for $fix_state {
663+
fn input<B: AsRef<[u8]>>(&mut self, data: B) {
664+
self.state.update(data.as_ref());
665+
}
666+
}
667+
668+
impl FixedOutput for $fix_state {
669+
type OutputSize = $bytes;
670+
671+
fn fixed_result(self) -> Output {
672+
self.state.finalize()
673+
}
674+
}
675+
676+
impl Reset for $fix_state {
677+
fn reset(&mut self) {
678+
self.state.reset()
679+
}
680+
}
681+
682+
impl Mac for $fix_state {
683+
type OutputSize = $bytes;
684+
type KeySize = $bytes;
685+
686+
fn new(key: &GenericArray<u8, $bytes>) -> Self {
687+
let state = $state::new_keyed(key, $bytes::to_usize());
688+
Self { state }
689+
}
690+
691+
fn new_varkey(key: &[u8]) -> Result<Self, InvalidKeyLength> {
692+
if key.len() > $bytes::to_usize() {
693+
Err(InvalidKeyLength)
694+
} else {
695+
let state = $state::new_keyed(key, $bytes::to_usize());
696+
Ok(Self { state })
697+
}
698+
}
699+
700+
fn input(&mut self, data: &[u8]) { self.state.update(data); }
701+
702+
fn reset(&mut self) {
703+
<Self as Reset>::reset(self)
704+
}
705+
706+
fn result(self) -> MacResult<Self::OutputSize> {
707+
MacResult::new(self.state.finalize())
708+
}
709+
}
710+
711+
impl_opaque_debug!($fix_state);
712+
impl_write!($fix_state);
713+
}
714+
}

blake2/src/blake2bp.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use digest::generic_array::typenum::U64;
2+
use compressor_b::{CompressorB, CompressorBBuilder};
3+
4+
blake2_p_impl!(VarBlake2bp, Blake2bp, CompressorB, CompressorBBuilder, u64, U64, 4,
5+
"Blake2bp instance with a variable output.",
6+
"Blake2bp instance with a fixed output.",
7+
);

blake2/src/blake2sp.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
use digest::generic_array::typenum::U32;
2+
use compressor_s::{CompressorS, CompressorSBuilder};
3+
4+
blake2_p_impl!(VarBlake2sp, Blake2sp, CompressorS, CompressorSBuilder, u32, U32, 8,
5+
"Blake2sp instance with a variable output.",
6+
"Blake2sp instance with a fixed output.",
7+
);

blake2/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ mod compressor_b;
112112
mod compressor_s;
113113
mod blake2b;
114114
mod blake2s;
115+
mod blake2bp;
116+
mod blake2sp;
115117

116118
pub use digest::Digest;
117119
pub use blake2b::{Blake2b, VarBlake2b};
118120
pub use blake2s::{Blake2s, VarBlake2s};
121+
pub use blake2bp::{Blake2bp, VarBlake2bp};
122+
pub use blake2sp::{Blake2sp, VarBlake2sp};

blake2/tests/data/blake2bp.blb

49.9 KB
Binary file not shown.

blake2/tests/data/blake2sp.blb

40.4 KB
Binary file not shown.

blake2/tests/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
#[macro_use]
33
extern crate digest;
44
extern crate blake2;
5+
extern crate hex_literal;
56

67
use digest::dev::{digest_test, variable_test};
78

89
new_test!(blake2b_fixed, "blake2b/fixed", blake2::Blake2b, digest_test);
910
new_test!(blake2b_variable, "blake2b/variable", blake2::VarBlake2b, variable_test);
1011
new_test!(blake2s_variable, "blake2s/variable", blake2::VarBlake2s, variable_test);
12+
new_test!(blake2bp, "blake2bp", blake2::Blake2bp, digest_test);
13+
new_test!(blake2sp, "blake2sp", blake2::Blake2sp, digest_test);

0 commit comments

Comments
 (0)