From 7f7497951f9d6655d1857010dbb505183d8f29d8 Mon Sep 17 00:00:00 2001 From: Abeeujah Date: Sat, 31 Jan 2026 02:37:01 +0100 Subject: [PATCH] dev: Replace local ChaCha20-Poly1305 with external crate Integrated the crate across all modules (Router, PeerStorage, Onion Utils, etc.) and removed the deprecated internal implementation. Updated test vectors to align with the new 12-byte nonce construction and ensured SCID encryption remains consistent. --- lightning/Cargo.toml | 1 + lightning/src/crypto/chacha20.rs | 638 -------------------- lightning/src/crypto/chacha20poly1305rfc.rs | 157 ----- lightning/src/crypto/mod.rs | 3 - lightning/src/crypto/poly1305.rs | 434 ------------- lightning/src/crypto/streams.rs | 149 +++-- lightning/src/ln/inbound_payment.rs | 40 +- lightning/src/ln/onion_utils.rs | 47 +- lightning/src/ln/our_peer_storage.rs | 16 +- lightning/src/ln/peer_channel_encryptor.rs | 27 +- lightning/src/routing/router.rs | 14 +- lightning/src/sign/mod.rs | 11 +- lightning/src/util/scid_utils.rs | 12 +- 13 files changed, 199 insertions(+), 1350 deletions(-) delete mode 100644 lightning/src/crypto/chacha20.rs delete mode 100644 lightning/src/crypto/chacha20poly1305rfc.rs delete mode 100644 lightning/src/crypto/poly1305.rs diff --git a/lightning/Cargo.toml b/lightning/Cargo.toml index b3b597029da..aa0512dfe36 100644 --- a/lightning/Cargo.toml +++ b/lightning/Cargo.toml @@ -41,6 +41,7 @@ lightning-macros = { version = "0.2", path = "../lightning-macros" } bech32 = { version = "0.11.0", default-features = false } bitcoin = { version = "0.32.4", default-features = false, features = ["secp-recovery"] } +chacha20-poly1305 = { version = "0.1.2", default-features = false } dnssec-prover = { version = "0.6", default-features = false } hashbrown = { version = "0.13", default-features = false } possiblyrandom = { version = "0.2", path = "../possiblyrandom", default-features = false } diff --git a/lightning/src/crypto/chacha20.rs b/lightning/src/crypto/chacha20.rs deleted file mode 100644 index 5b0c16c933f..00000000000 --- a/lightning/src/crypto/chacha20.rs +++ /dev/null @@ -1,638 +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 or the MIT license -// , 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 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 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); - } - - 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, - } - // 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 = repeat(0).take(tv.keystream.len()).collect(); - let mut output: Vec = 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, - } - // 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 = repeat(0).take(tv.keystream.len()).collect(); - let mut output: Vec = 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 839fad9ce6c..00000000000 --- 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 or the MIT license -// , 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 478918a49a8..73d7ad64685 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 a71e39ed773..00000000000 --- a/lightning/src/crypto/poly1305.rs +++ /dev/null @@ -1,434 +0,0 @@ -// 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. - -// 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 = repeat(i as u8).take(32).collect(); - let msg: Vec = 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::*; diff --git a/lightning/src/crypto/streams.rs b/lightning/src/crypto/streams.rs index c406e933bc9..8df554ef29c 100644 --- a/lightning/src/crypto/streams.rs +++ b/lightning/src/crypto/streams.rs @@ -1,7 +1,4 @@ -use crate::crypto::chacha20::ChaCha20; -use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC; use crate::crypto::fixed_time_eq; -use crate::crypto::poly1305::Poly1305; use crate::io::{self, Read, Write}; use crate::ln::msgs::DecodeError; @@ -10,6 +7,10 @@ use crate::util::ser::{ }; use alloc::vec::Vec; +use chacha20_poly1305::{ + chacha20::{ChaCha20, Key, Nonce}, + poly1305::Poly1305, +}; pub(crate) struct ChaChaReader<'a, R: io::Read> { pub chacha: &'a mut ChaCha20, @@ -19,7 +20,7 @@ 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]); + self.chacha.apply_keystream(&mut dest[..res]); } Ok(res) } @@ -42,11 +43,20 @@ impl<'a, W: Writeable> ChaChaPolyWriteAdapter<'a, W> { impl<'a, T: Writeable> Writeable for ChaChaPolyWriteAdapter<'a, T> { // Simultaneously write and encrypt Self::writeable. fn write(&self, w: &mut W) -> Result<(), io::Error> { - let mut chacha = ChaCha20Poly1305RFC::new(&self.rho, &[0; 12], &[]); - let mut chacha_stream = ChaChaPolyWriter { chacha: &mut chacha, write: w }; + let mut chacha = ChaCha20::new(Key::new(self.rho), Nonce::new([0; 12]), 0); + let mut mac_key = [0u8; 64]; + chacha.apply_keystream(&mut mac_key); + + #[cfg(not(fuzzing))] + let mac = Poly1305::new(mac_key[..32].try_into().unwrap()); + #[cfg(fuzzing)] + let mac = Poly1305::new(self.rho); + + let mut chacha_stream = + ChaChaPolyWriter { chacha: &mut chacha, poly: mac, write_len: 0, write: w }; self.writeable.write(&mut chacha_stream)?; - let mut tag = [0 as u8; 16]; - chacha.finish_and_get_tag(&mut tag); + + let tag = chacha_stream.finish_and_get_tag(); tag.write(w)?; Ok(()) @@ -62,12 +72,12 @@ impl<'a, T: Writeable> Writeable for ChaChaPolyWriteAdapter<'a, T> { pub(crate) fn chachapoly_encrypt_with_swapped_aad( mut plaintext: Vec, key: [u8; 32], aad: [u8; 32], ) -> Vec { - let mut chacha = ChaCha20::new(&key[..], &[0; 12]); + let mut chacha = ChaCha20::new(Key::new(key), Nonce::new([0; 12]), 0); let mut mac_key = [0u8; 64]; - chacha.process_in_place(&mut mac_key); + chacha.apply_keystream(&mut mac_key); - let mut mac = Poly1305::new(&mac_key[..32]); - chacha.process_in_place(&mut plaintext[..]); + let mut mac = Poly1305::new(mac_key[..32].try_into().unwrap()); + chacha.apply_keystream(&mut plaintext[..]); mac.input(&plaintext[..]); if plaintext.len() % 16 != 0 { @@ -80,7 +90,7 @@ pub(crate) fn chachapoly_encrypt_with_swapped_aad( mac.input(&(plaintext.len() as u64).to_le_bytes()); mac.input(&32u64.to_le_bytes()); - plaintext.extend_from_slice(&mac.result()); + plaintext.extend_from_slice(&mac.tag()); plaintext } @@ -93,7 +103,7 @@ pub(crate) fn chachapoly_encrypt_with_swapped_aad( /// /// Note that we do *not* use the provided AAD as the standard ChaCha20Poly1305 AAD as that would /// require placing it first and prevent us from avoiding redundant Poly1305 rounds. Instead, the -/// ChaCha20Poly1305 MAC check is tweaked to move the AAD to *after* the the contents being +/// ChaCha20Poly1305 MAC check is tweaked to move the AAD to *after* the contents being /// checked, effectively treating the contents as the AAD for the AAD-containing MAC but behaving /// like classic ChaCha20Poly1305 for the non-AAD-containing MAC. pub(crate) struct ChaChaDualPolyReadAdapter { @@ -113,25 +123,33 @@ impl LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea } let (key, aad) = params; - let mut chacha = ChaCha20::new(&key[..], &[0; 12]); + let mut chacha = ChaCha20::new(Key::new(key), Nonce::new([0; 12]), 0); let mut mac_key = [0u8; 64]; - chacha.process_in_place(&mut mac_key); + chacha.apply_keystream(&mut mac_key); #[cfg(not(fuzzing))] - let mut mac = Poly1305::new(&mac_key[..32]); + let mut mac = Poly1305::new(mac_key[..32].try_into().unwrap()); + #[cfg(not(fuzzing))] + let mut mac_aad = Poly1305::new(mac_key[..32].try_into().unwrap()); + #[cfg(fuzzing)] + let mut mac = Poly1305::new(key); #[cfg(fuzzing)] - let mut mac = Poly1305::new(&key); + let mut mac_aad = Poly1305::new(key); let decrypted_len = r.remaining_bytes() - 16; let s = FixedLengthReader::new(r, decrypted_len); - let mut chacha_stream = - ChaChaDualPolyReader { chacha: &mut chacha, poly: &mut mac, read_len: 0, read: s }; + let mut chacha_stream = ChaChaDualPolyReader { + chacha: &mut chacha, + poly: &mut mac, + poly_aad: &mut mac_aad, + read_len: 0, + read: s, + }; let readable: T = Readable::read(&mut chacha_stream)?; while chacha_stream.read.bytes_remain() { let mut buf = [0; 256]; if chacha_stream.read(&mut buf)? == 0 { - // Reached EOF return Err(DecodeError::ShortRead); } } @@ -139,11 +157,11 @@ impl LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea let read_len = chacha_stream.read_len; if read_len % 16 != 0 { - mac.input(&[0; 16][0..16 - (read_len % 16)]); + let padding = &[0; 16][0..16 - (read_len % 16)]; + mac.input(padding); + mac_aad.input(padding); } - let mut mac_aad = mac; - mac_aad.input(&aad[..]); // Note that we don't need to pad the AAD since its a multiple of 16 bytes @@ -155,11 +173,11 @@ impl LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea mac.input(&0u64.to_le_bytes()); mac.input(&(read_len as u64).to_le_bytes()); - let mut tag = [0 as u8; 16]; + let mut tag = [0u8; 16]; r.read_exact(&mut tag)?; - if fixed_time_eq(&mac.result(), &tag) { + if fixed_time_eq(&mac.tag(), &tag) { Ok(Self { readable, used_aad: false }) - } else if fixed_time_eq(&mac_aad.result(), &tag) { + } else if fixed_time_eq(&mac_aad.tag(), &tag) { Ok(Self { readable, used_aad: true }) } else { return Err(DecodeError::InvalidValue); @@ -170,6 +188,7 @@ impl LengthReadableArgs<([u8; 32], [u8; 32])> for ChaChaDualPolyRea struct ChaChaDualPolyReader<'a, R: Read> { chacha: &'a mut ChaCha20, poly: &'a mut Poly1305, + poly_aad: &'a mut Poly1305, read_len: usize, pub read: R, } @@ -177,12 +196,13 @@ struct ChaChaDualPolyReader<'a, R: Read> { impl<'a, R: Read> Read for ChaChaDualPolyReader<'a, R> { // Decrypts bytes from Self::read into `dest`. // After all reads complete, the caller must compare the expected tag with - // the result of `Poly1305::result()`. + // the result of `Poly1305::tag()` fn read(&mut self, dest: &mut [u8]) -> Result { let res = self.read.read(dest)?; if res > 0 { - self.poly.input(&dest[0..res]); - self.chacha.process_in_place(&mut dest[0..res]); + self.poly.input(&dest[..res]); + self.poly_aad.input(&dest[..res]); + self.chacha.apply_keystream(&mut dest[..res]); self.read_len += res; } Ok(res) @@ -204,19 +224,36 @@ impl LengthReadableArgs<[u8; 32]> for ChaChaPolyReadAdapter { return Err(DecodeError::InvalidValue); } - let mut chacha = ChaCha20Poly1305RFC::new(&secret, &[0; 12], &[]); + let mut chacha = ChaCha20::new(Key::new(secret), Nonce::new([0; 12]), 0); + let mut mac_key = [0u8; 64]; + chacha.apply_keystream(&mut mac_key); + + #[cfg(not(fuzzing))] + let mut mac = Poly1305::new(mac_key[..32].try_into().unwrap()); + #[cfg(fuzzing)] + let mut mac = Poly1305::new(secret); + let decrypted_len = r.remaining_bytes() - 16; let s = FixedLengthReader::new(r, decrypted_len); - let mut chacha_stream = ChaChaPolyReader { chacha: &mut chacha, read: s }; + let mut chacha_stream = ChaChaPolyReader::new(&mut chacha, &mut mac, s); let readable: T = Readable::read(&mut chacha_stream)?; while chacha_stream.read.bytes_remain() { let mut buf = [0; 256]; chacha_stream.read(&mut buf)?; } - let mut tag = [0 as u8; 16]; + let read_len = chacha_stream.read_len(); + drop(chacha_stream); + + if read_len % 16 != 0 { + mac.input(&[0; 16][0..16 - (read_len % 16)]); + } + mac.input(&0u64.to_le_bytes()); + mac.input(&(read_len as u64).to_le_bytes()); + + let mut tag = [0u8; 16]; r.read_exact(&mut tag)?; - if !chacha.finish_and_check_tag(&tag) { + if !fixed_time_eq(&mac.tag(), &tag) { return Err(DecodeError::InvalidValue); } @@ -224,20 +261,32 @@ impl LengthReadableArgs<[u8; 32]> for ChaChaPolyReadAdapter { } } -/// Enables simultaneously reading and decrypting a ChaCha20Poly1305RFC stream from a std::io::Read. +/// Enables simultaneously reading and decrypting a ChaCha20Poly1305 stream from a std::io::Read. struct ChaChaPolyReader<'a, R: Read> { - pub chacha: &'a mut ChaCha20Poly1305RFC, + chacha: &'a mut ChaCha20, + poly: &'a mut Poly1305, + read_len: usize, pub read: R, } +impl<'a, R: Read> ChaChaPolyReader<'a, R> { + fn new(chacha: &'a mut ChaCha20, poly: &'a mut Poly1305, read: R) -> Self { + Self { chacha, poly, read_len: 0, read } + } + + fn read_len(&self) -> usize { + self.read_len + } +} + impl<'a, R: Read> Read for ChaChaPolyReader<'a, R> { // Decrypt bytes from Self::read into `dest`. - // `ChaCha20Poly1305RFC::finish_and_check_tag` must be called to check the tag after all reads - // complete. fn read(&mut self, dest: &mut [u8]) -> Result { let res = self.read.read(dest)?; if res > 0 { - self.chacha.decrypt_in_place(&mut dest[0..res]); + self.poly.input(&dest[..res]); + self.chacha.apply_keystream(&mut dest[..res]); + self.read_len += res; } Ok(res) } @@ -245,14 +294,26 @@ impl<'a, R: Read> Read for ChaChaPolyReader<'a, R> { /// Enables simultaneously writing and encrypting a byte stream into a Writer. struct ChaChaPolyWriter<'a, W: Writer> { - pub chacha: &'a mut ChaCha20Poly1305RFC, + chacha: &'a mut ChaCha20, + poly: Poly1305, + write_len: usize, pub write: &'a mut W, } +impl<'a, W: Writer> ChaChaPolyWriter<'a, W> { + /// Finish encrypting and return the 16-byte authentication tag. + fn finish_and_get_tag(mut self) -> [u8; 16] { + if self.write_len % 16 != 0 { + self.poly.input(&[0; 16][0..16 - (self.write_len % 16)]); + } + self.poly.input(&0u64.to_le_bytes()); + self.poly.input(&(self.write_len as u64).to_le_bytes()); + self.poly.tag() + } +} + impl<'a, W: Writer> Writer for ChaChaPolyWriter<'a, W> { // Encrypt then write bytes from `src` into Self::write. - // `ChaCha20Poly1305RFC::finish_and_get_tag` can be called to retrieve the tag after all writes - // complete. fn write_all(&mut self, src: &[u8]) -> Result<(), io::Error> { let mut src_idx = 0; while src_idx < src.len() { @@ -260,8 +321,10 @@ impl<'a, W: Writer> Writer for ChaChaPolyWriter<'a, W> { let bytes_written = (&mut write_buffer[..]) .write(&src[src_idx..]) .expect("In-memory writes can't fail"); - self.chacha.encrypt_in_place(&mut write_buffer[..bytes_written]); + self.chacha.apply_keystream(&mut write_buffer[..bytes_written]); + self.poly.input(&write_buffer[..bytes_written]); self.write.write_all(&write_buffer[..bytes_written])?; + self.write_len += bytes_written; src_idx += bytes_written; } Ok(()) diff --git a/lightning/src/ln/inbound_payment.rs b/lightning/src/ln/inbound_payment.rs index 51f8b7bfce9..03fdb41acaa 100644 --- a/lightning/src/ln/inbound_payment.rs +++ b/lightning/src/ln/inbound_payment.rs @@ -13,12 +13,12 @@ use bitcoin::hashes::cmp::fixed_time_eq; use bitcoin::hashes::hmac::{Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::{Hash, HashEngine}; +use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce}; -use crate::crypto::chacha20::ChaCha20; use crate::crypto::utils::hkdf_extract_expand_6x; use crate::ln::msgs; use crate::ln::msgs::MAX_VALUE_MSAT; -use crate::offers::nonce::Nonce; +use crate::offers::nonce::Nonce as LocalNonce; use crate::sign::EntropySource; use crate::types::payment::{PaymentHash, PaymentPreimage, PaymentSecret}; use crate::util::errors::APIError; @@ -90,8 +90,13 @@ impl ExpandedKey { /// Encrypts or decrypts the given `bytes`. Used for data included in an offer message's /// metadata (e.g., payment id). - pub(crate) fn crypt_for_offer(&self, mut bytes: [u8; 32], nonce: Nonce) -> [u8; 32] { - ChaCha20::encrypt_single_block_in_place(&self.offers_encryption_key, &nonce.0, &mut bytes); + pub(crate) fn crypt_for_offer(&self, mut bytes: [u8; 32], nonce: LocalNonce) -> [u8; 32] { + ChaCha20::new_from_block( + Key::new(self.offers_encryption_key), + Nonce::new(nonce.0[4..].try_into().unwrap()), + u32::from_le_bytes(nonce.0[..4].try_into().unwrap()), + ) + .apply_keystream(&mut bytes); bytes } } @@ -295,12 +300,14 @@ fn construct_payment_secret( let (iv_slice, encrypted_metadata_slice) = payment_secret_bytes.split_at_mut(IV_LEN); iv_slice.copy_from_slice(iv_bytes); - ChaCha20::encrypt_single_block( - metadata_key, - iv_bytes, - encrypted_metadata_slice, - metadata_bytes, - ); + encrypted_metadata_slice.copy_from_slice(metadata_bytes); + ChaCha20::new_from_block( + Key::new(*metadata_key), + Nonce::new(iv_bytes[4..].try_into().unwrap()), + u32::from_le_bytes(iv_bytes[..4].try_into().unwrap()), + ) + .apply_keystream(encrypted_metadata_slice); + PaymentSecret(payment_secret_bytes) } @@ -479,12 +486,13 @@ fn decrypt_metadata( iv_bytes.copy_from_slice(iv_slice); let mut metadata_bytes: [u8; METADATA_LEN] = [0; METADATA_LEN]; - ChaCha20::encrypt_single_block( - &keys.metadata_key, - &iv_bytes, - &mut metadata_bytes, - encrypted_metadata_bytes, - ); + metadata_bytes.copy_from_slice(encrypted_metadata_bytes); + ChaCha20::new_from_block( + Key::new(keys.metadata_key), + Nonce::new(iv_bytes[4..].try_into().unwrap()), + u32::from_le_bytes(iv_bytes[..4].try_into().unwrap()), + ) + .apply_keystream(&mut metadata_bytes); (iv_bytes, metadata_bytes) } diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index fcfac7c5e63..125b49d2895 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -11,7 +11,6 @@ use super::msgs::OnionErrorPacket; use crate::blinded_path::BlindedHop; -use crate::crypto::chacha20::ChaCha20; use crate::crypto::streams::ChaChaReader; use crate::events::HTLCHandlingFailureReason; use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS; @@ -38,6 +37,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::secp256k1; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey}; +use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce}; use crate::io::{Cursor, Read}; @@ -707,8 +707,8 @@ pub(super) fn construct_onion_packet( ) -> Result { let mut packet_data = [0; ONION_DATA_LEN]; - let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]); - chacha.process(&[0; ONION_DATA_LEN], &mut packet_data); + let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0); + chacha.apply_keystream(&mut packet_data); debug_assert_eq!(payloads.len(), onion_keys.len(), "Payloads and keys must have equal lengths"); @@ -745,8 +745,8 @@ pub(super) fn construct_trampoline_onion_packet( } let mut packet_data = vec![0u8; packet_length]; - let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]); - chacha.process_in_place(&mut packet_data); + let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0); + chacha.apply_keystream(&mut packet_data); construct_onion_packet_with_init_noise::<_, _>( payloads, @@ -765,8 +765,8 @@ pub(super) fn construct_onion_packet_with_writable_hopdata( ) -> Result { let mut packet_data = [0; ONION_DATA_LEN]; - let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]); - chacha.process(&[0; ONION_DATA_LEN], &mut packet_data); + let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0); + chacha.apply_keystream(&mut packet_data); let packet = FixedSizeOnionPacket(packet_data); construct_onion_packet_with_init_noise::<_, _>( @@ -804,8 +804,8 @@ pub(crate) fn construct_onion_message_packet Result { let mut packet_data = vec![0; packet_data_len]; - let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]); - chacha.process_in_place(&mut packet_data); + let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0); + chacha.apply_keystream(&mut packet_data); construct_onion_packet_with_init_noise::<_, _>(payloads, onion_keys, packet_data, None) } @@ -821,12 +821,9 @@ fn construct_onion_packet_with_init_noise( let mut pos = 0; for (i, (payload, keys)) in payloads.iter().zip(onion_keys.iter()).enumerate() { - let mut chacha = ChaCha20::new(&keys.rho, &[0u8; 8]); - // TODO: Batch this. - for _ in 0..(packet_data.len() - pos) { - let mut dummy = [0; 1]; - chacha.process_in_place(&mut dummy); // We don't have a seek function :( - } + // Seek to the position in the keystream where we want to start encrypting + let seek_pos = (packet_data.len() - pos) as u32; + let mut chacha = ChaCha20::new(Key::new(keys.rho), Nonce::new([0; 12]), seek_pos); let mut payload_len = LengthCalculatingWriter(0); payload.write(&mut payload_len).expect("Failed to calculate length"); @@ -840,7 +837,7 @@ fn construct_onion_packet_with_init_noise( } res.resize(pos, 0u8); - chacha.process_in_place(&mut res); + chacha.apply_keystream(&mut res); } res }; @@ -855,8 +852,8 @@ fn construct_onion_packet_with_init_noise( packet_data[0..payload_len.0].copy_from_slice(&payload.encode()[..]); packet_data[payload_len.0..(payload_len.0 + 32)].copy_from_slice(&hmac_res); - let mut chacha = ChaCha20::new(&keys.rho, &[0u8; 8]); - chacha.process_in_place(packet_data); + let mut chacha = ChaCha20::new(Key::new(keys.rho), Nonce::new([0; 12]), 0); + chacha.apply_keystream(packet_data); if i == 0 { let stop_index = packet_data.len(); @@ -878,8 +875,8 @@ fn construct_onion_packet_with_init_noise( /// Encrypts/decrypts a failure packet. fn crypt_failure_packet(shared_secret: &[u8], packet: &mut OnionErrorPacket) { let ammag = gen_ammag_from_shared_secret(&shared_secret); - let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]); - chacha.process_in_place(&mut packet.data); + let mut chacha = ChaCha20::new(Key::new(ammag), Nonce::new([0; 12]), 0); + chacha.apply_keystream(&mut packet.data); if let Some(ref mut attribution_data) = packet.attribution_data { attribution_data.crypt(shared_secret); @@ -2700,7 +2697,7 @@ fn decode_next_hop, N: NextPacketBytes>( }); } - let mut chacha = ChaCha20::new(&rho, &[0u8; 8]); + let mut chacha = ChaCha20::new(Key::new(rho), Nonce::new([0; 12]), 0); let mut chacha_stream = ChaChaReader { chacha: &mut chacha, read: Cursor::new(&hop_data[..]) }; match R::read(&mut chacha_stream, read_args) { Err(err) => { @@ -2765,7 +2762,7 @@ fn decode_next_hop, N: NextPacketBytes>( } // Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we // fill the onion hop data we'll forward to our next-hop peer. - chacha_stream.chacha.process_in_place(&mut new_packet_bytes.as_mut()[read_pos..]); + chacha_stream.chacha.apply_keystream(&mut new_packet_bytes.as_mut()[read_pos..]); return Ok((msg, Some((hmac, new_packet_bytes)))); // This packet needs forwarding } }, @@ -2807,9 +2804,9 @@ impl AttributionData { /// Encrypts or decrypts the attribution data using the provided shared secret. pub(crate) fn crypt(&mut self, shared_secret: &[u8]) { let ammagext = gen_ammagext_from_shared_secret(&shared_secret); - let mut chacha = ChaCha20::new(&ammagext, &[0u8; 8]); - chacha.process_in_place(&mut self.hold_times); - chacha.process_in_place(&mut self.hmacs); + let mut chacha = ChaCha20::new(Key::new(ammagext), Nonce::new([0; 12]), 0); + chacha.apply_keystream(&mut self.hold_times); + chacha.apply_keystream(&mut self.hmacs); } /// Adds the current node's HMACs for all possible positions to this packet. diff --git a/lightning/src/ln/our_peer_storage.rs b/lightning/src/ln/our_peer_storage.rs index ab0e9783ffa..7fe37eaddc0 100644 --- a/lightning/src/ln/our_peer_storage.rs +++ b/lightning/src/ln/our_peer_storage.rs @@ -14,18 +14,18 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine}; use bitcoin::secp256k1::PublicKey; +use chacha20_poly1305::{ChaCha20Poly1305, Key, Nonce}; use crate::ln::types::ChannelId; use crate::sign::PeerStorageKey; -use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC; use crate::prelude::*; /// [`DecryptedOurPeerStorage`] is used to store serialised channel information that allows for the creation of a /// `peer_storage` backup. /// /// This structure is designed to serialize channel data for backup and supports encryption -/// using `ChaCha20Poly1305RFC` for transmission. +/// using `ChaCha20Poly1305` for transmission. /// /// # Key Methods /// - [`DecryptedOurPeerStorage::new`]: Returns [`DecryptedOurPeerStorage`] with the given data. @@ -66,9 +66,8 @@ impl DecryptedOurPeerStorage { let plaintext_len = data.len(); let nonce = derive_nonce(key, random_bytes); - let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b""); - let mut tag = [0; 16]; - chacha.encrypt_full_message_in_place(&mut data[0..plaintext_len], &mut tag); + let chacha = ChaCha20Poly1305::new(Key::new(key.inner), Nonce::new(nonce)); + let tag = chacha.encrypt(&mut data[0..plaintext_len], None); data.extend_from_slice(&tag); @@ -122,9 +121,10 @@ impl EncryptedOurPeerStorage { let nonce = derive_nonce(key, random_bytes); - let mut chacha = ChaCha20Poly1305RFC::new(&key.inner, &nonce, b""); - - if chacha.check_decrypt_in_place(encrypted_data, tag).is_err() { + let chacha = ChaCha20Poly1305::new(Key::new(key.inner), Nonce::new(nonce)); + let mut decrypt_tag = [0; 16]; + decrypt_tag.copy_from_slice(tag); + if chacha.decrypt(encrypted_data, decrypt_tag, None).is_err() { return Err(()); } diff --git a/lightning/src/ln/peer_channel_encryptor.rs b/lightning/src/ln/peer_channel_encryptor.rs index 5554c5a8c19..1ee4721c110 100644 --- a/lightning/src/ln/peer_channel_encryptor.rs +++ b/lightning/src/ln/peer_channel_encryptor.rs @@ -25,8 +25,8 @@ use bitcoin::secp256k1; use bitcoin::secp256k1::ecdh::SharedSecret; use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::{PublicKey, SecretKey}; +use chacha20_poly1305::{ChaCha20Poly1305, Key, Nonce}; -use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC; use crate::crypto::utils::hkdf_extract_expand_twice; use crate::util::ser::VecWriter; @@ -150,10 +150,10 @@ impl PeerChannelEncryptor { fn encrypt_with_ad(res: &mut [u8], n: u64, key: &[u8; 32], h: &[u8], plaintext: &[u8]) { let mut nonce = [0; 12]; nonce[4..].copy_from_slice(&n.to_le_bytes()[..]); + res[0..plaintext.len()].copy_from_slice(plaintext); - let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h); - let mut tag = [0; 16]; - chacha.encrypt(plaintext, &mut res[0..plaintext.len()], &mut tag); + let chacha = ChaCha20Poly1305::new(Key::new(*key), Nonce::new(nonce)); + let tag = chacha.encrypt(&mut res[0..plaintext.len()], Some(h)); res[plaintext.len()..].copy_from_slice(&tag); } @@ -166,9 +166,8 @@ impl PeerChannelEncryptor { let mut nonce = [0; 12]; nonce[4..].copy_from_slice(&n.to_le_bytes()[..]); - let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h); - let mut tag = [0; 16]; - chacha.encrypt_full_message_in_place(&mut res[offset..], &mut tag); + let chacha = ChaCha20Poly1305::new(Key::new(*key), Nonce::new(nonce)); + let tag = chacha.encrypt(&mut res[offset..], Some(h)); res.extend_from_slice(&tag); } @@ -178,9 +177,11 @@ impl PeerChannelEncryptor { let mut nonce = [0; 12]; nonce[4..].copy_from_slice(&n.to_le_bytes()[..]); - let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h); + let chacha = ChaCha20Poly1305::new(Key::new(*key), Nonce::new(nonce)); let (inout, tag) = inout.split_at_mut(inout.len() - 16); - if chacha.check_decrypt_in_place(inout, tag).is_err() { + let mut decrypt_tag = [0; 16]; + decrypt_tag.copy_from_slice(tag); + if chacha.decrypt(inout, decrypt_tag, Some(h)).is_err() { return Err(LightningError { err: "Bad MAC".to_owned(), action: msgs::ErrorAction::DisconnectPeer { msg: None }, @@ -197,9 +198,13 @@ impl PeerChannelEncryptor { nonce[4..].copy_from_slice(&n.to_le_bytes()[..]); let (data, hmac) = cyphertext.split_at(cyphertext.len() - 16); + let mut tag = [0; 16]; + tag.copy_from_slice(hmac); + res.copy_from_slice(data); + let mac_check = - ChaCha20Poly1305RFC::new(key, &nonce, h).variable_time_decrypt(&data, res, hmac); - mac_check.map_err(|()| LightningError { + ChaCha20Poly1305::new(Key::new(*key), Nonce::new(nonce)).decrypt(res, tag, Some(h)); + mac_check.map_err(|_| LightningError { err: "Bad MAC".to_owned(), action: msgs::ErrorAction::DisconnectPeer { msg: None }, }) diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 42d569415af..6cd100919f4 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -10,6 +10,7 @@ //! The router finds paths within a [`NetworkGraph`] for a payment. use bitcoin::secp256k1::{self, PublicKey, Secp256k1}; +use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce}; use lightning_invoice::Bolt11Invoice; use crate::blinded_path::payment::{ @@ -17,7 +18,6 @@ use crate::blinded_path::payment::{ PaymentRelay, ReceiveTlvs, }; use crate::blinded_path::{BlindedHop, Direction, IntroductionNode}; -use crate::crypto::chacha20::ChaCha20; use crate::ln::channel_state::ChannelDetails; use crate::ln::channelmanager::{PaymentId, RecipientOnionFields, MIN_FINAL_CLTV_EXPIRY_DELTA}; use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT}; @@ -3821,11 +3821,11 @@ fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters, } // Init PRNG with the path-dependant nonce, which is static for private paths. - let mut prng = ChaCha20::new(random_seed_bytes, &path_nonce); + let mut prng = ChaCha20::new(Key::new(*random_seed_bytes), Nonce::new(path_nonce), 0); let mut random_path_bytes = [0u8; ::core::mem::size_of::()]; // Pick a random path length in [1 .. 3] - prng.process_in_place(&mut random_path_bytes); + prng.apply_keystream(&mut random_path_bytes); let random_walk_length = usize::from_be_bytes(random_path_bytes).wrapping_rem(3).wrapping_add(1); for random_hop in 0..random_walk_length { @@ -3836,7 +3836,7 @@ fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters, if let Some(cur_node_id) = cur_hop { if let Some(cur_node) = network_nodes.get(&cur_node_id) { // Randomly choose the next unvisited hop. - prng.process_in_place(&mut random_path_bytes); + prng.apply_keystream(&mut random_path_bytes); if let Some(random_channel) = usize::from_be_bytes(random_path_bytes) .checked_rem(cur_node.channels.len()) .and_then(|index| cur_node.channels.get(index)) @@ -3957,7 +3957,6 @@ mod tests { use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath}; use crate::blinded_path::BlindedHop; use crate::chain::transaction::OutPoint; - use crate::crypto::chacha20::ChaCha20; use crate::ln::chan_utils::make_funding_redeemscript; use crate::ln::channel_state::{ChannelCounterparty, ChannelDetails, ChannelShutdownState}; use crate::ln::channelmanager; @@ -3994,6 +3993,7 @@ mod tests { use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::{PublicKey, SecretKey}; use bitcoin::transaction::TxOut; + use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce}; use crate::io::Cursor; use crate::prelude::*; @@ -7585,10 +7585,10 @@ mod tests { for p in route.paths { // 1. Select random observation point - let mut prng = ChaCha20::new(&random_seed_bytes, &[0u8; 12]); + let mut prng = ChaCha20::new(Key::new(random_seed_bytes), Nonce::new([0u8; 12]), 0); let mut random_bytes = [0u8; ::core::mem::size_of::()]; - prng.process_in_place(&mut random_bytes); + prng.apply_keystream(&mut random_bytes); let random_path_index = usize::from_be_bytes(random_bytes).wrapping_rem(p.hops.len()); let observation_point = NodeId::from_pubkey(&p.hops.get(random_path_index).unwrap().pubkey); diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 84bfbb902ea..9d239feedf6 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -34,6 +34,7 @@ use bitcoin::secp256k1::schnorr; use bitcoin::secp256k1::All; use bitcoin::secp256k1::{Keypair, PublicKey, Scalar, Secp256k1, SecretKey, Signing}; use bitcoin::{secp256k1, Psbt, Sequence, Txid, WPubkeyHash, Witness}; +use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce}; use lightning_invoice::RawBolt11Invoice; @@ -62,7 +63,6 @@ use crate::util::async_poll::MaybeSend; use crate::util::ser::{ReadableArgs, Writeable}; use crate::util::transaction_utils; -use crate::crypto::chacha20::ChaCha20; use crate::prelude::*; use crate::sign::ecdsa::EcdsaChannelSigner; #[cfg(taproot)] @@ -2791,7 +2791,14 @@ impl EntropySource for RandomBytes { let index = self.index.next(); let mut nonce = [0u8; 16]; nonce[..8].copy_from_slice(&index.to_be_bytes()); - ChaCha20::get_single_block(&self.seed, &nonce) + let mut chacha_bytes = [0; 32]; + ChaCha20::new( + Key::new(self.seed), + Nonce::new(nonce[4..].try_into().unwrap()), + u32::from_le_bytes(nonce[..4].try_into().unwrap()), + ) + .apply_keystream(&mut chacha_bytes); + chacha_bytes } } diff --git a/lightning/src/util/scid_utils.rs b/lightning/src/util/scid_utils.rs index d57c529a41a..ec8884a0c08 100644 --- a/lightning/src/util/scid_utils.rs +++ b/lightning/src/util/scid_utils.rs @@ -73,12 +73,12 @@ pub fn scid_from_parts( /// 3) payments intended to be intercepted will route using a fake scid (this is typically used so /// the forwarding node can open a JIT channel to the next hop) pub(crate) mod fake_scid { - use crate::crypto::chacha20::ChaCha20; use crate::prelude::*; use crate::sign::EntropySource; use crate::util::scid_utils; use bitcoin::constants::ChainHash; use bitcoin::Network; + use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce}; const TEST_SEGWIT_ACTIVATION_HEIGHT: u32 = 1; const MAINNET_SEGWIT_ACTIVATION_HEIGHT: u32 = 481_824; @@ -150,15 +150,15 @@ pub(crate) mod fake_scid { fn get_encrypted_vout( &self, block_height: u32, tx_index: u32, fake_scid_rand_bytes: &[u8; 32], ) -> u8 { - let mut salt = [0 as u8; 8]; + let mut salt = [0 as u8; 12]; let block_height_bytes = block_height.to_be_bytes(); salt[0..4].copy_from_slice(&block_height_bytes); let tx_index_bytes = tx_index.to_be_bytes(); salt[4..8].copy_from_slice(&tx_index_bytes); - let mut chacha = ChaCha20::new(fake_scid_rand_bytes, &salt); + let mut chacha = ChaCha20::new(Key::new(*fake_scid_rand_bytes), Nonce::new(salt), 0); let mut vout_byte = [*self as u8]; - chacha.process_in_place(&mut vout_byte); + chacha.apply_keystream(&mut vout_byte); vout_byte[0] & NAMESPACE_ID_BITMASK } } @@ -242,7 +242,7 @@ pub(crate) mod fake_scid { let namespace = Namespace::Phantom; let fake_scid_rand_bytes = [0; 32]; let testnet_genesis = ChainHash::using_genesis_block(Network::Testnet); - let valid_encrypted_vout = namespace.get_encrypted_vout(0, 0, &fake_scid_rand_bytes); + let valid_encrypted_vout = namespace.get_encrypted_vout(1, 0, &fake_scid_rand_bytes); let valid_fake_scid = scid_utils::scid_from_parts(1, 0, valid_encrypted_vout as u64).unwrap(); assert!(is_valid_phantom(&fake_scid_rand_bytes, valid_fake_scid, &testnet_genesis)); @@ -255,7 +255,7 @@ pub(crate) mod fake_scid { let namespace = Namespace::Intercept; let fake_scid_rand_bytes = [0; 32]; let testnet_genesis = ChainHash::using_genesis_block(Network::Testnet); - let valid_encrypted_vout = namespace.get_encrypted_vout(0, 0, &fake_scid_rand_bytes); + let valid_encrypted_vout = namespace.get_encrypted_vout(1, 0, &fake_scid_rand_bytes); let valid_fake_scid = scid_utils::scid_from_parts(1, 0, valid_encrypted_vout as u64).unwrap(); assert!(is_valid_intercept(&fake_scid_rand_bytes, valid_fake_scid, &testnet_genesis));