mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore: document parts of ECIES and MAC (#1260)
This commit is contained in:
@ -24,6 +24,12 @@ use std::convert::TryFrom;
|
||||
|
||||
const PROTOCOL_VERSION: usize = 4;
|
||||
|
||||
/// Computes the shared secret with ECDH and strips the y coordinate after computing the shared
|
||||
/// secret.
|
||||
///
|
||||
/// This uses the given remote public key and local (ephemeral) secret key to [compute a shared
|
||||
/// secp256k1 point](secp256k1::ecdh::shared_secret_point) and slices off the y coordinate from the
|
||||
/// returned pair, returning only the bytes of the x coordinate as a [`H256`].
|
||||
fn ecdh_x(public_key: &PublicKey, secret_key: &SecretKey) -> H256 {
|
||||
H256::from_slice(&secp256k1::ecdh::shared_secret_point(public_key, secret_key)[..32])
|
||||
}
|
||||
@ -332,6 +338,8 @@ impl ECIES {
|
||||
self.parse_auth_unencrypted(unencrypted)
|
||||
}
|
||||
|
||||
/// Create an `ack` message using the internal nonce, local ephemeral public key, and RLPx
|
||||
/// ECIES protocol version.
|
||||
fn create_ack_unencrypted(&self) -> impl AsRef<[u8]> {
|
||||
#[derive(RlpEncodable, RlpMaxEncodedLen)]
|
||||
struct S {
|
||||
@ -354,7 +362,7 @@ impl ECIES {
|
||||
buf
|
||||
}
|
||||
|
||||
/// Write an ack message to the given buffer.
|
||||
/// Write an `ack` message to the given buffer.
|
||||
pub fn write_ack(&mut self, out: &mut BytesMut) {
|
||||
let unencrypted = self.create_ack_unencrypted();
|
||||
|
||||
@ -378,6 +386,13 @@ impl ECIES {
|
||||
self.setup_frame(true);
|
||||
}
|
||||
|
||||
/// Parse the incoming `ack` message from the given `data` bytes, which are assumed to be
|
||||
/// unencrypted. This parses the remote ephemeral pubkey and nonce from the message, and uses
|
||||
/// ECDH to compute the shared secret. The shared secret is the x coordinate of the point
|
||||
/// returned by ECDH.
|
||||
///
|
||||
/// This sets the `remote_ephemeral_public_key` and `remote_nonce`, and
|
||||
/// `ephemeral_shared_secret` fields in the ECIES state.
|
||||
fn parse_ack_unencrypted(&mut self, data: &[u8]) -> Result<(), ECIESError> {
|
||||
let mut data = Rlp::new(data)?;
|
||||
self.remote_ephemeral_public_key =
|
||||
|
||||
@ -10,6 +10,13 @@ use typenum::U16;
|
||||
|
||||
pub type HeaderBytes = GenericArray<u8, U16>;
|
||||
|
||||
/// [`Ethereum MAC`](https://github.com/ethereum/devp2p/blob/master/rlpx.md#mac) state.
|
||||
///
|
||||
/// The ethereum MAC is a cursed MAC construction.
|
||||
///
|
||||
/// The ethereum MAC is a nonstandard MAC construction that uses AES-256 (without a mode, as a
|
||||
/// block cipher) and Keccak-256. However, it only ever encrypts messages that are 128 bits long,
|
||||
/// and is not defined as a general MAC.
|
||||
#[derive(Debug)]
|
||||
pub struct MAC {
|
||||
secret: H256,
|
||||
@ -17,17 +24,21 @@ pub struct MAC {
|
||||
}
|
||||
|
||||
impl MAC {
|
||||
/// Initialize the MAC with the given secret
|
||||
pub fn new(secret: H256) -> Self {
|
||||
Self { secret, hasher: Keccak256::new() }
|
||||
}
|
||||
|
||||
/// Update the internal keccak256 hasher with the given data
|
||||
pub fn update(&mut self, data: &[u8]) {
|
||||
self.hasher.update(data)
|
||||
}
|
||||
|
||||
/// Accumulate the given [`HeaderBytes`] into the MAC's internal state.
|
||||
pub fn update_header(&mut self, data: &HeaderBytes) {
|
||||
let aes = Aes256Enc::new_from_slice(self.secret.as_ref()).unwrap();
|
||||
let mut encrypted = self.digest().to_fixed_bytes();
|
||||
|
||||
aes.encrypt_padded::<NoPadding>(&mut encrypted, H128::len_bytes()).unwrap();
|
||||
for i in 0..data.len() {
|
||||
encrypted[i] ^= data[i];
|
||||
@ -35,11 +46,13 @@ impl MAC {
|
||||
self.hasher.update(encrypted);
|
||||
}
|
||||
|
||||
/// Accumulate the given message body into the MAC's internal state.
|
||||
pub fn update_body(&mut self, data: &[u8]) {
|
||||
self.hasher.update(data);
|
||||
let prev = self.digest();
|
||||
let aes = Aes256Enc::new_from_slice(self.secret.as_ref()).unwrap();
|
||||
let mut encrypted = self.digest().to_fixed_bytes();
|
||||
|
||||
aes.encrypt_padded::<NoPadding>(&mut encrypted, H128::len_bytes()).unwrap();
|
||||
for i in 0..16 {
|
||||
encrypted[i] ^= prev[i];
|
||||
@ -47,6 +60,8 @@ impl MAC {
|
||||
self.hasher.update(encrypted);
|
||||
}
|
||||
|
||||
/// Produce a digest by finalizing the internal keccak256 hasher and returning the first 128
|
||||
/// bits.
|
||||
pub fn digest(&self) -> H128 {
|
||||
H128::from_slice(&self.hasher.clone().finalize()[..16])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user