Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit fe227e6

Browse files
committedSep 1, 2019
poly1305: Use UniversalHash trait
A first pass at adapting Poly1305 to use the `UniversalHash` trait
1 parent a205a37 commit fe227e6

File tree

4 files changed

+115
-159
lines changed

4 files changed

+115
-159
lines changed
 

‎poly1305/Cargo.toml

+1-4
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@ readme = "README.md"
1212
edition = "2018"
1313

1414
[dependencies]
15-
subtle = { version = "2", default-features = false }
15+
universal-hash = "0.2"
1616
zeroize = { version = "0.9", optional = true, default-features = false }
1717

18-
[dev-dependencies]
19-
crypto-mac = { version = "0.7", features = ["dev"] }
20-
2118
[badges]
2219
maintenance = { status = "experimental" }
2320
travis-ci = { repository = "RustCrypto/universal-hashes" }

‎poly1305/benches/poly1305.rs

+25-41
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,29 @@
11
#![feature(test)]
22

3-
use crypto_mac::generic_array::{
4-
typenum::{U16, U32},
5-
GenericArray,
6-
};
7-
use crypto_mac::{MacResult, bench};
8-
use poly1305::{Block, Poly1305};
9-
use std::convert::TryInto;
10-
11-
bench!(Poly1305Mac);
12-
13-
/// Poly1305 isn't a traditional MAC and for that reason doesn't impl the
14-
/// `crypto_mac::Mac` trait.
15-
///
16-
/// This type is a newtype that impls a pseudo-MAC to leverage the benchmark
17-
/// functionality.
18-
///
19-
/// This is just for benchmarking! Don't copy and paste this into your program
20-
/// unless you really know what you're doing!!!
21-
#[derive(Clone)]
22-
struct Poly1305Mac(Poly1305);
23-
24-
impl Mac for Poly1305Mac {
25-
type OutputSize = U16;
26-
type KeySize = U32;
27-
28-
fn new(key: &GenericArray<u8, Self::KeySize>) -> Poly1305Mac {
29-
let poly = Poly1305::new(key.as_slice().try_into().unwrap());
30-
Poly1305Mac(poly)
31-
}
32-
33-
fn input(&mut self, data: &[u8]) {
34-
self.0.input(data);
35-
}
3+
extern crate test;
4+
5+
use poly1305::{Poly1305, universal_hash::UniversalHash};
6+
use test::Bencher;
7+
8+
macro_rules! bench {
9+
($name:ident, $bs:expr) => {
10+
#[bench]
11+
fn $name(b: &mut Bencher) {
12+
let key = Default::default();
13+
let mut m = Poly1305::new(&key);
14+
let data = [0; $bs];
15+
16+
b.iter(|| {
17+
m.update_padded(&data);
18+
});
19+
20+
b.bytes = $bs;
21+
}
22+
};
23+
}
3624

37-
fn reset(&mut self) {
38-
unimplemented!();
39-
}
4025

41-
fn result(self) -> MacResult<Self::OutputSize> {
42-
let tag: Block = self.0.result().into();
43-
MacResult::new(tag.into())
44-
}
45-
}
26+
bench!(bench1_10, 10);
27+
bench!(bench2_100, 100);
28+
bench!(bench3_1000, 1000);
29+
bench!(bench3_10000, 10000);

‎poly1305/src/lib.rs

+69-96
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,14 @@
1616
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
1717
#![warn(missing_docs, rust_2018_idioms)]
1818

19-
pub use subtle;
19+
pub use universal_hash;
2020

2121
use core::{cmp::min, convert::TryInto};
22-
use subtle::{Choice, ConstantTimeEq};
22+
use universal_hash::generic_array::{
23+
typenum::{U16, U32},
24+
GenericArray,
25+
};
26+
use universal_hash::{Output, UniversalHash};
2327
#[cfg(feature = "zeroize")]
2428
use zeroize::Zeroize;
2529

@@ -50,9 +54,12 @@ pub struct Poly1305 {
5054
buffer: Block,
5155
}
5256

53-
impl Poly1305 {
57+
impl UniversalHash for Poly1305 {
58+
type KeySize = U32;
59+
type OutputSize = U16;
60+
5461
/// Initialize Poly1305 with the given key
55-
pub fn new(key: &Key) -> Poly1305 {
62+
fn new(key: &GenericArray<u8, U32>) -> Poly1305 {
5663
let mut poly = Poly1305 {
5764
r: [0u32; 5],
5865
h: [0u32; 5],
@@ -77,75 +84,28 @@ impl Poly1305 {
7784
}
7885

7986
/// Input data into the Poly1305 universal hash function
80-
pub fn input(&mut self, data: &[u8]) {
81-
let mut m = data;
82-
83-
if self.leftover > 0 {
84-
let want = min(16 - self.leftover, m.len());
85-
86-
for (i, byte) in m.iter().cloned().enumerate().take(want) {
87-
self.buffer[self.leftover + i] = byte;
88-
}
89-
90-
m = &m[want..];
91-
self.leftover += want;
92-
93-
if self.leftover < BLOCK_SIZE {
94-
return;
95-
}
96-
97-
self.block(false);
98-
self.leftover = 0;
99-
}
100-
101-
while m.len() >= BLOCK_SIZE {
102-
// TODO(tarcieri): avoid a copy here when `TryInto` is available (1.34+)
103-
// We can avoid copying this data into the buffer, but do for now
104-
// because it simplifies constant-time assessment.
105-
self.buffer.copy_from_slice(&m[..BLOCK_SIZE]);
106-
self.block(false);
107-
m = &m[BLOCK_SIZE..];
108-
}
109-
110-
self.buffer[..m.len()].copy_from_slice(m);
111-
self.leftover = m.len();
87+
fn update_block(&mut self, block: &GenericArray<u8, U16>) {
88+
// TODO(tarcieri): pass block directly to `Poly1305::compute_block`
89+
self.update(block.as_slice());
11290
}
11391

114-
/// Input data into Poly1305, first padding it to Poly1305's block size
115-
/// ala the `pad16()` function described in RFC 8439 section 2.8.1:
116-
/// <https://tools.ietf.org/html/rfc8439#section-2.8.1>
117-
///
118-
/// This is primarily useful for implementing Salsa20 family authenticated
119-
/// encryption constructions.
120-
pub fn input_padded(&mut self, data: &[u8]) {
121-
self.input(data);
122-
123-
// Pad associated data with `\0` if it's unaligned with the block size
124-
let unaligned_len = data.len() % BLOCK_SIZE;
125-
126-
if unaligned_len != 0 {
127-
let pad = Block::default();
128-
let pad_len = BLOCK_SIZE - unaligned_len;
129-
self.input(&pad[..pad_len]);
130-
}
131-
}
132-
133-
/// Process input messages in a chained manner
134-
pub fn chain(mut self, data: &[u8]) -> Self {
135-
self.input(data);
136-
self
92+
/// Reset internal state
93+
fn reset(&mut self) {
94+
self.h = Default::default();
95+
self.buffer = Default::default();
96+
self.leftover = 0;
13797
}
13898

13999
/// Get the hashed output
140-
pub fn result(mut self) -> Tag {
100+
fn result(mut self) -> Output<U16> {
141101
if self.leftover > 0 {
142102
self.buffer[self.leftover] = 1;
143103

144104
for i in (self.leftover + 1)..BLOCK_SIZE {
145105
self.buffer[i] = 0;
146106
}
147107

148-
self.block(true);
108+
self.compute_block(true);
149109
}
150110

151111
// fully carry h
@@ -229,17 +189,58 @@ impl Poly1305 {
229189
f = u64::from(h3) + u64::from(self.pad[3]) + (f >> 32);
230190
h3 = f as u32;
231191

232-
let mut tag = Block::default();
233-
tag[0..4].copy_from_slice(&h0.to_le_bytes());
234-
tag[4..8].copy_from_slice(&h1.to_le_bytes());
235-
tag[8..12].copy_from_slice(&h2.to_le_bytes());
236-
tag[12..16].copy_from_slice(&h3.to_le_bytes());
192+
let mut output = GenericArray::default();
193+
output[0..4].copy_from_slice(&h0.to_le_bytes());
194+
output[4..8].copy_from_slice(&h1.to_le_bytes());
195+
output[8..12].copy_from_slice(&h2.to_le_bytes());
196+
output[12..16].copy_from_slice(&h3.to_le_bytes());
237197

238-
Tag::new(tag)
198+
Output::new(output)
199+
}
200+
}
201+
202+
impl Poly1305 {
203+
/// Input data into the Poly1305 universal hash function
204+
pub fn update(&mut self, data: &[u8]) {
205+
let mut m = data;
206+
207+
if self.leftover > 0 {
208+
let want = min(16 - self.leftover, m.len());
209+
210+
for (i, byte) in m.iter().cloned().enumerate().take(want) {
211+
self.buffer[self.leftover + i] = byte;
212+
}
213+
214+
m = &m[want..];
215+
self.leftover += want;
216+
217+
if self.leftover < BLOCK_SIZE {
218+
return;
219+
}
220+
221+
self.compute_block(false);
222+
self.leftover = 0;
223+
}
224+
225+
while m.len() >= BLOCK_SIZE {
226+
// TODO(tarcieri): avoid copying data into the buffer here
227+
self.buffer.copy_from_slice(&m[..BLOCK_SIZE]);
228+
self.compute_block(false);
229+
m = &m[BLOCK_SIZE..];
230+
}
231+
232+
self.buffer[..m.len()].copy_from_slice(m);
233+
self.leftover = m.len();
234+
}
235+
236+
/// Process input messages in a chained manner
237+
pub fn chain(mut self, data: &[u8]) -> Self {
238+
self.update(data);
239+
self
239240
}
240241

241242
/// Compute a single block of Poly1305 using the internal buffer
242-
fn block(&mut self, finished: bool) {
243+
fn compute_block(&mut self, finished: bool) {
243244
let hibit = if finished { 0 } else { 1 << 24 };
244245

245246
let r0 = self.r[0];
@@ -340,31 +341,3 @@ impl Drop for Poly1305 {
340341
self.buffer.zeroize();
341342
}
342343
}
343-
344-
/// Poly1305 authentication tags
345-
pub struct Tag(Block);
346-
347-
impl Tag {
348-
/// Create a new Poly1305 authentication tag
349-
fn new(tag: Block) -> Self {
350-
Tag(tag)
351-
}
352-
}
353-
354-
impl AsRef<Block> for Tag {
355-
fn as_ref(&self) -> &Block {
356-
&self.0
357-
}
358-
}
359-
360-
impl ConstantTimeEq for Tag {
361-
fn ct_eq(&self, other: &Self) -> Choice {
362-
self.0.ct_eq(other.0.as_ref())
363-
}
364-
}
365-
366-
impl From<Tag> for Block {
367-
fn from(tag: Tag) -> Block {
368-
tag.0
369-
}
370-
}

‎poly1305/tests/lib.rs

+20-18
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use poly1305::{Poly1305, KEY_SIZE};
1+
use poly1305::{universal_hash::UniversalHash, Poly1305, KEY_SIZE};
22
use std::iter::repeat;
33

44
#[test]
@@ -26,10 +26,10 @@ fn test_nacl_vector() {
2626
0xd9,
2727
];
2828

29-
let result1 = Poly1305::new(&key).chain(&msg).result();
30-
assert_eq!(&expected[..], result1.as_ref());
29+
let result1 = Poly1305::new(key.as_ref().into()).chain(&msg).result();
30+
assert_eq!(&expected[..], result1.into_bytes().as_slice());
3131

32-
let result2 = Poly1305::new(&key)
32+
let result2 = Poly1305::new(key.as_ref().into())
3333
.chain(&msg[0..32])
3434
.chain(&msg[32..96])
3535
.chain(&msg[96..112])
@@ -43,7 +43,7 @@ fn test_nacl_vector() {
4343
.chain(&msg[130..131])
4444
.result();
4545

46-
assert_eq!(&expected[..], result2.as_ref());
46+
assert_eq!(&expected[..], result2.into_bytes().as_slice());
4747
}
4848

4949
#[test]
@@ -64,9 +64,11 @@ fn donna_self_test() {
6464
0x00,
6565
];
6666

67-
let result = Poly1305::new(&wrap_key).chain(&wrap_msg).result();
67+
let result = Poly1305::new(wrap_key.as_ref().into())
68+
.chain(&wrap_msg)
69+
.result();
6870

69-
assert_eq!(&wrap_mac[..], result.as_ref());
71+
assert_eq!(&wrap_mac[..], result.into_bytes().as_slice());
7072

7173
let total_key = [
7274
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xff,
@@ -79,18 +81,18 @@ fn donna_self_test() {
7981
0x39,
8082
];
8183

82-
let mut tpoly = Poly1305::new(&total_key);
84+
let mut tpoly = Poly1305::new(total_key.as_ref().into());
8385

8486
for i in 0..256 {
8587
let mut key = [0u8; KEY_SIZE];
8688
key.copy_from_slice(&repeat(i as u8).take(KEY_SIZE).collect::<Vec<_>>());
8789

8890
let msg: Vec<u8> = repeat(i as u8).take(256).collect();
89-
let tag = Poly1305::new(&key).chain(&msg[..i]).result();
90-
tpoly.input(tag.as_ref());
91+
let tag = Poly1305::new(key.as_ref().into()).chain(&msg[..i]).result();
92+
tpoly.update(tag.into_bytes().as_slice());
9193
}
9294

93-
assert_eq!(&total_mac[..], tpoly.result().as_ref());
95+
assert_eq!(&total_mac[..], tpoly.result().into_bytes().as_slice());
9496
}
9597

9698
#[test]
@@ -104,17 +106,17 @@ fn test_tls_vectors() {
104106
0x07,
105107
];
106108

107-
let result1 = Poly1305::new(&key).chain(&msg1).result();
108-
assert_eq!(&expected1[..], result1.as_ref());
109+
let result1 = Poly1305::new(key.as_ref().into()).chain(&msg1).result();
110+
assert_eq!(&expected1[..], result1.into_bytes().as_slice());
109111

110112
let msg2 = b"Hello world!";
111113
let expected2 = [
112114
0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2, 0xb2,
113115
0xf0,
114116
];
115117

116-
let result2 = Poly1305::new(&key).chain(&msg2[..]).result();
117-
assert_eq!(&expected2[..], result2.as_ref());
118+
let result2 = Poly1305::new(key.as_ref().into()).chain(&msg2[..]).result();
119+
assert_eq!(&expected2[..], result2.into_bytes().as_slice());
118120
}
119121

120122
#[test]
@@ -135,7 +137,7 @@ fn padded_input() {
135137
0xba,
136138
];
137139

138-
let mut poly = Poly1305::new(&key);
139-
poly.input_padded(&msg);
140-
assert_eq!(&expected[..], poly.result().as_ref());
140+
let mut poly = Poly1305::new(key.as_ref().into());
141+
poly.update_padded(&msg);
142+
assert_eq!(&expected[..], poly.result().into_bytes().as_slice());
141143
}

0 commit comments

Comments
 (0)
Please sign in to comment.