Skip to content

Commit 0b4c819

Browse files
committed
review: Abstract hash digest during NOISE handshake
Create a wrapper object for the handshake hash and use it during the NOISE state machine.
1 parent 9280c5d commit 0b4c819

File tree

3 files changed

+59
-41
lines changed

3 files changed

+59
-41
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/// Abstraction for the hash digest used in the NOISE handshake
2+
/// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md
3+
4+
use bitcoin::hashes::{Hash, HashEngine};
5+
use bitcoin::hashes::sha256::Hash as Sha256;
6+
7+
pub(super) struct HandshakeHash {
8+
pub(super) value: [u8; 32],
9+
}
10+
11+
impl HandshakeHash {
12+
// Initialize a new handshake_hash with the input data
13+
pub(super) fn new(first_input: &[u8]) -> Self {
14+
Self {
15+
value: Sha256::hash(first_input).into_inner()
16+
}
17+
}
18+
19+
// Update the handshake hash with new data
20+
pub(super) fn update(&mut self, input: &[u8]) {
21+
let mut sha = Sha256::engine();
22+
sha.input(&self.value);
23+
sha.input(input);
24+
self.value = Sha256::from_engine(sha).into_inner();
25+
}
26+
}

lightning/src/ln/peers/handshake/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use ln::peers::conduit::Conduit;
88
use ln::peers::handshake::states::{HandshakeState, IHandshakeState};
99

1010
mod acts;
11+
mod handshake_hash;
1112
mod states;
1213

1314
/// Object for managing handshakes.

lightning/src/ln/peers/handshake/states.rs

Lines changed: 32 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,17 @@
11
use bitcoin::secp256k1;
22

3-
use bitcoin::hashes::{Hash, HashEngine};
3+
use bitcoin::hashes::Hash;
44
use bitcoin::hashes::sha256::Hash as Sha256;
55
use bitcoin::secp256k1::{SecretKey, PublicKey};
66

77
use ln::peers::{chacha, hkdf5869rfc};
88
use ln::peers::conduit::{Conduit, SymmetricKey};
99
use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE};
10+
use ln::peers::handshake::handshake_hash::HandshakeHash;
1011

1112
// Alias type to help differentiate between temporary key and chaining key when passing bytes around
1213
type ChainingKey = [u8; 32];
1314

14-
// Generate a SHA-256 hash from one or more elements concatenated together
15-
macro_rules! concat_then_sha256 {
16-
( $( $x:expr ),+ ) => {{
17-
let mut sha = Sha256::engine();
18-
$(
19-
sha.input($x.as_ref());
20-
)+
21-
Sha256::from_engine(sha)
22-
}}
23-
}
24-
2515
pub(super) enum HandshakeState {
2616
InitiatorStarting(InitiatorStartingState),
2717
ResponderAwaitingActOne(ResponderAwaitingActOneState),
@@ -66,17 +56,17 @@ pub(super) struct InitiatorStartingState {
6656
initiator_ephemeral_private_key: SecretKey,
6757
initiator_ephemeral_public_key: PublicKey,
6858
responder_static_public_key: PublicKey,
69-
chaining_key: Sha256,
70-
hash: Sha256
59+
chaining_key: ChainingKey,
60+
hash: HandshakeHash,
7161
}
7262

7363
// Handshake state of the Responder prior to receiving Act 1
7464
pub(super) struct ResponderAwaitingActOneState {
7565
responder_static_private_key: SecretKey,
7666
responder_ephemeral_private_key: SecretKey,
7767
responder_ephemeral_public_key: PublicKey,
78-
chaining_key: Sha256,
79-
hash: Sha256,
68+
chaining_key: ChainingKey,
69+
hash: HandshakeHash,
8070
act_one_builder: ActBuilder
8171
}
8272

@@ -87,13 +77,13 @@ pub(super) struct InitiatorAwaitingActTwoState {
8777
initiator_ephemeral_private_key: SecretKey,
8878
responder_static_public_key: PublicKey,
8979
chaining_key: ChainingKey,
90-
hash: Sha256,
80+
hash: HandshakeHash,
9181
act_two_builder: ActBuilder
9282
}
9383

9484
// Handshake state of the Responder prior to receiving Act 3
9585
pub(super) struct ResponderAwaitingActThreeState {
96-
hash: Sha256,
86+
hash: HandshakeHash,
9787
responder_ephemeral_private_key: SecretKey,
9888
chaining_key: ChainingKey,
9989
temporary_key: [u8; 32],
@@ -139,7 +129,7 @@ impl IHandshakeState for InitiatorStartingState {
139129
&initiator_ephemeral_private_key,
140130
&initiator_ephemeral_public_key,
141131
&responder_static_public_key,
142-
chaining_key.into_inner(),
132+
chaining_key,
143133
hash,
144134
&mut act_one
145135
);
@@ -215,7 +205,7 @@ impl IHandshakeState for ResponderAwaitingActOneState {
215205
let (initiator_ephemeral_public_key, hash, chaining_key, _) = process_act_message(
216206
&act_one,
217207
&responder_static_private_key,
218-
chaining_key.into_inner(),
208+
chaining_key,
219209
hash,
220210
)?;
221211

@@ -280,7 +270,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
280270
let chaining_key = self.chaining_key;
281271
let act_two = Act::from(act_two_builder);
282272

283-
let (responder_ephemeral_public_key, hash, chaining_key, temporary_key) = process_act_message(
273+
let (responder_ephemeral_public_key, mut hash, chaining_key, temporary_key) = process_act_message(
284274
&act_two,
285275
&initiator_ephemeral_private_key,
286276
chaining_key,
@@ -291,10 +281,10 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
291281

292282
// start serializing act three
293283
// 1. c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed())
294-
chacha::encrypt(&temporary_key, 1, &hash, &initiator_static_public_key.serialize(), &mut act_three[1..50]);
284+
chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_static_public_key.serialize(), &mut act_three[1..50]);
295285

296286
// 2. h = SHA-256(h || c)
297-
let hash = concat_then_sha256!(hash, act_three[1..50]);
287+
hash.update(&act_three[1..50]);
298288

299289
// 3. se = ECDH(s.priv, re)
300290
let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key);
@@ -303,7 +293,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState {
303293
let (chaining_key, temporary_key) = hkdf5869rfc::derive(&chaining_key, &ecdh);
304294

305295
// 5. t = encryptWithAD(temp_k3, 0, h, zero)
306-
chacha::encrypt(&temporary_key, 0, &hash, &[0; 0], &mut act_three[50..]);
296+
chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0], &mut act_three[50..]);
307297

308298
// 6. sk, rk = HKDF(ck, zero)
309299
let (sending_key, receiving_key) = hkdf5869rfc::derive(&chaining_key, &[0; 0]);
@@ -342,7 +332,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState {
342332
));
343333
}
344334

345-
let hash = self.hash;
335+
let mut hash = self.hash;
346336
let temporary_key = self.temporary_key;
347337
let responder_ephemeral_private_key = self.responder_ephemeral_private_key;
348338
let chaining_key = self.chaining_key;
@@ -364,15 +354,15 @@ impl IHandshakeState for ResponderAwaitingActThreeState {
364354

365355
// 4. rs = decryptWithAD(temp_k2, 1, h, c)
366356
let mut remote_pubkey = [0; 33];
367-
chacha::decrypt(&temporary_key, 1, &hash, &tagged_encrypted_pubkey, &mut remote_pubkey)?;
357+
chacha::decrypt(&temporary_key, 1, &hash.value, &tagged_encrypted_pubkey, &mut remote_pubkey)?;
368358
let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(&remote_pubkey) {
369359
public_key
370360
} else {
371361
return Err("invalid remote public key".to_string());
372362
};
373363

374364
// 5. h = SHA-256(h || c)
375-
let hash = concat_then_sha256!(hash, tagged_encrypted_pubkey);
365+
hash.update(tagged_encrypted_pubkey);
376366

377367
// 6. se = ECDH(e.priv, rs)
378368
let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey);
@@ -381,7 +371,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState {
381371
let (chaining_key, temporary_key) = hkdf5869rfc::derive(&chaining_key, &ecdh);
382372

383373
// 8. p = decryptWithAD(temp_k3, 0, h, t)
384-
chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?;
374+
chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag, &mut [0; 0])?;
385375

386376
// 9. rk, sk = HKDF(ck, zero)
387377
let (receiving_key, sending_key) = hkdf5869rfc::derive(&chaining_key, &[0; 0]);
@@ -405,31 +395,32 @@ impl IHandshakeState for ResponderAwaitingActThreeState {
405395
// the initiator provides the remote's static public key and running on the responder they provide
406396
// their own.
407397
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization
408-
fn initialize_handshake_state(responder_static_public_key: &PublicKey) -> (Sha256, Sha256) {
398+
fn initialize_handshake_state(responder_static_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) {
409399
let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256";
410400
let prologue = b"lightning";
411401

412402
// 1. h = SHA-256(protocolName)
413403
// 2. ck = h
414-
let chaining_key = concat_then_sha256!(protocol_name);
404+
let mut hash = HandshakeHash::new(protocol_name);
405+
let chaining_key = hash.value.clone();
415406

416407
// 3. h = SHA-256(h || prologue)
417-
let hash = concat_then_sha256!(chaining_key, prologue);
408+
hash.update(prologue);
418409

419410
// h = SHA-256(h || responderPublicKey)
420-
let hash = concat_then_sha256!(hash, responder_static_public_key.serialize());
411+
hash.update(&responder_static_public_key.serialize());
421412

422413
(hash, chaining_key)
423414
}
424415

425416
// Due to the very high similarity of acts 1 and 2, this method is used to process both
426417
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender)
427418
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender)
428-
fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: Sha256, act_out: &mut [u8]) -> (Sha256, SymmetricKey, SymmetricKey) {
419+
fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, mut hash: HandshakeHash, act_out: &mut [u8]) -> (HandshakeHash, SymmetricKey, SymmetricKey) {
429420
// 1. e = generateKey() (passed in)
430421
// 2. h = SHA-256(h || e.pub.serializeCompressed())
431422
let serialized_local_public_key = local_public_ephemeral_key.serialize();
432-
let hash = concat_then_sha256!(hash, serialized_local_public_key);
423+
hash.update(&serialized_local_public_key);
433424

434425
// 3. ACT1: es = ECDH(e.priv, rs)
435426
// 3. ACT2: es = ECDH(e.priv, re)
@@ -441,10 +432,10 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e
441432

442433
// 5. ACT1: c = encryptWithAD(temp_k1, 0, h, zero)
443434
// 5. ACT2: c = encryptWithAD(temp_k2, 0, h, zero)
444-
chacha::encrypt(&temporary_key, 0, &hash, &[0; 0], &mut act_out[34..]);
435+
chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0], &mut act_out[34..]);
445436

446437
// 6. h = SHA-256(h || c)
447-
let hash = concat_then_sha256!(hash, &act_out[34..]);
438+
hash.update(&act_out[34..]);
448439

449440
// Send m = 0 || e.pub.serializeCompressed() || c
450441
act_out[0] = 0;
@@ -456,7 +447,7 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e
456447
// Due to the very high similarity of acts 1 and 2, this method is used to process both
457448
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver)
458449
// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver)
459-
fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> {
450+
fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining_key: ChainingKey, mut hash: HandshakeHash) -> Result<(PublicKey, HandshakeHash, SymmetricKey, SymmetricKey), String> {
460451
// 1. Read exactly 50 bytes from the network buffer
461452
// Partial act messages are handled by the callers. By the time it gets here, it
462453
// must be the correct size.
@@ -481,7 +472,7 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining
481472
}
482473

483474
// 4. h = SHA-256(h || re.serializeCompressed())
484-
let hash = concat_then_sha256!(hash, ephemeral_public_key_bytes);
475+
hash.update(ephemeral_public_key_bytes);
485476

486477
// 5. Act1: es = ECDH(s.priv, re)
487478
// 5. Act2: ee = ECDH(e.priv, ee)
@@ -493,10 +484,10 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining
493484

494485
// 7. Act1: p = decryptWithAD(temp_k1, 0, h, c)
495486
// 7. Act2: p = decryptWithAD(temp_k2, 0, h, c)
496-
chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?;
487+
chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag, &mut [0; 0])?;
497488

498489
// 8. h = SHA-256(h || c)
499-
let hash = concat_then_sha256!(hash, chacha_tag);
490+
hash.update(chacha_tag);
500491

501492
Ok((ephemeral_public_key, hash, chaining_key, temporary_key))
502493
}
@@ -513,7 +504,7 @@ fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey {
513504
pk_object.mul_assign(&curve, &private_key[..]).expect("invalid multiplication");
514505

515506
let preimage = pk_object.serialize();
516-
concat_then_sha256!(preimage).into_inner()
507+
Sha256::hash(&preimage).into_inner()
517508
}
518509

519510
#[cfg(test)]

0 commit comments

Comments
 (0)