X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fchacha20.rs;h=508ecd635c45d007b6fb6de37b57d816146b3750;hb=0dfcacd22c23f69b6526c9c6507d21427a2b7ccb;hp=dd90b20f694587f754e1f6e7fe16ecc13db4892d;hpb=53052234959a3c0a7323a194c351c4ba9b46339b;p=rust-lightning diff --git a/lightning/src/util/chacha20.rs b/lightning/src/util/chacha20.rs index dd90b20f..508ecd63 100644 --- a/lightning/src/util/chacha20.rs +++ b/lightning/src/util/chacha20.rs @@ -2,22 +2,24 @@ // 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 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. +use io; #[cfg(not(feature = "fuzztarget"))] mod real_chacha { - use std::cmp; - use util::byte_utils::{slice_to_le32, le32_to_array}; + use core::cmp; + use core::convert::TryInto; #[derive(Clone, Copy, PartialEq, Eq)] #[allow(non_camel_case_types)] struct u32x4(pub u32, pub u32, pub u32, pub u32); - impl ::std::ops::Add for u32x4 { + impl ::core::ops::Add for u32x4 { type Output = u32x4; fn add(self, rhs: u32x4) -> u32x4 { u32x4(self.0.wrapping_add(rhs.0), @@ -26,7 +28,7 @@ mod real_chacha { self.3.wrapping_add(rhs.3)) } } - impl ::std::ops::Sub for u32x4 { + impl ::core::ops::Sub for u32x4 { type Output = u32x4; fn sub(self, rhs: u32x4) -> u32x4 { u32x4(self.0.wrapping_sub(rhs.0), @@ -35,24 +37,37 @@ mod real_chacha { self.3.wrapping_sub(rhs.3)) } } - impl ::std::ops::BitXor for u32x4 { + impl ::core::ops::BitXor for u32x4 { type Output = u32x4; fn bitxor(self, rhs: u32x4) -> u32x4 { u32x4(self.0 ^ rhs.0, self.1 ^ rhs.1, self.2 ^ rhs.2, self.3 ^ rhs.3) } } - impl ::std::ops::Shr for u32x4 { + impl ::core::ops::Shr for u32x4 { type Output = u32x4; fn shr(self, rhs: u32x4) -> u32x4 { u32x4(self.0 >> rhs.0, self.1 >> rhs.1, self.2 >> rhs.2, self.3 >> rhs.3) } } - impl ::std::ops::Shl for u32x4 { + impl ::core::ops::Shl for u32x4 { type Output = u32x4; fn shl(self, rhs: u32x4) -> u32x4 { u32x4(self.0 << rhs.0, self.1 << rhs.1, self.2 << rhs.2, self.3 << rhs.3) } } + impl u32x4 { + 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 { @@ -65,7 +80,7 @@ mod real_chacha { #[derive(Copy)] pub struct ChaCha20 { state : ChaChaState, - output : [u8; 64], + output : [u8; BLOCK_SIZE], offset : usize, } @@ -95,7 +110,7 @@ mod real_chacha { d1,d2,d3,d4 ]; for i in 0..lens.len() { - $output[i*4..(i+1)*4].copy_from_slice(&le32_to_array(lens[i])); + $output[i*4..(i+1)*4].copy_from_slice(&lens[i].to_le_bytes()); } }} } @@ -133,7 +148,7 @@ mod real_chacha { assert!(key.len() == 16 || key.len() == 32); assert!(nonce.len() == 8 || nonce.len() == 12); - ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; 64], offset: 64 } + ChaCha20{ state: ChaCha20::expand(key, nonce), output: [0u8; BLOCK_SIZE], offset: 64 } } fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState { @@ -143,59 +158,28 @@ mod real_chacha { _ => unreachable!(), }; ChaChaState { - a: u32x4( - slice_to_le32(&constant[0..4]), - slice_to_le32(&constant[4..8]), - slice_to_le32(&constant[8..12]), - slice_to_le32(&constant[12..16]) - ), - b: u32x4( - slice_to_le32(&key[0..4]), - slice_to_le32(&key[4..8]), - slice_to_le32(&key[8..12]), - slice_to_le32(&key[12..16]) - ), + a: u32x4::from_bytes(&constant[0..16]), + b: u32x4::from_bytes(&key[0..16]), c: if key.len() == 16 { - u32x4( - slice_to_le32(&key[0..4]), - slice_to_le32(&key[4..8]), - slice_to_le32(&key[8..12]), - slice_to_le32(&key[12..16]) - ) + u32x4::from_bytes(&key[0..16]) } else { - u32x4( - slice_to_le32(&key[16..20]), - slice_to_le32(&key[20..24]), - slice_to_le32(&key[24..28]), - slice_to_le32(&key[28..32]) - ) + u32x4::from_bytes(&key[16..32]) }, d: if nonce.len() == 16 { - u32x4( - slice_to_le32(&nonce[0..4]), - slice_to_le32(&nonce[4..8]), - slice_to_le32(&nonce[8..12]), - slice_to_le32(&nonce[12..16]) - ) + u32x4::from_bytes(&nonce[0..16]) } else if nonce.len() == 12 { - u32x4( - 0, - slice_to_le32(&nonce[0..4]), - slice_to_le32(&nonce[4..8]), - slice_to_le32(&nonce[8..12]) - ) + let mut nonce4 = [0; 4*4]; + nonce4[4..].copy_from_slice(nonce); + u32x4::from_bytes(&nonce4) } else { - u32x4( - 0, - 0, - slice_to_le32(&nonce[0..4]), - slice_to_le32(&nonce[4..8]) - ) + let mut nonce4 = [0; 4*4]; + nonce4[8..].copy_from_slice(nonce); + u32x4::from_bytes(&nonce4) } } } - // put the the next 64 keystream bytes into self.output + // put the the next BLOCK_SIZE keystream bytes into self.output fn update(&mut self) { let mut state = self.state; @@ -224,6 +208,7 @@ mod real_chacha { 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(); @@ -231,12 +216,12 @@ mod real_chacha { while i < len { // If there is no keystream available in the output buffer, // generate the next block. - if self.offset == 64 { + if self.offset == BLOCK_SIZE { self.update(); } // Process the min(available keystream, remaining input length). - let count = cmp::min(64 - self.offset, len - i); + 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); @@ -248,6 +233,29 @@ mod real_chacha { 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(not(feature = "fuzztarget"))] @@ -267,14 +275,31 @@ mod fuzzy_chacha { 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(feature = "fuzztarget")] pub use self::fuzzy_chacha::ChaCha20; +pub(crate) struct ChaChaReader<'a, R: io::Read> { + pub chacha: &'a mut ChaCha20, + pub read: R, +} +impl<'a, R: io::Read> io::Read for ChaChaReader<'a, R> { + fn read(&mut self, dest: &mut [u8]) -> Result { + let res = self.read.read(dest)?; + if res > 0 { + self.chacha.process_in_place(&mut dest[0..res]); + } + Ok(res) + } +} + #[cfg(test)] mod test { - use std::iter::repeat; + use prelude::*; + use core::iter::repeat; use super::ChaCha20; @@ -284,7 +309,7 @@ mod test { key: [u8; 32], nonce: [u8; 8], keystream: Vec, - }; + } // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 let test_vectors = vec!( TestVector{ @@ -419,7 +444,7 @@ mod test { key: [u8; 32], nonce: [u8; 12], keystream: Vec, - }; + } // taken from http://tools.ietf.org/html/draft-agl-tls-chacha20poly1305-04 let test_vectors = vec!( TestVector{