diff --git a/polyval/src/backend.rs b/polyval/src/backend.rs index b1a6c9c..6547d18 100644 --- a/polyval/src/backend.rs +++ b/polyval/src/backend.rs @@ -1,7 +1,5 @@ //! POLYVAL backends -#[cfg_attr(not(target_pointer_width = "64"), path = "backend/soft32.rs")] -#[cfg_attr(target_pointer_width = "64", path = "backend/soft64.rs")] mod soft; use cfg_if::cfg_if; diff --git a/polyval/src/backend/soft.rs b/polyval/src/backend/soft.rs new file mode 100644 index 0000000..232cc6a --- /dev/null +++ b/polyval/src/backend/soft.rs @@ -0,0 +1,112 @@ +//! Portable software implementation. Provides implementations for low power 32-bit devices as well +//! as a 64-bit implementation. + +// Use 64-bit backend on 64-bit targets, ARMv7, and WASM. +// Fall back to 32-bit backend on others +// TODO(tarcieri): use `cpubits` crate when available? +#[cfg_attr( + not(any( + target_pointer_width = "64", + all(target_arch = "arm", target_feature = "v7"), + target_family = "wasm" + )), + path = "soft/soft32.rs" +)] +#[cfg_attr( + any( + target_pointer_width = "64", + all(target_arch = "arm", target_feature = "v7"), + target_family = "wasm" + ), + path = "soft/soft64.rs" +)] +mod soft_impl; + +use crate::{Block, Key, Tag}; +use soft_impl::*; +use universal_hash::{ + KeyInit, Reset, UhfBackend, UhfClosure, UniversalHash, + consts::{U1, U16}, + crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser}, +}; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +/// **POLYVAL**: GHASH-like universal hash over GF(2^128). +/// +/// Paramaterized on a constant that determines how many +/// blocks to process at once: higher numbers use more memory, +/// and require more time to re-key, but process data significantly +/// faster. +/// +/// (This constant is not used when acceleration is not enabled.) +#[derive(Clone)] +pub struct Polyval { + /// GF(2^128) field element input blocks are multiplied by + h: FieldElement, + + /// Field element representing the computed universal hash + s: FieldElement, +} + +impl Polyval { + /// Initialize POLYVAL with the given `H` field element and initial block + pub fn new_with_init_block(h: &Key, init_block: u128) -> Self { + Self { + h: h.into(), + s: init_block.into(), + } + } +} + +impl KeySizeUser for Polyval { + type KeySize = U16; +} + +impl KeyInit for Polyval { + /// Initialize POLYVAL with the given `H` field element + fn new(h: &Key) -> Self { + Self::new_with_init_block(h, 0) + } +} + +impl BlockSizeUser for Polyval { + type BlockSize = U16; +} + +impl ParBlocksSizeUser for Polyval { + type ParBlocksSize = U1; +} + +impl UhfBackend for Polyval { + fn proc_block(&mut self, x: &Block) { + let x = FieldElement::from(x); + self.s = (self.s + x) * self.h; + } +} + +impl UniversalHash for Polyval { + fn update_with_backend(&mut self, f: impl UhfClosure) { + f.call(self); + } + + /// Get POLYVAL result (i.e. computed `S` field element) + fn finalize(self) -> Tag { + self.s.into() + } +} + +impl Reset for Polyval { + fn reset(&mut self) { + self.s = FieldElement::default(); + } +} + +#[cfg(feature = "zeroize")] +impl Drop for Polyval { + fn drop(&mut self) { + self.h.zeroize(); + self.s.zeroize(); + } +} diff --git a/polyval/src/backend/soft32.rs b/polyval/src/backend/soft/soft32.rs similarity index 74% rename from polyval/src/backend/soft32.rs rename to polyval/src/backend/soft/soft32.rs index f93e3af..e1d9e51 100644 --- a/polyval/src/backend/soft32.rs +++ b/polyval/src/backend/soft/soft32.rs @@ -30,86 +30,49 @@ //! `N` is present only so that we can provide a `GenericPolyval` that //! is always generic. -use crate::{Block, Key, Tag}; +use crate::Block; use core::{ num::Wrapping, ops::{Add, Mul}, }; -use universal_hash::{ - KeyInit, Reset, UhfBackend, UhfClosure, UniversalHash, - consts::{U1, U16}, - crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser}, -}; #[cfg(feature = "zeroize")] use zeroize::Zeroize; -/// **POLYVAL**: GHASH-like universal hash over GF(2^128). -/// -/// Paramaterized on a constant that determines how many -/// blocks to process at once: higher numbers use more memory, -/// and require more time to re-key, but process data significantly -/// faster. -/// -/// (This constant is not used when acceleration is not enabled.) -#[derive(Clone)] -pub struct Polyval { - /// GF(2^128) field element input blocks are multiplied by - h: U32x4, - - /// Field element representing the computed universal hash - s: U32x4, -} - -impl KeySizeUser for Polyval { - type KeySize = U16; -} +/// POLYVAL field element implemented as 4 x `u32` values. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +pub(super) struct FieldElement(u32, u32, u32, u32); -impl Polyval { - /// Initialize POLYVAL with the given `H` field element and initial block - pub fn new_with_init_block(h: &Key, init_block: u128) -> Self { - Self { - h: h.into(), - s: init_block.into(), - } +impl FieldElement { + /// Iterate over the integer components of this field element. + fn iter(&self) -> impl Iterator { + [self.0, self.1, self.2, self.3].into_iter() } } -impl KeyInit for Polyval { - /// Initialize POLYVAL with the given `H` field element - fn new(h: &Key) -> Self { - Self::new_with_init_block(h, 0) +impl From<&Block> for FieldElement { + fn from(bytes: &Block) -> FieldElement { + FieldElement( + u32::from_le_bytes(bytes[..4].try_into().unwrap()), + u32::from_le_bytes(bytes[4..8].try_into().unwrap()), + u32::from_le_bytes(bytes[8..12].try_into().unwrap()), + u32::from_le_bytes(bytes[12..].try_into().unwrap()), + ) } } -impl BlockSizeUser for Polyval { - type BlockSize = U16; -} - -impl ParBlocksSizeUser for Polyval { - type ParBlocksSize = U1; -} - -impl UhfBackend for Polyval { - fn proc_block(&mut self, x: &Block) { - let x = U32x4::from(x); - self.s = (self.s + x) * self.h; +impl From for Block { + #[inline] + fn from(fe: FieldElement) -> Block { + Block::from(&fe) } } -impl UniversalHash for Polyval { - fn update_with_backend(&mut self, f: impl UhfClosure) { - f.call(self); - } - - /// Get POLYVAL result (i.e. computed `S` field element) - fn finalize(self) -> Tag { +impl From<&FieldElement> for Block { + fn from(fe: &FieldElement) -> Block { let mut block = Block::default(); - for (chunk, i) in block - .chunks_mut(4) - .zip(&[self.s.0, self.s.1, self.s.2, self.s.3]) - { + for (chunk, i) in block.chunks_mut(4).zip(fe.iter()) { chunk.copy_from_slice(&i.to_le_bytes()); } @@ -117,38 +80,9 @@ impl UniversalHash for Polyval { } } -impl Reset for Polyval { - fn reset(&mut self) { - self.s = U32x4::default(); - } -} - -#[cfg(feature = "zeroize")] -impl Drop for Polyval { - fn drop(&mut self) { - self.h.zeroize(); - self.s.zeroize(); - } -} - -/// 4 x `u32` values -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] -struct U32x4(u32, u32, u32, u32); - -impl From<&Block> for U32x4 { - fn from(bytes: &Block) -> U32x4 { - U32x4( - u32::from_le_bytes(bytes[..4].try_into().unwrap()), - u32::from_le_bytes(bytes[4..8].try_into().unwrap()), - u32::from_le_bytes(bytes[8..12].try_into().unwrap()), - u32::from_le_bytes(bytes[12..].try_into().unwrap()), - ) - } -} - -impl From for U32x4 { +impl From for FieldElement { fn from(x: u128) -> Self { - U32x4( + FieldElement( x as u32, (x >> 32) as u32, (x >> 64) as u32, @@ -158,12 +92,12 @@ impl From for U32x4 { } #[allow(clippy::suspicious_arithmetic_impl)] -impl Add for U32x4 { +impl Add for FieldElement { type Output = Self; /// Adds two POLYVAL field elements. fn add(self, rhs: Self) -> Self::Output { - U32x4( + FieldElement( self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, @@ -173,7 +107,7 @@ impl Add for U32x4 { } #[allow(clippy::suspicious_arithmetic_impl)] -impl Mul for U32x4 { +impl Mul for FieldElement { type Output = Self; /// Computes carryless POLYVAL multiplication over GF(2^128) in constant time. @@ -276,12 +210,12 @@ impl Mul for U32x4 { zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25); } - U32x4(zw[4], zw[5], zw[6], zw[7]) + FieldElement(zw[4], zw[5], zw[6], zw[7]) } } #[cfg(feature = "zeroize")] -impl Zeroize for U32x4 { +impl Zeroize for FieldElement { fn zeroize(&mut self) { self.0.zeroize(); self.1.zeroize(); diff --git a/polyval/src/backend/soft64.rs b/polyval/src/backend/soft/soft64.rs similarity index 65% rename from polyval/src/backend/soft64.rs rename to polyval/src/backend/soft/soft64.rs index b33a286..dba125d 100644 --- a/polyval/src/backend/soft64.rs +++ b/polyval/src/backend/soft/soft64.rs @@ -10,85 +10,47 @@ //! `N` is present only so that we can provide a `GenericPolyval` that //! is always generic. +use crate::Block; use core::{ num::Wrapping, ops::{Add, Mul}, }; -use universal_hash::{ - KeyInit, Reset, UhfBackend, UhfClosure, UniversalHash, - consts::{U1, U16}, - crypto_common::{BlockSizeUser, KeySizeUser, ParBlocksSizeUser}, -}; - #[cfg(feature = "zeroize")] use zeroize::Zeroize; -use crate::{Block, Key, Tag}; - -/// **POLYVAL**: GHASH-like universal hash over GF(2^128). -/// -/// Paramaterized on a constant that determines how many -/// blocks to process at once: higher numbers use more memory, -/// and require more time to re-key, but process data significantly -/// faster. -/// -/// (This constant is not used when acceleration is not enabled.) -#[derive(Clone)] -pub struct Polyval { - /// GF(2^128) field element input blocks are multiplied by - h: U64x2, - - /// Field element representing the computed universal hash - s: U64x2, -} +/// POLYVAL field element implemented as 2 x `u64` values. +#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] +pub(super) struct FieldElement(u64, u64); -impl Polyval { - /// Initialize POLYVAL with the given `H` field element and initial block - pub fn new_with_init_block(h: &Key, init_block: u128) -> Self { - Self { - h: h.into(), - s: init_block.into(), - } +impl FieldElement { + /// Iterate over the integer components of this field element. + fn iter(&self) -> impl Iterator { + [self.0, self.1].into_iter() } } -impl KeySizeUser for Polyval { - type KeySize = U16; -} - -impl KeyInit for Polyval { - /// Initialize POLYVAL with the given `H` field element - fn new(h: &Key) -> Self { - Self::new_with_init_block(h, 0) +impl From<&Block> for FieldElement { + fn from(bytes: &Block) -> FieldElement { + FieldElement( + u64::from_le_bytes(bytes[..8].try_into().unwrap()), + u64::from_le_bytes(bytes[8..].try_into().unwrap()), + ) } } -impl BlockSizeUser for Polyval { - type BlockSize = U16; -} - -impl ParBlocksSizeUser for Polyval { - type ParBlocksSize = U1; -} - -impl UhfBackend for Polyval { - fn proc_block(&mut self, x: &Block) { - let x = U64x2::from(x); - self.s = (self.s + x) * self.h; +impl From for Block { + #[inline] + fn from(fe: FieldElement) -> Block { + Block::from(&fe) } } -impl UniversalHash for Polyval { - fn update_with_backend(&mut self, f: impl UhfClosure) { - f.call(self); - } - - /// Get POLYVAL result (i.e. computed `S` field element) - fn finalize(self) -> Tag { +impl From<&FieldElement> for Block { + fn from(fe: &FieldElement) -> Block { let mut block = Block::default(); - for (chunk, i) in block.chunks_mut(8).zip(&[self.s.0, self.s.1]) { + for (chunk, i) in block.chunks_mut(8).zip(fe.iter()) { chunk.copy_from_slice(&i.to_le_bytes()); } @@ -96,51 +58,24 @@ impl UniversalHash for Polyval { } } -impl Reset for Polyval { - fn reset(&mut self) { - self.s = U64x2::default(); - } -} - -#[cfg(feature = "zeroize")] -impl Drop for Polyval { - fn drop(&mut self) { - self.h.zeroize(); - self.s.zeroize(); - } -} - -/// 2 x `u64` values -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)] -struct U64x2(u64, u64); - -impl From<&Block> for U64x2 { - fn from(bytes: &Block) -> U64x2 { - U64x2( - u64::from_le_bytes(bytes[..8].try_into().unwrap()), - u64::from_le_bytes(bytes[8..].try_into().unwrap()), - ) - } -} - -impl From for U64x2 { +impl From for FieldElement { fn from(x: u128) -> Self { - U64x2((x >> 64) as u64, (x) as u64) + FieldElement((x >> 64) as u64, (x) as u64) } } #[allow(clippy::suspicious_arithmetic_impl)] -impl Add for U64x2 { +impl Add for FieldElement { type Output = Self; /// Adds two POLYVAL field elements. fn add(self, rhs: Self) -> Self::Output { - U64x2(self.0 ^ rhs.0, self.1 ^ rhs.1) + FieldElement(self.0 ^ rhs.0, self.1 ^ rhs.1) } } #[allow(clippy::suspicious_arithmetic_impl)] -impl Mul for U64x2 { +impl Mul for FieldElement { type Output = Self; /// Computes carryless POLYVAL multiplication over GF(2^128) in constant time. @@ -198,12 +133,12 @@ impl Mul for U64x2 { v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7); v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57); - U64x2(v2, v3) + FieldElement(v2, v3) } } #[cfg(feature = "zeroize")] -impl Zeroize for U64x2 { +impl Zeroize for FieldElement { fn zeroize(&mut self) { self.0.zeroize(); self.1.zeroize();