X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Futil%2Fchacha20.rs;h=865a09fa0401f2d705cf989e9c16d346e7e7f964;hb=bedc2c64fcfe5fa5f85ded630e9ed2eb3c3651eb;hp=3578fb36626f494053decf24c96d4633bdc412b8;hpb=99073c74ddce0d7b7a09eca1a4d938704309eb19;p=rust-lightning diff --git a/lightning/src/util/chacha20.rs b/lightning/src/util/chacha20.rs index 3578fb36..865a09fa 100644 --- a/lightning/src/util/chacha20.rs +++ b/lightning/src/util/chacha20.rs @@ -9,7 +9,7 @@ // You may not use this file except in accordance with one or both of these // licenses. -use io; +use crate::io; #[cfg(not(fuzzing))] mod real_chacha { @@ -21,6 +21,7 @@ mod real_chacha { 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), @@ -30,6 +31,7 @@ mod real_chacha { } 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), @@ -39,23 +41,27 @@ mod real_chacha { } 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 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) + #[inline] + fn shr(self, shr: u8) -> u32x4 { + u32x4(self.0 >> shr, self.1 >> shr, self.2 >> shr, self.3 >> shr) } } - impl ::core::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) + #[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 ( @@ -118,31 +124,25 @@ mod real_chacha { macro_rules! round{ ($state: expr) => {{ $state.a = $state.a + $state.b; - rotate!($state.d, $state.a, S16); + rotate!($state.d, $state.a, 16); $state.c = $state.c + $state.d; - rotate!($state.b, $state.c, S12); + rotate!($state.b, $state.c, 12); $state.a = $state.a + $state.b; - rotate!($state.d, $state.a, S8); + rotate!($state.d, $state.a, 8); $state.c = $state.c + $state.d; - rotate!($state.b, $state.c, S7); + rotate!($state.b, $state.c, 7); }} } macro_rules! rotate { - ($a: expr, $b: expr, $c:expr) => {{ + ($a: expr, $b: expr, $rot: expr) => {{ let v = $a ^ $b; - let r = S32 - $c; + let r = 32 - $rot; let right = v >> r; - $a = (v << $c) ^ right + $a = (v << $rot) ^ right }} } - const S32:u32x4 = u32x4(32, 32, 32, 32); - const S16:u32x4 = u32x4(16, 16, 16, 16); - const S12:u32x4 = u32x4(12, 12, 12, 12); - const S8:u32x4 = u32x4(8, 8, 8, 8); - const S7:u32x4 = u32x4(7, 7, 7, 7); - impl ChaCha20 { pub fn new(key: &[u8], nonce: &[u8]) -> ChaCha20 { assert!(key.len() == 16 || key.len() == 32); @@ -159,6 +159,30 @@ mod real_chacha { 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] ^ bytes[i]; + } + } + fn expand(key: &[u8], nonce: &[u8]) -> ChaChaState { let constant = match key.len() { 16 => b"expand 16-byte k", @@ -290,6 +314,17 @@ mod fuzzy_chacha { [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); + } + + 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); } @@ -316,7 +351,7 @@ impl<'a, R: io::Read> io::Read for ChaChaReader<'a, R> { #[cfg(test)] mod test { - use prelude::*; + use crate::prelude::*; use core::iter::repeat; use super::ChaCha20; @@ -618,4 +653,49 @@ mod test { 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); + } }