X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Foffers%2Fmerkle.rs;h=9782dc7d1e84131f1d6e659dce2d28ac7e9de6f0;hb=6388c9a3e52423ae28ce5136307ae18b30186357;hp=1a505aae8f018e07ee0230b7da01b1ef3939e4ab;hpb=6b3535451e6243611d3435f9eb195706b9ca1ba7;p=rust-lightning diff --git a/lightning/src/offers/merkle.rs b/lightning/src/offers/merkle.rs index 1a505aae..9782dc7d 100644 --- a/lightning/src/offers/merkle.rs +++ b/lightning/src/offers/merkle.rs @@ -13,7 +13,7 @@ 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}; +use crate::util::ser::{BigSize, Readable, Writeable, Writer}; use crate::prelude::*; @@ -194,14 +194,33 @@ impl<'a> Iterator for TlvStream<'a> { } } +/// Encoding for a pre-serialized TLV stream that excludes any signature TLV records. +/// +/// Panics if the wrapped bytes are not a well-formed TLV stream. +pub(super) struct WithoutSignatures<'a>(pub &'a Vec); + +impl<'a> Writeable for WithoutSignatures<'a> { + #[inline] + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let tlv_stream = TlvStream::new(&self.0[..]); + for record in tlv_stream.skip_signatures() { + writer.write_all(record.record_bytes)?; + } + Ok(()) + } +} + #[cfg(test)] mod tests { + use super::{TlvStream, WithoutSignatures}; + use bitcoin::hashes::{Hash, sha256}; use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey}; use core::convert::Infallible; use crate::offers::offer::{Amount, OfferBuilder}; use crate::offers::invoice_request::InvoiceRequest; use crate::offers::parse::Bech32Encode; + use crate::util::ser::Writeable; #[test] fn calculates_merkle_root_hash() { @@ -253,6 +272,36 @@ mod tests { ); } + #[test] + fn skips_encoding_signature_tlv_records() { + let secp_ctx = Secp256k1::new(); + let recipient_pubkey = { + let secret_key = SecretKey::from_slice(&[41; 32]).unwrap(); + KeyPair::from_secret_key(&secp_ctx, &secret_key).public_key() + }; + let payer_keys = { + let secret_key = SecretKey::from_slice(&[42; 32]).unwrap(); + KeyPair::from_secret_key(&secp_ctx, &secret_key) + }; + + let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey) + .amount_msats(100) + .build_unchecked() + .request_invoice(vec![0; 8], payer_keys.public_key()).unwrap() + .build_unchecked() + .sign::<_, Infallible>(|digest| Ok(secp_ctx.sign_schnorr_no_aux_rand(digest, &payer_keys))) + .unwrap(); + + let mut bytes_without_signature = Vec::new(); + WithoutSignatures(&invoice_request.bytes).write(&mut bytes_without_signature).unwrap(); + + assert_ne!(bytes_without_signature, invoice_request.bytes); + assert_eq!( + TlvStream::new(&bytes_without_signature).count(), + TlvStream::new(&invoice_request.bytes).count() - 1, + ); + } + impl AsRef<[u8]> for InvoiceRequest { fn as_ref(&self) -> &[u8] { &self.bytes