}
}
+pub(super) fn derive_keys(nonce: Nonce, expanded_key: &ExpandedKey) -> KeyPair {
+ const IV_BYTES: &[u8; IV_LEN] = b"LDK Invoice ~~~~";
+ 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_inner()).unwrap();
+ KeyPair::from_secret_key(&secp_ctx, &privkey)
+}
+
/// Verifies data given in a TLV stream was used to produce the given metadata, consisting of:
/// - a 128-bit [`Nonce`] and possibly
/// - a [`Sha256`] hash of the nonce and the TLV records using the [`ExpandedKey`].
/// If the latter is not included in the metadata, the TLV stream is used to check if the given
/// `signing_pubkey` can be derived from it.
pub(super) fn verify_metadata<'a, T: secp256k1::Signing>(
- metadata: &Vec<u8>, expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
+ metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
signing_pubkey: PublicKey, tlv_stream: impl core::iter::Iterator<Item = TlvRecord<'a>>,
secp_ctx: &Secp256k1<T>
-) -> bool {
+) -> Result<Option<KeyPair>, ()> {
+ let hmac = hmac_for_message(metadata, expanded_key, iv_bytes, tlv_stream)?;
+
+ if metadata.len() == Nonce::LENGTH {
+ let derived_keys = KeyPair::from_secret_key(
+ secp_ctx, &SecretKey::from_slice(hmac.as_inner()).unwrap()
+ );
+ if fixed_time_eq(&signing_pubkey.serialize(), &derived_keys.public_key().serialize()) {
+ Ok(Some(derived_keys))
+ } else {
+ Err(())
+ }
+ } else if metadata[Nonce::LENGTH..].len() == Sha256::LEN {
+ if fixed_time_eq(&metadata[Nonce::LENGTH..], &hmac.into_inner()) {
+ Ok(None)
+ } else {
+ Err(())
+ }
+ } else {
+ Err(())
+ }
+}
+
+fn hmac_for_message<'a>(
+ metadata: &[u8], expanded_key: &ExpandedKey, iv_bytes: &[u8; IV_LEN],
+ tlv_stream: impl core::iter::Iterator<Item = TlvRecord<'a>>
+) -> Result<Hmac<Sha256>, ()> {
if metadata.len() < Nonce::LENGTH {
- return false;
+ return Err(());
}
let nonce = match Nonce::try_from(&metadata[..Nonce::LENGTH]) {
Ok(nonce) => nonce,
- Err(_) => return false,
+ Err(_) => return Err(()),
};
let mut hmac = expanded_key.hmac_for_offer(nonce, iv_bytes);
if metadata.len() == Nonce::LENGTH {
hmac.input(DERIVED_METADATA_AND_KEYS_HMAC_INPUT);
- let hmac = Hmac::from_engine(hmac);
- let derived_pubkey = SecretKey::from_slice(hmac.as_inner()).unwrap().public_key(&secp_ctx);
- fixed_time_eq(&signing_pubkey.serialize(), &derived_pubkey.serialize())
- } else if metadata[Nonce::LENGTH..].len() == Sha256::LEN {
- hmac.input(DERIVED_METADATA_HMAC_INPUT);
- fixed_time_eq(&metadata[Nonce::LENGTH..], &Hmac::from_engine(hmac).into_inner())
} else {
- false
+ hmac.input(DERIVED_METADATA_HMAC_INPUT);
}
+
+ Ok(Hmac::from_engine(hmac))
}