Skip to content
Merged
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
2 changes: 0 additions & 2 deletions polyval/src/backend.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
112 changes: 112 additions & 0 deletions polyval/src/backend/soft.rs
Original file line number Diff line number Diff line change
@@ -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<const N: usize = 1> {
/// GF(2^128) field element input blocks are multiplied by
h: FieldElement,

/// Field element representing the computed universal hash
s: FieldElement,
}

impl<const N: usize> Polyval<N> {
/// 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<const N: usize> KeySizeUser for Polyval<N> {
type KeySize = U16;
}

impl<const N: usize> KeyInit for Polyval<N> {
/// Initialize POLYVAL with the given `H` field element
fn new(h: &Key) -> Self {
Self::new_with_init_block(h, 0)
}
}

impl<const N: usize> BlockSizeUser for Polyval<N> {
type BlockSize = U16;
}

impl<const N: usize> ParBlocksSizeUser for Polyval<N> {
type ParBlocksSize = U1;
}

impl<const N: usize> UhfBackend for Polyval<N> {
fn proc_block(&mut self, x: &Block) {
let x = FieldElement::from(x);
self.s = (self.s + x) * self.h;
}
}

impl<const N: usize> UniversalHash for Polyval<N> {
fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
f.call(self);
}

/// Get POLYVAL result (i.e. computed `S` field element)
fn finalize(self) -> Tag {
self.s.into()
}
}

impl<const N: usize> Reset for Polyval<N> {
fn reset(&mut self) {
self.s = FieldElement::default();
}
}

#[cfg(feature = "zeroize")]
impl<const N: usize> Drop for Polyval<N> {
fn drop(&mut self) {
self.h.zeroize();
self.s.zeroize();
}
}
126 changes: 30 additions & 96 deletions polyval/src/backend/soft32.rs → polyval/src/backend/soft/soft32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,125 +30,59 @@
//! `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<const N: usize = 1> {
/// GF(2^128) field element input blocks are multiplied by
h: U32x4,

/// Field element representing the computed universal hash
s: U32x4,
}

impl<const N: usize> KeySizeUser for Polyval<N> {
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<const N: usize> Polyval<N> {
/// 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<Item = u32> {
[self.0, self.1, self.2, self.3].into_iter()
}
}

impl<const N: usize> KeyInit for Polyval<N> {
/// 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<const N: usize> BlockSizeUser for Polyval<N> {
type BlockSize = U16;
}

impl<const N: usize> ParBlocksSizeUser for Polyval<N> {
type ParBlocksSize = U1;
}

impl<const N: usize> UhfBackend for Polyval<N> {
fn proc_block(&mut self, x: &Block) {
let x = U32x4::from(x);
self.s = (self.s + x) * self.h;
impl From<FieldElement> for Block {
#[inline]
fn from(fe: FieldElement) -> Block {
Block::from(&fe)
}
}

impl<const N: usize> UniversalHash for Polyval<N> {
fn update_with_backend(&mut self, f: impl UhfClosure<BlockSize = Self::BlockSize>) {
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());
}

block
}
}

impl<const N: usize> Reset for Polyval<N> {
fn reset(&mut self) {
self.s = U32x4::default();
}
}

#[cfg(feature = "zeroize")]
impl<const N: usize> Drop for Polyval<N> {
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<u128> for U32x4 {
impl From<u128> for FieldElement {
fn from(x: u128) -> Self {
U32x4(
FieldElement(
x as u32,
(x >> 32) as u32,
(x >> 64) as u32,
Expand All @@ -158,12 +92,12 @@ impl From<u128> 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,
Expand All @@ -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.
Expand Down Expand Up @@ -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();
Expand Down
Loading