bytes: self.bytes,
contents: self.contents,
signature,
+ tagged_hash: self.tagged_hash,
})
}
}
bytes: Vec<u8>,
contents: InvoiceContents,
signature: Signature,
+ tagged_hash: TaggedHash,
}
/// The contents of an [`Bolt12Invoice`] for responding to either an [`Offer`] or a [`Refund`].
/// Hash that was used for signing the invoice.
pub fn signable_hash(&self) -> [u8; 32] {
- merkle::message_digest(SIGNATURE_TAG, &self.bytes).as_ref().clone()
+ self.tagged_hash.as_digest().as_ref().clone()
}
/// Verifies that the invoice was for a request or refund created using the given key. Returns
None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
Some(signature) => signature,
};
- let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
+ let tagged_hash = TaggedHash::new(SIGNATURE_TAG, &bytes);
let pubkey = contents.fields().signing_pubkey;
- merkle::verify_signature(&signature, message, pubkey)?;
+ merkle::verify_signature(&signature, &tagged_hash, pubkey)?;
- Ok(Bolt12Invoice { bytes, contents, signature })
+ Ok(Bolt12Invoice { bytes, contents, signature, tagged_hash })
}
}
assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
- assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
+ assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok());
let digest = Message::from_slice(&invoice.signable_hash()).unwrap();
let pubkey = recipient_pubkey().into();
assert_eq!(invoice.signing_pubkey(), recipient_pubkey());
let message = TaggedHash::new(SIGNATURE_TAG, &invoice.bytes);
- assert!(merkle::verify_signature(&invoice.signature, message, recipient_pubkey()).is_ok());
+ assert!(merkle::verify_signature(&invoice.signature, &message, recipient_pubkey()).is_ok());
assert_eq!(
invoice.as_tlv_stream(),
Some(signature) => signature,
};
let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
- merkle::verify_signature(&signature, message, contents.payer_id)?;
+ merkle::verify_signature(&signature, &message, contents.payer_id)?;
Ok(InvoiceRequest { bytes, contents, signature })
}
assert_eq!(invoice_request.payer_note(), None);
let message = TaggedHash::new(SIGNATURE_TAG, &invoice_request.bytes);
- assert!(merkle::verify_signature(&invoice_request.signature, message, payer_pubkey()).is_ok());
+ assert!(merkle::verify_signature(&invoice_request.signature, &message, payer_pubkey()).is_ok());
assert_eq!(
invoice_request.as_tlv_stream(),
///
/// [BIP 340]: https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki
/// [BOLT 12]: https://github.com/rustyrussell/lightning-rfc/blob/guilt/offers/12-offer-encoding.md#signature-calculation
-#[derive(Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
pub struct TaggedHash(Message);
impl TaggedHash {
///
/// Panics if `tlv_stream` is not a well-formed TLV stream containing at least one TLV record.
pub(super) fn new(tag: &str, tlv_stream: &[u8]) -> Self {
- Self(message_digest(tag, tlv_stream))
+ let tag = sha256::Hash::hash(tag.as_bytes());
+ let merkle_root = root_hash(tlv_stream);
+ Self(Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap())
}
/// Returns the digest to sign.
/// Verifies the signature with a pubkey over the given message using a tagged hash as the message
/// digest.
pub(super) fn verify_signature(
- signature: &Signature, message: TaggedHash, pubkey: PublicKey,
+ signature: &Signature, message: &TaggedHash, pubkey: PublicKey,
) -> Result<(), secp256k1::Error> {
let digest = message.as_digest();
let pubkey = pubkey.into();
secp_ctx.verify_schnorr(signature, digest, &pubkey)
}
-pub(super) fn message_digest(tag: &str, bytes: &[u8]) -> Message {
- let tag = sha256::Hash::hash(tag.as_bytes());
- let merkle_root = root_hash(bytes);
- Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap()
-}
-
/// Computes a merkle root hash for the given data, which must be a well-formed TLV stream
/// containing at least one TLV record.
fn root_hash(data: &[u8]) -> sha256::Hash {