Drop local chacha20poly1305 implementation
What changed, and why it matters
This commit removes the project's own implementations of the ChaCha20 stream cipher, Poly1305 message-authentication code, and the ChaCha20-Poly1305 combined encryption mode. It is described as the final step of migrating to the external 'rust-bitcoin chacha20-poly1305' crate. The change itself is a pure deletion of local code and module declarations; it does not add the replacement crate or change any call sites in this diff. There is no direct evidence in the commit that this fixes a security vulnerability.
Verify that the migration to the rust-bitcoin chacha20-poly1305 crate is complete in adjacent commits (Cargo.toml dependency addition, import updates, and functional equivalence tests). Run the existing ChaCha20-Poly1305 test vectors against the new crate and confirm no callers still reference the deleted modules. Treat this commit as a maintenance/refactoring change unless additional context shows the old implementation had a known flaw.
Security signals we found
Removal of custom cryptographic primitives in favor of an external crate
Deleted ChaCha20, Poly1305, and ChaCha20-Poly1305 RFC implementations
Commit message describes migration, not a security fix
No CVE, advisory, or security-relevant description in commit metadata
Evidence from the diff
The diff deletes four files/modules: lightning/src/crypto/chacha20.rs, chacha20poly1305rfc.rs, poly1305.rs, and their pub(crate) declarations in crypto/mod.rs. The deleted code included a ChaCha20 implementation adapted from rust-crypto, a Poly1305 implementation ported from poly1305-donna, and an RFC-variant ChaCha20-Poly1305 AEAD wrapper. The commit message frames this as completing a migration to the rust-bitcoin chacha20-poly1305 crate. No replacement code, dependency changes, or consumer updates are visible in the supplied diff, so the security effect depends entirely on whether the migration was completed elsewhere. The deleted code had a fuzzing-specific stub that bypassed cryptography, but that is normal for fuzz builds and is not a runtime vulnerability.
Changed components
lightning/src/crypto/chacha20.rslightning/src/crypto/poly1305.rslightning/src/crypto/chacha20poly1305rfc.rslightning/src/crypto/mod.rsInspect captured patch +0 / −1233
diff --git a/lightning/src/crypto/chacha20.rs b/lightning/src/crypto/chacha20.rs
deleted file mode 100644
index 67f9e93..0000000
--- a/lightning/src/crypto/chacha20.rs
+++ /dev/null
@@ -1,639 +0,0 @@
-// This file was stolen from rust-crypto.
-// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-#[cfg(not(fuzzing))]
-mod real_chacha {
- use core::cmp;
-
- #[derive(Clone, Copy, PartialEq, Eq)]
- #[allow(non_camel_case_types)]
- struct u32x4(pub u32, pub u32, pub u32, pub u32);
- impl ::core::ops::Add for u32x4 {
- type Output = u32x4;
- #[inline]
- fn add(self, rhs: u32x4) -> u32x4 {
- u32x4(
- self.0.wrapping_add(rhs.0),
- self.1.wrapping_add(rhs.1),
- self.2.wrapping_add(rhs.2),
- self.3.wrapping_add(rhs.3),
- )
- }
- }
- impl ::core::ops::Sub for u32x4 {
- type Output = u32x4;
- #[inline]
- fn sub(self, rhs: u32x4) -> u32x4 {
- u32x4(
- self.0.wrapping_sub(rhs.0),
- self.1.wrapping_sub(rhs.1),
- self.2.wrapping_sub(rhs.2),
- self.3.wrapping_sub(rhs.3),
- )
- }
- }
- impl ::core::ops::BitXor for u32x4 {
- type Output = u32x4;
- #[inline]
- fn bitxor(self, rhs: u32x4) -> u32x4 {
- u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3)
- }
- }
- impl ::core::ops::Shr<u8> for u32x4 {
- type Output = u32x4;
- #[inline]
- fn shr(self, shr: u8) -> u32x4 {
- u32x4(self.0 >> shr, self.1 >> shr, self.2 >> shr, self.3 >> shr)
- }
- }
- impl ::core::ops::Shl<u8> for u32x4 {
- type Output = u32x4;
- #[inline]
- fn shl(self, shl: u8) -> u32x4 {
- u32x4(self.0 << shl, self.1 << shl, self.2 << shl, self.3 << shl)
- }
- }
- impl u32x4 {
- #[inline]
- fn from_bytes(bytes: &[u8]) -> Self {
- assert_eq!(bytes.len(), 4 * 4);
- Self(
- u32::from_le_bytes(bytes[0 * 4..1 * 4].try_into().expect("len is 4")),
- u32::from_le_bytes(bytes[1 * 4..2 * 4].try_into().expect("len is 4")),
- u32::from_le_bytes(bytes[2 * 4..3 * 4].try_into().expect("len is 4")),
- u32::from_le_bytes(bytes[3 * 4..4 * 4].try_into().expect("len is 4")),
- )
- }
- }
-
- const BLOCK_SIZE: usize = 64;
-
- #[derive(Clone, Copy)]
- struct ChaChaState {
- a: u32x4,
- b: u32x4,
- c: u32x4,
- d: u32x4,
- }
-
- #[derive(Copy)]
- pub struct ChaCha20 {
- state: ChaChaState,
- output: [u8; BLOCK_SIZE],
- offset: usize,
- }
-
- impl Clone for ChaCha20 {
- fn clone(&self) -> ChaCha20 {
- *self
- }
- }
-
- macro_rules! swizzle {
- ($b: expr, $c: expr, $d: expr) => {{
- let u32x4(b10, b11, b12, b13) = $b;
- $b = u32x4(b11, b12, b13, b10);
- let u32x4(c10, c11, c12, c13) = $c;
- $c = u32x4(c12, c13, c10, c11);
- let u32x4(d10, d11, d12, d13) = $d;
- $d = u32x4(d13, d10, d11, d12);
- }};
- }
-
- macro_rules! state_to_buffer {
- ($state: expr, $output: expr) => {{
- let u32x4(a1, a2, a3, a4) = $state.a;
- let u32x4(b1, b2, b3, b4) = $state.b;
- let u32x4(c1, c2, c3, c4) = $state.c;
- let u32x4(d1, d2, d3, d4) = $state.d;
- let lens = [a1, a2, a3, a4, b1, b2, b3, b4, c1, c2, c3, c4, d1, d2, d3, d4];
- for i in 0..lens.len() {
- $output[i * 4..(i + 1) * 4].copy_from_slice(&lens[i].to_le_bytes());
- }
- }};
- }
-
- macro_rules! round {
- ($state: expr) => {{
- $state.a = $state.a + $state.b;
- rotate!($state.d, $state.a, 16);
- $state.c = $state.c + $state.d;
- rotate!($state.b, $state.c, 12);
- $state.a = $state.a + $state.b;
- rotate!($state.d, $state.a, 8);
- $state.c = $state.c + $state.d;
- rotate!($state.b, $state.c, 7);
- }};
- }
-
- macro_rules! rotate {
- ($a: expr, $b: expr, $rot: expr) => {{
- let v = $a ^ $b;
- let r = 32 - $rot;
- let right = v >> r;
- $a = (v << $rot) ^ right
- }};
- }
-
- impl ChaCha20 {
- pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 8 || nonce.len() == 12);
-
- ChaCha20 { state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 }
- }
-
- /// Get one block from a ChaCha stream.
- pub fn get_single_block(key: &[u8; 32], nonce: &[u8; 16]) -> [u8; 32] {
- let mut chacha = ChaCha20 {
- state: ChaCha20::expand(key, nonce),
- output: [0u8; BLOCK_SIZE],
- offset: 64,
- };
- let mut chacha_bytes = [0; 32];
- chacha.process_in_place(&mut chacha_bytes);
- chacha_bytes
- }
-
- /// Encrypts `src` into `dest` using a single block from a ChaCha stream. Passing `dest` as
- /// `src` in a second call will decrypt it.
- pub fn encrypt_single_block(key: &[u8; 32], nonce: &[u8; 16], dest: &mut [u8], src: &[u8]) {
- debug_assert_eq!(dest.len(), src.len());
- debug_assert!(dest.len() <= 32);
-
- let block = ChaCha20::get_single_block(key, nonce);
- for i in 0..dest.len() {
- dest[i] = block[i] ^ src[i];
- }
- }
-
- /// Same as `encrypt_single_block` only operates on a fixed-size input in-place.
- pub fn encrypt_single_block_in_place(
- key: &[u8; 32], nonce: &[u8; 16], bytes: &mut [u8; 32],
- ) {
- let block = ChaCha20::get_single_block(key, nonce);
- for i in 0..bytes.len() {
- bytes[i] ^= block[i];
- }
- }
-
- fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState {
- let constant = match key.len() {
- 16 => b"expand 16-byte k",
- 32 => b"expand 32-byte k",
- _ => unreachable!(),
- };
- ChaChaState {
- a: u32x4::from_bytes(&constant[0..16]),
- b: u32x4::from_bytes(&key[0..16]),
- c: if key.len() == 16 {
- u32x4::from_bytes(&key[0..16])
- } else {
- u32x4::from_bytes(&key[16..32])
- },
- d: if nonce.len() == 16 {
- u32x4::from_bytes(&nonce[0..16])
- } else if nonce.len() == 12 {
- let mut nonce4 = [0; 4 * 4];
- nonce4[4..].copy_from_slice(nonce);
- u32x4::from_bytes(&nonce4)
- } else {
- let mut nonce4 = [0; 4 * 4];
- nonce4[8..].copy_from_slice(nonce);
- u32x4::from_bytes(&nonce4)
- },
- }
- }
-
- // put the the next BLOCK_SIZE keystream bytes into self.output
- fn update(&mut self) {
- let mut state = self.state;
-
- for _ in 0..10 {
- round!(state);
- swizzle!(state.b, state.c, state.d);
- round!(state);
- swizzle!(state.d, state.c, state.b);
- }
- state.a = state.a + self.state.a;
- state.b = state.b + self.state.b;
- state.c = state.c + self.state.c;
- state.d = state.d + self.state.d;
-
- state_to_buffer!(state, self.output);
-
- self.state.d = self.state.d + u32x4(1, 0, 0, 0);
- let u32x4(c12, _, _, _) = self.state.d;
- if c12 == 0 {
- // we could increment the other counter word with an 8 byte nonce
- // but other implementations like boringssl have this same
- // limitation
- panic!("counter is exhausted");
- }
-
- self.offset = 0;
- }
-
- #[inline] // Useful cause input may be 0s on stack that should be optimized out
- pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
- assert!(input.len() == output.len());
- let len = input.len();
- let mut i = 0;
- while i < len {
- // If there is no keystream available in the output buffer,
- // generate the next block.
- if self.offset == BLOCK_SIZE {
- self.update();
- }
-
- // Process the min(available keystream, remaining input length).
- let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
- // explicitly assert lengths to avoid bounds checks:
- assert!(output.len() >= i + count);
- assert!(input.len() >= i + count);
- assert!(self.output.len() >= self.offset + count);
- for j in 0..count {
- output[i + j] = input[i + j] ^ self.output[self.offset + j];
- }
- i += count;
- self.offset += count;
- }
- }
-
- pub fn process_in_place(&mut self, input_output: &mut [u8]) {
- let len = input_output.len();
- let mut i = 0;
- while i < len {
- // If there is no keystream available in the output buffer,
- // generate the next block.
- if self.offset == BLOCK_SIZE {
- self.update();
- }
-
- // Process the min(available keystream, remaining input length).
- let count = cmp::min(BLOCK_SIZE - self.offset, len - i);
- // explicitly assert lengths to avoid bounds checks:
- assert!(input_output.len() >= i + count);
- assert!(self.output.len() >= self.offset + count);
- for j in 0..count {
- input_output[i + j] ^= self.output[self.offset + j];
- }
- i += count;
- self.offset += count;
- }
- }
-
- #[cfg(test)]
- pub fn seek_to_block(&mut self, block_offset: u32) {
- self.state.d.0 = block_offset;
- self.update();
- }
- }
-}
-#[cfg(not(fuzzing))]
-pub use self::real_chacha::ChaCha20;
-
-#[cfg(fuzzing)]
-mod fuzzy_chacha {
- pub struct ChaCha20 {}
-
- impl ChaCha20 {
- pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 8 || nonce.len() == 12);
- Self {}
- }
-
- pub fn get_single_block(_key: &[u8; 32], _nonce: &[u8; 16]) -> [u8; 32] {
- [0; 32]
- }
-
- pub fn encrypt_single_block(
- _key: &[u8; 32], _nonce: &[u8; 16], dest: &mut [u8], src: &[u8],
- ) {
- debug_assert_eq!(dest.len(), src.len());
- debug_assert!(dest.len() <= 32);
- dest.copy_from_slice(src);
- }
-
- pub fn encrypt_single_block_in_place(
- _key: &[u8; 32], _nonce: &[u8; 16], _bytes: &mut [u8; 32],
- ) {
- }
-
- pub fn process(&mut self, input: &[u8], output: &mut [u8]) {
- output.copy_from_slice(input);
- }
-
- pub fn process_in_place(&mut self, _input_output: &mut [u8]) {}
- }
-}
-#[cfg(fuzzing)]
-pub use self::fuzzy_chacha::ChaCha20;
-
-#[cfg(test)]
-mod test {
- use core::iter::repeat;
-
- use crate::prelude::*;
-
- use super::ChaCha20;
-
- #[test]
- fn test_chacha20_256_tls_vectors() {
- struct TestVector {
- key: [u8; 32],
- nonce: [u8; 8],
- keystream: Vec<u8>,
- }
- // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
- let test_vectors = [
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- keystream: vec![
- 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53,
- 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36,
- 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48,
- 0x8d, 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4,
- 0x15, 0x18, 0xa1, 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- keystream: vec![
- 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96, 0xd7, 0x73, 0x6e, 0x7b, 0x20,
- 0x8e, 0x3c, 0x96, 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60, 0x4f, 0x45,
- 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41, 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66,
- 0xd2, 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c, 0x53, 0xd7, 0x92, 0xb1,
- 0xc4, 0x3f, 0xea, 0x81, 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
- keystream: vec![
- 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5, 0xe7, 0x86, 0xdc, 0x63, 0x97,
- 0x3f, 0x65, 0x3a, 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13, 0x4f, 0xcb,
- 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31, 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08,
- 0x45, 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b, 0x52, 0x77, 0x06, 0x2e,
- 0xb7, 0xa0, 0x43, 0x3e, 0x44, 0x5f, 0x41, 0xe3,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- keystream: vec![
- 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, 0xf5, 0xcf, 0x35, 0xbd, 0x3d,
- 0xd3, 0x3b, 0x80, 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac, 0x33, 0x96,
- 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5,
- 0x3c, 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54, 0x5d, 0xdc, 0x49, 0x7a,
- 0x0b, 0x46, 0x6e, 0x7d, 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
- 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
- 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ],
- nonce: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
- keystream: vec![
- 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, 0x64,
- 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, 0xec, 0x01,
- 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46,
- 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, 0x05, 0xd3, 0xbe, 0x59,
- 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a, 0x38,
- 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a,
- 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60,
- 0xe8, 0x46, 0x29, 0xc9, 0xbd, 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
- 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49,
- 0x2b, 0x56, 0x2e, 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9,
- 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f,
- 0xc3, 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76,
- 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, 0x07,
- 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c,
- 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, 0x0e, 0xaf, 0x46,
- 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
- 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, 0x94, 0xdf, 0x76, 0x28, 0xfe,
- 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9,
- 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40,
- 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
- ],
- },
- ];
-
- for tv in test_vectors.iter() {
- let mut c = ChaCha20::new(&tv.key, &tv.nonce);
- let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
- let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
- c.process(&input[..], &mut output[..]);
- assert_eq!(output, tv.keystream);
- }
- }
-
- #[test]
- fn test_chacha20_256_tls_vectors_96_nonce() {
- struct TestVector {
- key: [u8; 32],
- nonce: [u8; 12],
- keystream: Vec<u8>,
- }
- // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
- let test_vectors = [
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- keystream: vec![
- 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d, 0x6a, 0xe5, 0x53,
- 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36,
- 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48,
- 0x8d, 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43, 0xb8, 0xf4,
- 0x15, 0x18, 0xa1, 0x1c, 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- keystream: vec![
- 0x45, 0x40, 0xf0, 0x5a, 0x9f, 0x1f, 0xb2, 0x96, 0xd7, 0x73, 0x6e, 0x7b, 0x20,
- 0x8e, 0x3c, 0x96, 0xeb, 0x4f, 0xe1, 0x83, 0x46, 0x88, 0xd2, 0x60, 0x4f, 0x45,
- 0x09, 0x52, 0xed, 0x43, 0x2d, 0x41, 0xbb, 0xe2, 0xa0, 0xb6, 0xea, 0x75, 0x66,
- 0xd2, 0xa5, 0xd1, 0xe7, 0xe2, 0x0d, 0x42, 0xaf, 0x2c, 0x53, 0xd7, 0x92, 0xb1,
- 0xc4, 0x3f, 0xea, 0x81, 0x7e, 0x9a, 0xd2, 0x75, 0xae, 0x54, 0x69, 0x63,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01],
- keystream: vec![
- 0xde, 0x9c, 0xba, 0x7b, 0xf3, 0xd6, 0x9e, 0xf5, 0xe7, 0x86, 0xdc, 0x63, 0x97,
- 0x3f, 0x65, 0x3a, 0x0b, 0x49, 0xe0, 0x15, 0xad, 0xbf, 0xf7, 0x13, 0x4f, 0xcb,
- 0x7d, 0xf1, 0x37, 0x82, 0x10, 0x31, 0xe8, 0x5a, 0x05, 0x02, 0x78, 0xa7, 0x08,
- 0x45, 0x27, 0x21, 0x4f, 0x73, 0xef, 0xc7, 0xfa, 0x5b, 0x52, 0x77, 0x06, 0x2e,
- 0xb7, 0xa0, 0x43, 0x3e, 0x44, 0x5f, 0x41, 0xe3,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00],
- keystream: vec![
- 0xef, 0x3f, 0xdf, 0xd6, 0xc6, 0x15, 0x78, 0xfb, 0xf5, 0xcf, 0x35, 0xbd, 0x3d,
- 0xd3, 0x3b, 0x80, 0x09, 0x63, 0x16, 0x34, 0xd2, 0x1e, 0x42, 0xac, 0x33, 0x96,
- 0x0b, 0xd1, 0x38, 0xe5, 0x0d, 0x32, 0x11, 0x1e, 0x4c, 0xaf, 0x23, 0x7e, 0xe5,
- 0x3c, 0xa8, 0xad, 0x64, 0x26, 0x19, 0x4a, 0x88, 0x54, 0x5d, 0xdc, 0x49, 0x7a,
- 0x0b, 0x46, 0x6e, 0x7d, 0x6b, 0xbd, 0xb0, 0x04, 0x1b, 0x2f, 0x58, 0x6b,
- ],
- },
- TestVector {
- key: [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
- 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
- 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
- ],
- nonce: [0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07],
- keystream: vec![
- 0xf7, 0x98, 0xa1, 0x89, 0xf1, 0x95, 0xe6, 0x69, 0x82, 0x10, 0x5f, 0xfb, 0x64,
- 0x0b, 0xb7, 0x75, 0x7f, 0x57, 0x9d, 0xa3, 0x16, 0x02, 0xfc, 0x93, 0xec, 0x01,
- 0xac, 0x56, 0xf8, 0x5a, 0xc3, 0xc1, 0x34, 0xa4, 0x54, 0x7b, 0x73, 0x3b, 0x46,
- 0x41, 0x30, 0x42, 0xc9, 0x44, 0x00, 0x49, 0x17, 0x69, 0x05, 0xd3, 0xbe, 0x59,
- 0xea, 0x1c, 0x53, 0xf1, 0x59, 0x16, 0x15, 0x5c, 0x2b, 0xe8, 0x24, 0x1a, 0x38,
- 0x00, 0x8b, 0x9a, 0x26, 0xbc, 0x35, 0x94, 0x1e, 0x24, 0x44, 0x17, 0x7c, 0x8a,
- 0xde, 0x66, 0x89, 0xde, 0x95, 0x26, 0x49, 0x86, 0xd9, 0x58, 0x89, 0xfb, 0x60,
- 0xe8, 0x46, 0x29, 0xc9, 0xbd, 0x9a, 0x5a, 0xcb, 0x1c, 0xc1, 0x18, 0xbe, 0x56,
- 0x3e, 0xb9, 0xb3, 0xa4, 0xa4, 0x72, 0xf8, 0x2e, 0x09, 0xa7, 0xe7, 0x78, 0x49,
- 0x2b, 0x56, 0x2e, 0xf7, 0x13, 0x0e, 0x88, 0xdf, 0xe0, 0x31, 0xc7, 0x9d, 0xb9,
- 0xd4, 0xf7, 0xc7, 0xa8, 0x99, 0x15, 0x1b, 0x9a, 0x47, 0x50, 0x32, 0xb6, 0x3f,
- 0xc3, 0x85, 0x24, 0x5f, 0xe0, 0x54, 0xe3, 0xdd, 0x5a, 0x97, 0xa5, 0xf5, 0x76,
- 0xfe, 0x06, 0x40, 0x25, 0xd3, 0xce, 0x04, 0x2c, 0x56, 0x6a, 0xb2, 0xc5, 0x07,
- 0xb1, 0x38, 0xdb, 0x85, 0x3e, 0x3d, 0x69, 0x59, 0x66, 0x09, 0x96, 0x54, 0x6c,
- 0xc9, 0xc4, 0xa6, 0xea, 0xfd, 0xc7, 0x77, 0xc0, 0x40, 0xd7, 0x0e, 0xaf, 0x46,
- 0xf7, 0x6d, 0xad, 0x39, 0x79, 0xe5, 0xc5, 0x36, 0x0c, 0x33, 0x17, 0x16, 0x6a,
- 0x1c, 0x89, 0x4c, 0x94, 0xa3, 0x71, 0x87, 0x6a, 0x94, 0xdf, 0x76, 0x28, 0xfe,
- 0x4e, 0xaa, 0xf2, 0xcc, 0xb2, 0x7d, 0x5a, 0xaa, 0xe0, 0xad, 0x7a, 0xd0, 0xf9,
- 0xd4, 0xb6, 0xad, 0x3b, 0x54, 0x09, 0x87, 0x46, 0xd4, 0x52, 0x4d, 0x38, 0x40,
- 0x7a, 0x6d, 0xeb, 0x3a, 0xb7, 0x8f, 0xab, 0x78, 0xc9,
- ],
- },
- ];
-
- for tv in test_vectors.iter() {
- let mut c = ChaCha20::new(&tv.key, &tv.nonce);
- let input: Vec<u8> = repeat(0).take(tv.keystream.len()).collect();
- let mut output: Vec<u8> = repeat(0).take(input.len()).collect();
- c.process(&input[..], &mut output[..]);
- assert_eq!(output, tv.keystream);
- }
- }
-
- #[test]
- fn get_single_block() {
- // Test that `get_single_block` (which takes a 16-byte nonce) is equivalent to getting a block
- // using a 12-byte nonce, with the block starting at the counter offset given by the remaining 4
- // bytes.
- let key = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
- 0x1c, 0x1d, 0x1e, 0x1f,
- ];
- let nonce_16bytes = [
- 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
- 0x0a, 0x0b,
- ];
- let counter_pos = &nonce_16bytes[..4];
- let nonce_12bytes = &nonce_16bytes[4..];
-
- // Initialize a ChaCha20 instance with its counter starting at 0.
- let mut chacha20 = ChaCha20::new(&key, nonce_12bytes);
- // Seek its counter to the block at counter_pos.
- chacha20.seek_to_block(u32::from_le_bytes(counter_pos.try_into().unwrap()));
- let mut block_bytes = [0; 32];
- chacha20.process_in_place(&mut block_bytes);
-
- assert_eq!(ChaCha20::get_single_block(&key, &nonce_16bytes), block_bytes);
- }
-
- #[test]
- fn encrypt_single_block() {
- let key = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
- 0x1c, 0x1d, 0x1e, 0x1f,
- ];
- let nonce = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0e, 0x0f,
- ];
- let bytes = [1; 32];
-
- let mut encrypted_bytes = [0; 32];
- ChaCha20::encrypt_single_block(&key, &nonce, &mut encrypted_bytes, &bytes);
-
- let mut decrypted_bytes = [0; 32];
- ChaCha20::encrypt_single_block(&key, &nonce, &mut decrypted_bytes, &encrypted_bytes);
-
- assert_eq!(bytes, decrypted_bytes);
- }
-
- #[test]
- fn encrypt_single_block_in_place() {
- let key = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
- 0x1c, 0x1d, 0x1e, 0x1f,
- ];
- let nonce = [
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
- 0x0e, 0x0f,
- ];
- let unencrypted_bytes = [1; 32];
- let mut bytes = unencrypted_bytes;
-
- ChaCha20::encrypt_single_block_in_place(&key, &nonce, &mut bytes);
- assert_ne!(bytes, unencrypted_bytes);
-
- ChaCha20::encrypt_single_block_in_place(&key, &nonce, &mut bytes);
- assert_eq!(bytes, unencrypted_bytes);
- }
-}
diff --git a/lightning/src/crypto/chacha20poly1305rfc.rs b/lightning/src/crypto/chacha20poly1305rfc.rs
deleted file mode 100644
index 839fad9..0000000
--- a/lightning/src/crypto/chacha20poly1305rfc.rs
+++ /dev/null
@@ -1,157 +0,0 @@
-// ring has a garbage API so its use is avoided, but rust-crypto doesn't have RFC-variant poly1305
-// Instead, we steal rust-crypto's implementation and tweak it to match the RFC.
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-//
-// This is a port of Andrew Moons poly1305-donna
-// https://github.com/floodyberry/poly1305-donna
-
-use super::chacha20::ChaCha20;
-use super::fixed_time_eq;
-use super::poly1305::Poly1305;
-
-pub struct ChaCha20Poly1305RFC {
- cipher: ChaCha20,
- mac: Poly1305,
- finished: bool,
- data_len: usize,
- aad_len: u64,
-}
-
-impl ChaCha20Poly1305RFC {
- #[inline]
- fn pad_mac_16(mac: &mut Poly1305, len: usize) {
- if len % 16 != 0 {
- mac.input(&[0; 16][0..16 - (len % 16)]);
- }
- }
- pub fn new(key: &[u8], nonce: &[u8], aad: &[u8]) -> ChaCha20Poly1305RFC {
- assert!(key.len() == 16 || key.len() == 32);
- assert!(nonce.len() == 12);
-
- // Ehh, I'm too lazy to *also* tweak ChaCha20 to make it RFC-compliant
- assert!(nonce[0] == 0 && nonce[1] == 0 && nonce[2] == 0 && nonce[3] == 0);
-
- let mut cipher = ChaCha20::new(key, &nonce[4..]);
- let mut mac_key = [0u8; 64];
- let zero_key = [0u8; 64];
- cipher.process(&zero_key, &mut mac_key);
-
- #[cfg(not(fuzzing))]
- let mut mac = Poly1305::new(&mac_key[..32]);
- #[cfg(fuzzing)]
- let mut mac = Poly1305::new(&key);
- mac.input(aad);
- ChaCha20Poly1305RFC::pad_mac_16(&mut mac, aad.len());
-
- ChaCha20Poly1305RFC { cipher, mac, finished: false, data_len: 0, aad_len: aad.len() as u64 }
- }
-
- pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
- assert!(input.len() == output.len());
- assert!(!self.finished);
- self.cipher.process(input, output);
- self.data_len += input.len();
- self.mac.input(output);
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.finished = true;
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
- out_tag.copy_from_slice(&self.mac.result());
- }
-
- pub fn encrypt_full_message_in_place(&mut self, input_output: &mut [u8], out_tag: &mut [u8]) {
- self.encrypt_in_place(input_output);
- self.finish_and_get_tag(out_tag);
- }
-
- // Encrypt `input_output` in-place. To finish and calculate the tag, use `finish_and_get_tag`
- // below.
- pub(in super::super) fn encrypt_in_place(&mut self, input_output: &mut [u8]) {
- debug_assert!(!self.finished);
- self.cipher.process_in_place(input_output);
- self.data_len += input_output.len();
- self.mac.input(input_output);
- }
-
- // If we were previously encrypting with `encrypt_in_place`, this method can be used to finish
- // encrypting and calculate the tag.
- pub(in super::super) fn finish_and_get_tag(&mut self, out_tag: &mut [u8]) {
- debug_assert!(!self.finished);
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.finished = true;
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
- out_tag.copy_from_slice(&self.mac.result());
- }
-
- /// Decrypt the `input`, checking the given `tag` prior to writing the decrypted contents
- /// into `output`. Note that, because `output` is not touched until the `tag` is checked,
- /// this decryption is *variable time*.
- pub fn variable_time_decrypt(
- &mut self, input: &[u8], output: &mut [u8], tag: &[u8],
- ) -> Result<(), ()> {
- assert!(input.len() == output.len());
- assert!(!self.finished);
-
- self.finished = true;
-
- self.mac.input(input);
-
- self.data_len += input.len();
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
-
- let calc_tag = self.mac.result();
- if fixed_time_eq(&calc_tag, tag) {
- self.cipher.process(input, output);
- Ok(())
- } else {
- Err(())
- }
- }
-
- pub fn check_decrypt_in_place(
- &mut self, input_output: &mut [u8], tag: &[u8],
- ) -> Result<(), ()> {
- self.decrypt_in_place(input_output);
- if self.finish_and_check_tag(tag) {
- Ok(())
- } else {
- Err(())
- }
- }
-
- /// Decrypt in place, without checking the tag. Use `finish_and_check_tag` to check it
- /// later when decryption finishes.
- ///
- /// Should never be `pub` because the public API should always enforce tag checking.
- pub(in super::super) fn decrypt_in_place(&mut self, input_output: &mut [u8]) {
- debug_assert!(!self.finished);
- self.mac.input(input_output);
- self.data_len += input_output.len();
- self.cipher.process_in_place(input_output);
- }
-
- /// If we were previously decrypting with `just_decrypt_in_place`, this method must be used
- /// to check the tag. Returns whether or not the tag is valid.
- pub(in super::super) fn finish_and_check_tag(&mut self, tag: &[u8]) -> bool {
- debug_assert!(!self.finished);
- self.finished = true;
- ChaCha20Poly1305RFC::pad_mac_16(&mut self.mac, self.data_len);
- self.mac.input(&self.aad_len.to_le_bytes());
- self.mac.input(&(self.data_len as u64).to_le_bytes());
-
- let calc_tag = self.mac.result();
- if fixed_time_eq(&calc_tag, tag) {
- true
- } else {
- false
- }
- }
-}
diff --git a/lightning/src/crypto/mod.rs b/lightning/src/crypto/mod.rs
index 478918a..73d7ad6 100644
--- a/lightning/src/crypto/mod.rs
+++ b/lightning/src/crypto/mod.rs
@@ -7,8 +7,5 @@ fn fixed_time_eq(a: &[u8], b: &[u8]) -> bool {
a == b
}
-pub(crate) mod chacha20;
-pub(crate) mod chacha20poly1305rfc;
-pub(crate) mod poly1305;
pub(crate) mod streams;
pub(crate) mod utils;
diff --git a/lightning/src/crypto/poly1305.rs b/lightning/src/crypto/poly1305.rs
deleted file mode 100644
index a71e39e..0000000
--- a/lightning/src/crypto/poly1305.rs
+++ /dev/null
@@ -1,434 +0,0 @@
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-// This is a port of Andrew Moons poly1305-donna
-// https://github.com/floodyberry/poly1305-donna
-
-#[cfg(not(fuzzing))]
-mod real_poly1305 {
- use core::cmp::min;
-
- #[derive(Clone, Copy)]
- pub struct Poly1305 {
- r: [u32; 5],
- h: [u32; 5],
- pad: [u32; 4],
- leftover: usize,
- buffer: [u8; 16],
- finalized: bool,
- }
-
- impl Poly1305 {
- pub fn new(key: &[u8]) -> Poly1305 {
- assert!(key.len() == 32);
- let mut poly = Poly1305 {
- r: [0u32; 5],
- h: [0u32; 5],
- pad: [0u32; 4],
- leftover: 0,
- buffer: [0u8; 16],
- finalized: false,
- };
-
- // r &= 0xffffffc0ffffffc0ffffffc0fffffff
- poly.r[0] = (u32::from_le_bytes(key[0..4].try_into().expect("len is 4"))) & 0x3ffffff;
- poly.r[1] =
- (u32::from_le_bytes(key[3..7].try_into().expect("len is 4")) >> 2) & 0x3ffff03;
- poly.r[2] =
- (u32::from_le_bytes(key[6..10].try_into().expect("len is 4")) >> 4) & 0x3ffc0ff;
- poly.r[3] =
- (u32::from_le_bytes(key[9..13].try_into().expect("len is 4")) >> 6) & 0x3f03fff;
- poly.r[4] =
- (u32::from_le_bytes(key[12..16].try_into().expect("len is 4")) >> 8) & 0x00fffff;
-
- poly.pad[0] = u32::from_le_bytes(key[16..20].try_into().expect("len is 4"));
- poly.pad[1] = u32::from_le_bytes(key[20..24].try_into().expect("len is 4"));
- poly.pad[2] = u32::from_le_bytes(key[24..28].try_into().expect("len is 4"));
- poly.pad[3] = u32::from_le_bytes(key[28..32].try_into().expect("len is 4"));
-
- poly
- }
-
- fn block(&mut self, m: &[u8]) {
- let hibit: u32 = if self.finalized { 0 } else { 1 << 24 };
-
- let r0 = self.r[0];
- let r1 = self.r[1];
- let r2 = self.r[2];
- let r3 = self.r[3];
- let r4 = self.r[4];
-
- let s1 = r1 * 5;
- let s2 = r2 * 5;
- let s3 = r3 * 5;
- let s4 = r4 * 5;
-
- let mut h0 = self.h[0];
- let mut h1 = self.h[1];
- let mut h2 = self.h[2];
- let mut h3 = self.h[3];
- let mut h4 = self.h[4];
-
- // h += m
- h0 += (u32::from_le_bytes(m[0..4].try_into().expect("len is 4"))) & 0x3ffffff;
- h1 += (u32::from_le_bytes(m[3..7].try_into().expect("len is 4")) >> 2) & 0x3ffffff;
- h2 += (u32::from_le_bytes(m[6..10].try_into().expect("len is 4")) >> 4) & 0x3ffffff;
- h3 += (u32::from_le_bytes(m[9..13].try_into().expect("len is 4")) >> 6) & 0x3ffffff;
- h4 += (u32::from_le_bytes(m[12..16].try_into().expect("len is 4")) >> 8) | hibit;
-
- // h *= r
- let d0 = (h0 as u64 * r0 as u64)
- + (h1 as u64 * s4 as u64)
- + (h2 as u64 * s3 as u64)
- + (h3 as u64 * s2 as u64)
- + (h4 as u64 * s1 as u64);
- let mut d1 = (h0 as u64 * r1 as u64)
- + (h1 as u64 * r0 as u64)
- + (h2 as u64 * s4 as u64)
- + (h3 as u64 * s3 as u64)
- + (h4 as u64 * s2 as u64);
- let mut d2 = (h0 as u64 * r2 as u64)
- + (h1 as u64 * r1 as u64)
- + (h2 as u64 * r0 as u64)
- + (h3 as u64 * s4 as u64)
- + (h4 as u64 * s3 as u64);
- let mut d3 = (h0 as u64 * r3 as u64)
- + (h1 as u64 * r2 as u64)
- + (h2 as u64 * r1 as u64)
- + (h3 as u64 * r0 as u64)
- + (h4 as u64 * s4 as u64);
- let mut d4 = (h0 as u64 * r4 as u64)
- + (h1 as u64 * r3 as u64)
- + (h2 as u64 * r2 as u64)
- + (h3 as u64 * r1 as u64)
- + (h4 as u64 * r0 as u64);
-
- // (partial) h %= p
- let mut c: u32;
- c = (d0 >> 26) as u32;
- h0 = d0 as u32 & 0x3ffffff;
- d1 += c as u64;
- c = (d1 >> 26) as u32;
- h1 = d1 as u32 & 0x3ffffff;
- d2 += c as u64;
- c = (d2 >> 26) as u32;
- h2 = d2 as u32 & 0x3ffffff;
- d3 += c as u64;
- c = (d3 >> 26) as u32;
- h3 = d3 as u32 & 0x3ffffff;
- d4 += c as u64;
- c = (d4 >> 26) as u32;
- h4 = d4 as u32 & 0x3ffffff;
- h0 += c * 5;
- c = h0 >> 26;
- h0 &= 0x3ffffff;
- h1 += c;
-
- self.h[0] = h0;
- self.h[1] = h1;
- self.h[2] = h2;
- self.h[3] = h3;
- self.h[4] = h4;
- }
-
- pub fn finish(&mut self) {
- if self.leftover > 0 {
- self.buffer[self.leftover] = 1;
- for i in self.leftover + 1..16 {
- self.buffer[i] = 0;
- }
- self.finalized = true;
- let tmp = self.buffer;
- self.block(&tmp);
- }
-
- // fully carry h
- let mut h0 = self.h[0];
- let mut h1 = self.h[1];
- let mut h2 = self.h[2];
- let mut h3 = self.h[3];
- let mut h4 = self.h[4];
-
- let mut c: u32;
- c = h1 >> 26;
- h1 &= 0x3ffffff;
- h2 += c;
- c = h2 >> 26;
- h2 &= 0x3ffffff;
- h3 += c;
- c = h3 >> 26;
- h3 &= 0x3ffffff;
- h4 += c;
- c = h4 >> 26;
- h4 &= 0x3ffffff;
- h0 += c * 5;
- c = h0 >> 26;
- h0 &= 0x3ffffff;
- h1 += c;
-
- // compute h + -p
- let mut g0 = h0.wrapping_add(5);
- c = g0 >> 26;
- g0 &= 0x3ffffff;
- let mut g1 = h1.wrapping_add(c);
- c = g1 >> 26;
- g1 &= 0x3ffffff;
- let mut g2 = h2.wrapping_add(c);
- c = g2 >> 26;
- g2 &= 0x3ffffff;
- let mut g3 = h3.wrapping_add(c);
- c = g3 >> 26;
- g3 &= 0x3ffffff;
- let mut g4 = h4.wrapping_add(c).wrapping_sub(1 << 26);
-
- // select h if h < p, or h + -p if h >= p
- let mut mask = (g4 >> (32 - 1)).wrapping_sub(1);
- g0 &= mask;
- g1 &= mask;
- g2 &= mask;
- g3 &= mask;
- g4 &= mask;
- mask = !mask;
- h0 = (h0 & mask) | g0;
- h1 = (h1 & mask) | g1;
- h2 = (h2 & mask) | g2;
- h3 = (h3 & mask) | g3;
- h4 = (h4 & mask) | g4;
-
- // h = h % (2^128)
- h0 = ((h0) | (h1 << 26)) & 0xffffffff;
- h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
- h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
- h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
-
- // h = mac = (h + pad) % (2^128)
- let mut f: u64;
- f = h0 as u64 + self.pad[0] as u64;
- h0 = f as u32;
- f = h1 as u64 + self.pad[1] as u64 + (f >> 32);
- h1 = f as u32;
- f = h2 as u64 + self.pad[2] as u64 + (f >> 32);
- h2 = f as u32;
- f = h3 as u64 + self.pad[3] as u64 + (f >> 32);
- h3 = f as u32;
-
- self.h[0] = h0;
- self.h[1] = h1;
- self.h[2] = h2;
- self.h[3] = h3;
- }
-
- pub fn input(&mut self, data: &[u8]) {
- assert!(!self.finalized);
- let mut m = data;
-
- if self.leftover > 0 {
- let want = min(16 - self.leftover, m.len());
- for i in 0..want {
- self.buffer[self.leftover + i] = m[i];
- }
- m = &m[want..];
- self.leftover += want;
-
- if self.leftover < 16 {
- return;
- }
-
- // self.block(self.buffer[..]);
- let tmp = self.buffer;
- self.block(&tmp);
-
- self.leftover = 0;
- }
-
- while m.len() >= 16 {
- self.block(&m[0..16]);
- m = &m[16..];
- }
-
- for i in 0..m.len() {
- self.buffer[i] = m[i];
- }
- self.leftover = m.len();
- }
-
- pub fn result(&mut self) -> [u8; 16] {
- if !self.finalized {
- self.finish();
- }
- let mut output = [0; 16];
- output[0..4].copy_from_slice(&self.h[0].to_le_bytes());
- output[4..8].copy_from_slice(&self.h[1].to_le_bytes());
- output[8..12].copy_from_slice(&self.h[2].to_le_bytes());
- output[12..16].copy_from_slice(&self.h[3].to_le_bytes());
- output
- }
- }
-
- #[cfg(test)]
- mod test {
- use core::iter::repeat;
-
- use super::Poly1305;
-
- fn poly1305(key: &[u8], msg: &[u8], mac: &mut [u8; 16]) {
- let mut poly = Poly1305::new(key);
- poly.input(msg);
- *mac = poly.result();
- }
-
- #[test]
- fn test_nacl_vector() {
- let key = [
- 0xee, 0xa6, 0xa7, 0x25, 0x1c, 0x1e, 0x72, 0x91, 0x6d, 0x11, 0xc2, 0xcb, 0x21, 0x4d,
- 0x3c, 0x25, 0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, 0x2d, 0x65, 0x1f, 0xa4,
- 0xc8, 0xcf, 0xf8, 0x80,
- ];
-
- let msg = [
- 0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, 0xc2, 0x96, 0x50, 0xba, 0x32, 0xfc,
- 0x76, 0xce, 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4, 0x47, 0x6f, 0xb8, 0xc5,
- 0x31, 0xa1, 0x18, 0x6a, 0xc0, 0xdf, 0xc1, 0x7c, 0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7,
- 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72, 0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2,
- 0x27, 0x0d, 0x6f, 0xb8, 0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7,
- 0xcc, 0x8a, 0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, 0x90, 0x22, 0x43, 0x68,
- 0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda, 0x99, 0x83,
- 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, 0x56, 0x24, 0x4a, 0x9e, 0x88, 0xd5, 0xf9, 0xb3,
- 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6, 0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4,
- 0x5a, 0x74, 0xe3, 0x55, 0xa5,
- ];
-
- let expected = [
- 0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, 0x2a, 0x7d, 0xfb, 0x4b, 0x3d, 0x33,
- 0x05, 0xd9,
- ];
-
- let mut mac = [0u8; 16];
- poly1305(&key, &msg, &mut mac);
- assert_eq!(&mac[..], &expected[..]);
-
- let mut poly = Poly1305::new(&key);
- poly.input(&msg[0..32]);
- poly.input(&msg[32..96]);
- poly.input(&msg[96..112]);
- poly.input(&msg[112..120]);
- poly.input(&msg[120..124]);
- poly.input(&msg[124..126]);
- poly.input(&msg[126..127]);
- poly.input(&msg[127..128]);
- poly.input(&msg[128..129]);
- poly.input(&msg[129..130]);
- poly.input(&msg[130..131]);
- let mac = poly.result();
- assert_eq!(&mac[..], &expected[..]);
- }
-
- #[test]
- fn donna_self_test() {
- let wrap_key = [
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let wrap_msg = [
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff,
- ];
-
- let wrap_mac = [
- 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00,
- ];
-
- let mut mac = [0u8; 16];
- poly1305(&wrap_key, &wrap_msg, &mut mac);
- assert_eq!(&mac[..], &wrap_mac[..]);
-
- let total_key = [
- 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00,
- ];
-
- let total_mac = [
- 0x64, 0xaf, 0xe2, 0xe8, 0xd6, 0xad, 0x7b, 0xbd, 0xd2, 0x87, 0xf9, 0x7c, 0x44, 0x62,
- 0x3d, 0x39,
- ];
-
- let mut tpoly = Poly1305::new(&total_key);
- for i in 0..256 {
- let key: Vec<u8> = repeat(i as u8).take(32).collect();
- let msg: Vec<u8> = repeat(i as u8).take(256).collect();
- let mut mac = [0u8; 16];
- poly1305(&key[..], &msg[0..i], &mut mac);
- tpoly.input(&mac);
- }
- let mac = tpoly.result();
- assert_eq!(&mac[..], &total_mac[..]);
- }
-
- #[test]
- fn test_tls_vectors() {
- // from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04
- let key = b"this is 32-byte key for Poly1305";
- let msg = [0u8; 32];
- let expected = [
- 0x49, 0xec, 0x78, 0x09, 0x0e, 0x48, 0x1e, 0xc6, 0xc2, 0x6b, 0x33, 0xb9, 0x1c, 0xcc,
- 0x03, 0x07,
- ];
- let mut mac = [0u8; 16];
- poly1305(key, &msg, &mut mac);
- assert_eq!(&mac[..], &expected[..]);
-
- let msg = b"Hello world!";
- let expected = [
- 0xa6, 0xf7, 0x45, 0x00, 0x8f, 0x81, 0xc9, 0x16, 0xa2, 0x0d, 0xcc, 0x74, 0xee, 0xf2,
- 0xb2, 0xf0,
- ];
- poly1305(key, msg, &mut mac);
- assert_eq!(&mac[..], &expected[..]);
- }
- }
-}
-#[cfg(not(fuzzing))]
-pub use real_poly1305::*;
-
-#[cfg(fuzzing)]
-mod fuzzy_poly1305 {
- #[derive(Clone, Copy)]
- pub struct Poly1305 {
- tag: [u8; 16],
- finalized: bool,
- }
-
- impl Poly1305 {
- pub fn new(key: &[u8]) -> Poly1305 {
- assert_eq!(key.len(), 32);
- let mut poly = Poly1305 { tag: [0; 16], finalized: false };
- poly.tag.copy_from_slice(&key[..16]);
-
- poly
- }
-
- pub fn finish(&mut self) {
- self.finalized = true;
- }
-
- pub fn input(&mut self, _data: &[u8]) {
- assert!(!self.finalized);
- }
-
- pub fn result(&mut self) -> [u8; 16] {
- if !self.finalized {
- self.finish();
- }
- self.tag
- }
- }
-}
-#[cfg(fuzzing)]
-pub use fuzzy_poly1305::*;
Why this scored 12/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.