]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Delay adding iv_bytes to MetadataMaterial::hmac
authorJeffrey Czyz <jkczyz@gmail.com>
Tue, 23 Jul 2024 18:36:39 +0000 (13:36 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Tue, 30 Jul 2024 21:06:24 +0000 (16:06 -0500)
In an upcoming commit, the iv_bytes used in MetadataMaterial will vary
depending on when whether a blinded path is included in the
corresponding message. Delay adding into MetadataMaterial::hmac as
otherwise the HmacEngine would need to be re-initialized using an
ExpandedKey, which won't be readily available.

lightning/src/ln/inbound_payment.rs
lightning/src/offers/invoice_request.rs
lightning/src/offers/offer.rs
lightning/src/offers/refund.rs
lightning/src/offers/signer.rs

index 2d807d550701aa09b123db8e5280f77ff601a521..0ae260a50861ef8683ed0f4e257c7e80dff3700e 100644 (file)
@@ -81,13 +81,8 @@ impl ExpandedKey {
        /// Returns an [`HmacEngine`] used to construct [`Offer::metadata`].
        ///
        /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
-       pub(crate) fn hmac_for_offer(
-               &self, nonce: Nonce, iv_bytes: &[u8; IV_LEN]
-       ) -> HmacEngine<Sha256> {
-               let mut hmac = HmacEngine::<Sha256>::new(&self.offers_base_key);
-               hmac.input(iv_bytes);
-               hmac.input(&nonce.0);
-               hmac
+       pub(crate) fn hmac_for_offer(&self) -> HmacEngine<Sha256> {
+               HmacEngine::<Sha256>::new(&self.offers_base_key)
        }
 
        /// Encrypts or decrypts the given `bytes`. Used for data included in an offer message's
index 4b340470226f546f15294f5b42db3f976c8c68be..de9c9c2db31743827732a24d4a5ba444163be4f4 100644 (file)
@@ -174,7 +174,7 @@ macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident,
                payment_id: PaymentId,
        ) -> Self {
                let payment_id = Some(payment_id);
-               let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id);
+               let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id);
                let metadata = Metadata::Derived(derivation_material);
                Self {
                        offer,
@@ -203,7 +203,7 @@ macro_rules! invoice_request_derived_payer_id_builder_methods { (
                secp_ctx: &'b Secp256k1<$secp_context>, payment_id: PaymentId
        ) -> Self {
                let payment_id = Some(payment_id);
-               let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id);
+               let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id);
                let metadata = Metadata::DerivedSigningPubkey(derivation_material);
                Self {
                        offer,
@@ -346,7 +346,8 @@ macro_rules! invoice_request_builder_methods { (
                                tlv_stream.2.payer_id = $self.payer_id.as_ref();
                        }
 
-                       let (derived_metadata, derived_keys) = metadata.derive_from(tlv_stream, $self.secp_ctx);
+                       let (derived_metadata, derived_keys) =
+                               metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx);
                        metadata = derived_metadata;
                        keys = derived_keys;
                        if let Some(keys) = keys {
index 29220125f66f948c3f3b4a55c209f67c3b596da9..deacacd15222b081f043b3decf73babb5757c65a 100644 (file)
@@ -258,7 +258,7 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => {
                node_id: PublicKey, expanded_key: &ExpandedKey, nonce: Nonce,
                secp_ctx: &'a Secp256k1<$secp_context>
        ) -> Self {
-               let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, None);
+               let derivation_material = MetadataMaterial::new(nonce, expanded_key, None);
                let metadata = Metadata::DerivedSigningPubkey(derivation_material);
                Self {
                        offer: OfferContents {
@@ -405,7 +405,8 @@ macro_rules! offer_builder_methods { (
                                // Either replace the signing pubkey with the derived pubkey or include the metadata
                                // for verification. In the former case, the blinded paths must include
                                // `OffersContext::InvoiceRequest` instead.
-                               let (derived_metadata, keys) = metadata.derive_from(tlv_stream, $self.secp_ctx);
+                               let (derived_metadata, keys) =
+                                       metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx);
                                match keys {
                                        Some(keys) => $self.offer.signing_pubkey = Some(keys.public_key()),
                                        None => $self.offer.metadata = Some(derived_metadata),
index 8547cfe993131e5f57130aa504914f67d7ad0e4c..76605c77fbbf9062e57aff8f9936bfb753cec09e 100644 (file)
@@ -210,7 +210,7 @@ macro_rules! refund_builder_methods { (
                }
 
                let payment_id = Some(payment_id);
-               let derivation_material = MetadataMaterial::new(nonce, expanded_key, IV_BYTES, payment_id);
+               let derivation_material = MetadataMaterial::new(nonce, expanded_key, payment_id);
                let metadata = Metadata::DerivedSigningPubkey(derivation_material);
                Ok(Self {
                        refund: RefundContents {
@@ -316,7 +316,8 @@ macro_rules! refund_builder_methods { (
                                tlv_stream.2.payer_id = None;
                        }
 
-                       let (derived_metadata, keys) = metadata.derive_from(tlv_stream, $self.secp_ctx);
+                       let (derived_metadata, keys) =
+                               metadata.derive_from(IV_BYTES, tlv_stream, $self.secp_ctx);
                        metadata = derived_metadata;
                        if let Some(keys) = keys {
                                $self.refund.payer_id = keys.public_key();
index 2e12a17056ecc7ed7e9f1c853ed8a361a137a500..c15b94d4996a7d3980f63b247378083ae30a88d0 100644 (file)
@@ -140,20 +140,19 @@ impl Metadata {
        }
 
        pub fn derive_from<W: Writeable, T: secp256k1::Signing>(
-               self, tlv_stream: W, secp_ctx: Option<&Secp256k1<T>>
+               self, iv_bytes: &[u8; IV_LEN], tlv_stream: W, secp_ctx: Option<&Secp256k1<T>>
        ) -> (Self, Option<Keypair>) {
                match self {
                        Metadata::Bytes(_) => (self, None),
                        Metadata::RecipientData(_) => { debug_assert!(false); (self, None) },
                        Metadata::PayerData(_) => { debug_assert!(false); (self, None) },
-                       Metadata::Derived(mut metadata_material) => {
-                               tlv_stream.write(&mut metadata_material.hmac).unwrap();
-                               (Metadata::Bytes(metadata_material.derive_metadata()), None)
+                       Metadata::Derived(metadata_material) => {
+                               (Metadata::Bytes(metadata_material.derive_metadata(iv_bytes, tlv_stream)), None)
                        },
-                       Metadata::DerivedSigningPubkey(mut metadata_material) => {
-                               tlv_stream.write(&mut metadata_material.hmac).unwrap();
+                       Metadata::DerivedSigningPubkey(metadata_material) => {
                                let secp_ctx = secp_ctx.unwrap();
-                               let (metadata, keys) = metadata_material.derive_metadata_and_keys(secp_ctx);
+                               let (metadata, keys) =
+                                       metadata_material.derive_metadata_and_keys(iv_bytes, tlv_stream, secp_ctx);
                                (Metadata::Bytes(metadata), Some(keys))
                        },
                }
@@ -217,10 +216,7 @@ pub(super) struct MetadataMaterial {
 }
 
 impl MetadataMaterial {
-       pub fn new(
-               nonce: Nonce, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
-               payment_id: Option<PaymentId>
-       ) -> Self {
+       pub fn new(nonce: Nonce, expanded_key: &ExpandedKey, payment_id: Option<PaymentId>) -> Self {
                // Encrypt payment_id
                let encrypted_payment_id = payment_id.map(|payment_id| {
                        expanded_key.crypt_for_offer(payment_id.0, nonce)
@@ -228,12 +224,16 @@ impl MetadataMaterial {
 
                Self {
                        nonce,
-                       hmac: expanded_key.hmac_for_offer(nonce, iv_bytes),
+                       hmac: expanded_key.hmac_for_offer(),
                        encrypted_payment_id,
                }
        }
 
-       fn derive_metadata(mut self) -> Vec<u8> {
+       fn derive_metadata<W: Writeable>(mut self, iv_bytes: &[u8; IV_LEN], tlv_stream: W) -> Vec<u8> {
+               self.hmac.input(iv_bytes);
+               self.hmac.input(&self.nonce.0);
+               tlv_stream.write(&mut self.hmac).unwrap();
+
                self.hmac.input(DERIVED_METADATA_HMAC_INPUT);
                self.maybe_include_encrypted_payment_id();
 
@@ -243,9 +243,13 @@ impl MetadataMaterial {
                bytes
        }
 
-       fn derive_metadata_and_keys<T: secp256k1::Signing>(
-               mut self, secp_ctx: &Secp256k1<T>
+       fn derive_metadata_and_keys<W: Writeable, T: secp256k1::Signing>(
+               mut self, iv_bytes: &[u8; IV_LEN], tlv_stream: W, secp_ctx: &Secp256k1<T>
        ) -> (Vec<u8>, Keypair) {
+               self.hmac.input(iv_bytes);
+               self.hmac.input(&self.nonce.0);
+               tlv_stream.write(&mut self.hmac).unwrap();
+
                self.hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
                self.maybe_include_encrypted_payment_id();
 
@@ -271,9 +275,12 @@ impl MetadataMaterial {
 
 pub(super) fn derive_keys(nonce: Nonce, expanded_key: &ExpandedKey) -> Keypair {
        const IV_BYTES: &[u8; IV_LEN] = b"LDK Invoice ~~~~";
+       let mut hmac = expanded_key.hmac_for_offer();
+       hmac.input(IV_BYTES);
+       hmac.input(&nonce.0);
+
        let secp_ctx = Secp256k1::new();
-       let hmac = Hmac::from_engine(expanded_key.hmac_for_offer(nonce, IV_BYTES));
-       let privkey = SecretKey::from_slice(hmac.as_byte_array()).unwrap();
+       let privkey = SecretKey::from_slice(Hmac::from_engine(hmac).as_byte_array()).unwrap();
        Keypair::from_secret_key(&secp_ctx, &privkey)
 }
 
@@ -368,7 +375,9 @@ fn hmac_for_message<'a>(
                Ok(nonce) => nonce,
                Err(_) => return Err(()),
        };
-       let mut hmac = expanded_key.hmac_for_offer(nonce, iv_bytes);
+       let mut hmac = expanded_key.hmac_for_offer();
+       hmac.input(iv_bytes);
+       hmac.input(&nonce.0);
 
        for record in tlv_stream {
                hmac.input(record.record_bytes);