Invoice request raw byte encoding and decoding
[rust-lightning] / lightning / src / offers / merkle.rs
index c7aafb0cfef2516fc8a4cd5965c155652d2594aa..95183bea20d2a50c29dc62f2890c0e0381cb402d 100644 (file)
@@ -10,6 +10,8 @@
 //! Tagged hashes for use in signature calculation and verification.
 
 use bitcoin::hashes::{Hash, HashEngine, sha256};
+use bitcoin::secp256k1::{Message, PublicKey, Secp256k1, self};
+use bitcoin::secp256k1::schnorr::Signature;
 use crate::io;
 use crate::util::ser::{BigSize, Readable};
 
@@ -18,6 +20,25 @@ use crate::prelude::*;
 /// Valid type range for signature TLV records.
 const SIGNATURE_TYPES: core::ops::RangeInclusive<u64> = 240..=1000;
 
+tlv_stream!(SignatureTlvStream, SignatureTlvStreamRef, SIGNATURE_TYPES, {
+       (240, signature: Signature),
+});
+
+/// Verifies the signature with a pubkey over the given bytes using a tagged hash as the message
+/// digest.
+///
+/// Panics if `bytes` is not a well-formed TLV stream containing at least one TLV record.
+pub(super) fn verify_signature(
+       signature: &Signature, tag: &str, bytes: &[u8], pubkey: PublicKey,
+) -> Result<(), secp256k1::Error> {
+       let tag = sha256::Hash::hash(tag.as_bytes());
+       let merkle_root = root_hash(bytes);
+       let digest = Message::from_slice(&tagged_hash(tag, merkle_root)).unwrap();
+       let pubkey = pubkey.into();
+       let secp_ctx = Secp256k1::verification_only();
+       secp_ctx.verify_schnorr(signature, &digest, &pubkey)
+}
+
 /// 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 {