Offer metadata and signing pubkey derivation
[rust-lightning] / lightning / src / offers / signer.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
8 // licenses.
9
10 //! Utilities for signing offer messages and verifying metadata.
11
12 use bitcoin::hashes::{Hash, HashEngine};
13 use bitcoin::hashes::hmac::{Hmac, HmacEngine};
14 use bitcoin::hashes::sha256::Hash as Sha256;
15 use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey, self};
16 use core::convert::TryInto;
17 use core::fmt;
18 use crate::ln::inbound_payment::{ExpandedKey, IV_LEN, Nonce};
19 use crate::util::ser::Writeable;
20
21 use crate::prelude::*;
22
23 const DERIVED_METADATA_HMAC_INPUT: &[u8; 16] = &[1; 16];
24 const DERIVED_METADATA_AND_KEYS_HMAC_INPUT: &[u8; 16] = &[2; 16];
25
26 /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be
27 /// verified.
28 #[derive(Clone)]
29 pub(super) enum Metadata {
30         /// Metadata as parsed, supplied by the user, or derived from the message contents.
31         Bytes(Vec<u8>),
32
33         /// Metadata to be derived from message contents and given material.
34         Derived(MetadataMaterial),
35
36         /// Metadata and signing pubkey to be derived from message contents and given material.
37         DerivedSigningPubkey(MetadataMaterial),
38 }
39
40 impl Metadata {
41         pub fn as_bytes(&self) -> Option<&Vec<u8>> {
42                 match self {
43                         Metadata::Bytes(bytes) => Some(bytes),
44                         Metadata::Derived(_) => None,
45                         Metadata::DerivedSigningPubkey(_) => None,
46                 }
47         }
48
49         pub fn has_derivation_material(&self) -> bool {
50                 match self {
51                         Metadata::Bytes(_) => false,
52                         Metadata::Derived(_) => true,
53                         Metadata::DerivedSigningPubkey(_) => true,
54                 }
55         }
56
57         pub fn derives_keys(&self) -> bool {
58                 match self {
59                         Metadata::Bytes(_) => false,
60                         Metadata::Derived(_) => false,
61                         Metadata::DerivedSigningPubkey(_) => true,
62                 }
63         }
64
65         pub fn without_keys(self) -> Self {
66                 match self {
67                         Metadata::Bytes(_) => self,
68                         Metadata::Derived(_) => self,
69                         Metadata::DerivedSigningPubkey(material) => Metadata::Derived(material),
70                 }
71         }
72
73         pub fn derive_from<W: Writeable, T: secp256k1::Signing>(
74                 self, tlv_stream: W, secp_ctx: Option<&Secp256k1<T>>
75         ) -> (Self, Option<KeyPair>) {
76                 match self {
77                         Metadata::Bytes(_) => (self, None),
78                         Metadata::Derived(mut metadata_material) => {
79                                 tlv_stream.write(&mut metadata_material.hmac).unwrap();
80                                 (Metadata::Bytes(metadata_material.derive_metadata()), None)
81                         },
82                         Metadata::DerivedSigningPubkey(mut metadata_material) => {
83                                 tlv_stream.write(&mut metadata_material.hmac).unwrap();
84                                 let secp_ctx = secp_ctx.unwrap();
85                                 let (metadata, keys) = metadata_material.derive_metadata_and_keys(secp_ctx);
86                                 (Metadata::Bytes(metadata), Some(keys))
87                         },
88                 }
89         }
90 }
91
92 impl fmt::Debug for Metadata {
93         fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94                 match self {
95                         Metadata::Bytes(bytes) => bytes.fmt(f),
96                         Metadata::Derived(_) => f.write_str("Derived"),
97                         Metadata::DerivedSigningPubkey(_) => f.write_str("DerivedSigningPubkey"),
98                 }
99         }
100 }
101
102 #[cfg(test)]
103 impl PartialEq for Metadata {
104         fn eq(&self, other: &Self) -> bool {
105                 match self {
106                         Metadata::Bytes(bytes) => if let Metadata::Bytes(other_bytes) = other {
107                                 bytes == other_bytes
108                         } else {
109                                 false
110                         },
111                         Metadata::Derived(_) => false,
112                         Metadata::DerivedSigningPubkey(_) => false,
113                 }
114         }
115 }
116
117 /// Material used to create metadata for a message.
118 #[derive(Clone)]
119 pub(super) struct MetadataMaterial {
120         nonce: Nonce,
121         hmac: HmacEngine<Sha256>,
122 }
123
124 impl MetadataMaterial {
125         pub fn new(nonce: Nonce, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN]) -> Self {
126                 Self {
127                         nonce,
128                         hmac: expanded_key.hmac_for_offer(nonce, iv_bytes),
129                 }
130         }
131
132         fn derive_metadata(mut self) -> Vec<u8> {
133                 self.hmac.input(DERIVED_METADATA_HMAC_INPUT);
134
135                 let mut bytes = self.nonce.as_slice().to_vec();
136                 bytes.extend_from_slice(&Hmac::from_engine(self.hmac).into_inner());
137                 bytes
138         }
139
140         fn derive_metadata_and_keys<T: secp256k1::Signing>(
141                 mut self, secp_ctx: &Secp256k1<T>
142         ) -> (Vec<u8>, KeyPair) {
143                 self.hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
144
145                 let hmac = Hmac::from_engine(self.hmac);
146                 let privkey = SecretKey::from_slice(hmac.as_inner()).unwrap();
147                 let keys = KeyPair::from_secret_key(secp_ctx, &privkey);
148                 (self.nonce.as_slice().to_vec(), keys)
149         }
150 }