Skip to content

Commit d0b54b0

Browse files
authoredSep 1, 2019
Merge pull request #6 from RustCrypto/polyval/use-universal-hash-trait
polyval: Use UniversalHash trait
2 parents 6e7668e + 241b394 commit d0b54b0

File tree

9 files changed

+77
-172
lines changed

9 files changed

+77
-172
lines changed
 

‎polyval/Cargo.toml

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ categories = ["cryptography", "no-std"]
1515
edition = "2018"
1616

1717
[dependencies]
18-
subtle = { version = "2", default-features = false }
18+
universal-hash = { version = "0.2", default-features = false }
19+
zeroize = { version = "0.10", optional = true, default-features = false }
1920

2021
[dev-dependencies]
21-
crypto-mac = { version = "0.7", features = ["dev"] }
2222
hex-literal = "0.1"
2323

2424
[features]
25+
default = []
26+
std = ["universal-hash/std"]
2527
insecure-soft = []
2628

2729
[badges]

‎polyval/benches/polyval.rs

+20-76
Original file line numberDiff line numberDiff line change
@@ -1,85 +1,29 @@
11
#![feature(test)]
22

3-
use crypto_mac::generic_array::{typenum::U16, GenericArray};
4-
use crypto_mac::{bench, MacResult};
5-
use polyval::{Block, Polyval};
6-
use std::{cmp::min, convert::TryInto};
3+
extern crate test;
74

8-
bench!(PolyvalMac);
5+
use polyval::{Polyval, universal_hash::UniversalHash};
6+
use test::Bencher;
97

10-
/// POLYVAL isn't a traditional MAC and for that reason doesn't impl the
11-
/// `crypto_mac::Mac` trait.
12-
///
13-
/// This type is a newtype that impls a pseudo-MAC to leverage the benchmark
14-
/// functionality.
15-
///
16-
/// This is just for benchmarking! Don't copy and paste this into your program
17-
/// unless you really know what you're doing!!!
18-
#[derive(Clone)]
19-
struct PolyvalMac {
20-
poly: Polyval,
21-
leftover: usize,
22-
buffer: Block,
23-
}
24-
25-
impl Mac for PolyvalMac {
26-
type OutputSize = U16;
27-
type KeySize = U16;
8+
// TODO(tarcieri): move this into the `universal-hash` crate
9+
macro_rules! bench {
10+
($name:ident, $bs:expr) => {
11+
#[bench]
12+
fn $name(b: &mut Bencher) {
13+
let key = Default::default();
14+
let mut m = Polyval::new(&key);
15+
let data = [0; $bs];
2816

29-
fn new(key: &GenericArray<u8, Self::KeySize>) -> PolyvalMac {
30-
let poly = Polyval::new(key.as_slice().try_into().unwrap());
17+
b.iter(|| {
18+
m.update_padded(&data);
19+
});
3120

32-
PolyvalMac {
33-
poly,
34-
leftover: 0,
35-
buffer: Block::default(),
21+
b.bytes = $bs;
3622
}
37-
}
38-
39-
fn input(&mut self, data: &[u8]) {
40-
let mut m = data;
41-
42-
if self.leftover > 0 {
43-
let want = min(16 - self.leftover, m.len());
44-
45-
for (i, byte) in m.iter().cloned().enumerate().take(want) {
46-
self.buffer[self.leftover + i] = byte;
47-
}
48-
49-
m = &m[want..];
50-
self.leftover += want;
51-
52-
if self.leftover < 16 {
53-
return;
54-
}
55-
56-
self.block();
57-
self.leftover = 0;
58-
}
59-
60-
while m.len() >= 16 {
61-
self.block();
62-
m = &m[16..];
63-
}
64-
65-
self.buffer[..m.len()].copy_from_slice(m);
66-
self.leftover = m.len();
67-
}
68-
69-
fn reset(&mut self) {
70-
unimplemented!();
71-
}
72-
73-
fn result(self) -> MacResult<Self::OutputSize> {
74-
let tag: Block = self.poly.result().into();
75-
MacResult::new(tag.into())
76-
}
23+
};
7724
}
7825

79-
impl PolyvalMac {
80-
/// Input the current internal buffer into POLYVAL
81-
fn block(&mut self) {
82-
let elem = self.buffer;
83-
self.poly.input_block(elem)
84-
}
85-
}
26+
bench!(bench1_10, 10);
27+
bench!(bench2_100, 100);
28+
bench!(bench3_1000, 1000);
29+
bench!(bench3_10000, 10000);

‎polyval/src/field.rs

+12-4
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,18 @@
1414
//!
1515
//! [RFC 8452 Section 3]: https://tools.ietf.org/html/rfc8452#section-3
1616
17-
pub mod backend;
18-
pub mod clmul;
17+
pub(crate) mod backend;
18+
mod clmul;
1919

2020
use self::backend::Backend;
21-
use super::Block;
2221
use core::ops::{Add, Mul};
2322

2423
/// Size of GF(2^128) in bytes (16-bytes).
2524
pub const FIELD_SIZE: usize = 16;
2625

26+
/// POLYVAL field element bytestrings (16-bytes)
27+
pub type Block = [u8; FIELD_SIZE];
28+
2729
/// Mask value used when performing Montgomery fast reduction.
2830
/// This corresponds to POLYVAL's polynomial with the highest bit unset.
2931
///
@@ -32,7 +34,7 @@ const MASK: u128 = 1 << 127 | 1 << 126 | 1 << 121 | 1;
3234

3335
/// POLYVAL field element.
3436
#[derive(Copy, Clone)]
35-
pub(crate) struct Element<B: Backend>(B);
37+
pub struct Element<B: Backend>(B);
3638

3739
impl<B: Backend> Element<B> {
3840
/// Load a `FieldElement` from its bytestring representation.
@@ -57,6 +59,12 @@ impl<B: Backend> Element<B> {
5759
}
5860
}
5961

62+
impl<B: Backend> Default for Element<B> {
63+
fn default() -> Self {
64+
Self::from_bytes(Block::default())
65+
}
66+
}
67+
6068
#[allow(clippy::suspicious_arithmetic_impl)]
6169
impl<B: Backend> Add for Element<B> {
6270
type Output = Self;

‎polyval/src/field/backend.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ mod pclmulqdq;
1212
mod soft;
1313

1414
use super::clmul::Clmul;
15-
use crate::Block;
15+
use super::Block;
1616
use core::ops::BitXor;
1717

1818
#[cfg(not(any(

‎polyval/src/field/backend/pclmulqdq.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use core::arch::x86::*;
1010
use core::arch::x86_64::*;
1111

1212
use super::Backend;
13-
use crate::{
14-
field::clmul::{self, Clmul},
13+
use crate::field::{
14+
clmul::{self, Clmul},
1515
Block,
1616
};
1717
use core::ops::BitXor;

‎polyval/src/field/backend/soft.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@
66
// See: <https://bearssl.org/gitweb/?p=BearSSL;a=blob;f=src/hash/ghash_ctmul64.c>
77

88
use super::Backend;
9-
use crate::field::clmul::{self, Clmul};
10-
use crate::Block;
9+
use crate::field::{
10+
clmul::{self, Clmul},
11+
Block,
12+
};
1113
use core::{convert::TryInto, ops::BitXor};
1214

1315
/// 2 x `u64` values emulating an XMM register

‎polyval/src/lib.rs

+23-46
Original file line numberDiff line numberDiff line change
@@ -47,77 +47,54 @@
4747
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
4848
#![warn(missing_docs, rust_2018_idioms)]
4949

50-
pub use subtle;
51-
5250
pub mod field;
53-
pub mod tag;
54-
55-
use self::field::Element;
56-
pub use self::tag::Tag;
5751

58-
// TODO(tarcieri): runtime selection of CLMUL vs soft backend when both are available
59-
use self::field::backend::M128i;
52+
pub use universal_hash;
6053

61-
/// Size of a POLYVAL block (128-bits)
62-
pub const BLOCK_SIZE: usize = 16;
54+
use core::convert::TryInto;
55+
use universal_hash::generic_array::{typenum::U16, GenericArray};
56+
use universal_hash::{Output, UniversalHash};
6357

64-
/// POLYVAL blocks (16-bytes)
65-
pub type Block = [u8; BLOCK_SIZE];
58+
// TODO(tarcieri): runtime selection of CLMUL vs soft backend when both are available
59+
use field::backend::M128i;
6660

6761
/// **POLYVAL**: GHASH-like universal hash over GF(2^128).
6862
#[allow(non_snake_case)]
6963
#[derive(Clone)]
7064
#[repr(align(16))]
7165
pub struct Polyval {
7266
/// GF(2^128) field element input blocks are multiplied by
73-
H: Element<M128i>,
67+
H: field::Element<M128i>,
7468

7569
/// Field element representing the computed universal hash
76-
S: Element<M128i>,
70+
S: field::Element<M128i>,
7771
}
7872

79-
impl Polyval {
73+
impl UniversalHash for Polyval {
74+
type KeySize = U16;
75+
type OutputSize = U16;
76+
8077
/// Initialize POLYVAL with the given `H` field element
81-
pub fn new(h: Block) -> Self {
78+
fn new(h: &GenericArray<u8, U16>) -> Self {
8279
Self {
83-
H: Element::from_bytes(h),
84-
S: Element::from_bytes(Block::default()),
80+
H: field::Element::from_bytes(h.as_slice().try_into().unwrap()),
81+
S: field::Element::default(),
8582
}
8683
}
8784

8885
/// Input a field element `X` to be authenticated into POLYVAL.
89-
pub fn input_block(&mut self, x: Block) {
90-
// "The sum of any two elements in the field is the result of XORing them."
91-
// -- RFC 8452 Section 3
92-
let sum = self.S + Element::from_bytes(x);
93-
self.S = sum * self.H;
94-
}
95-
96-
/// Input data into POLYVAL, first padding it to the block size
97-
/// ala the `right_pad_to_multiple_of_16_bytes()` function described in
98-
/// RFC 8452 Section 4:
99-
/// <https://tools.ietf.org/html/rfc8452#section-4>
100-
pub fn input_padded(&mut self, data: &[u8]) {
101-
for chunk in data.chunks(BLOCK_SIZE) {
102-
if chunk.len() == BLOCK_SIZE {
103-
// TODO(tarcieri): replace with `TryInto` in Rust 1.34+
104-
self.input_block(unsafe { *(chunk.as_ptr() as *const Block) });
105-
} else {
106-
let mut padded_block = [0u8; BLOCK_SIZE];
107-
padded_block[..chunk.len()].copy_from_slice(chunk);
108-
self.input_block(padded_block);
109-
}
110-
}
86+
fn update_block(&mut self, x: &GenericArray<u8, U16>) {
87+
let x = field::Element::from_bytes(x.as_slice().try_into().unwrap());
88+
self.S = (self.S + x) * self.H;
11189
}
11290

113-
/// Process input blocks in a chained manner
114-
pub fn chain_block(mut self, x: Block) -> Self {
115-
self.input_block(x);
116-
self
91+
/// Reset internal state
92+
fn reset(&mut self) {
93+
self.S = field::Element::default();
11794
}
11895

11996
/// Get POLYVAL result (i.e. computed `S` field element)
120-
pub fn result(self) -> Tag {
121-
Tag::new(self.S.to_bytes())
97+
fn result(self) -> Output<U16> {
98+
Output::new(GenericArray::from(self.S.to_bytes()))
12299
}
123100
}

‎polyval/src/tag.rs

-32
This file was deleted.

‎polyval/tests/lib.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
#[macro_use]
22
extern crate hex_literal;
33

4-
use polyval::{Block, Polyval};
4+
use polyval::{universal_hash::UniversalHash, Polyval};
55

66
//
77
// Test vectors or POLYVAL from RFC 8452 Appendix A
88
// <https://tools.ietf.org/html/rfc8452#appendix-A>
99
//
1010

11-
const H: Block = hex!("25629347589242761d31f826ba4b757b");
12-
const X_1: Block = hex!("4f4f95668c83dfb6401762bb2d01a262");
13-
const X_2: Block = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
11+
const H: [u8; 16] = hex!("25629347589242761d31f826ba4b757b");
12+
const X_1: [u8; 16] = hex!("4f4f95668c83dfb6401762bb2d01a262");
13+
const X_2: [u8; 16] = hex!("d1a24ddd2721d006bbe45f20d3c9f362");
1414

1515
/// POLYVAL(H, X_1, X_2)
16-
const POLYVAL_RESULT: Block = hex!("f7a3b47b846119fae5b7866cf5e5b77e");
16+
const POLYVAL_RESULT: [u8; 16] = hex!("f7a3b47b846119fae5b7866cf5e5b77e");
1717

1818
#[test]
1919
fn rfc_8452_test_vector() {
20-
let result = Polyval::new(H).chain_block(X_1).chain_block(X_2).result();
21-
assert_eq!(result.as_ref(), &POLYVAL_RESULT);
20+
let mut poly = Polyval::new(&H.into());
21+
poly.update_block(&X_1.into());
22+
poly.update_block(&X_2.into());
23+
24+
let result = poly.result();
25+
assert_eq!(&POLYVAL_RESULT[..], result.into_bytes().as_slice());
2226
}

0 commit comments

Comments
 (0)
Please sign in to comment.