Skip to content

Commit d1755c2

Browse files
committed
Encoding for TLV stream without signature records
When using bytes from an InvoiceRequest to constructing bytes for an Invoice, any signature TLV records in the bytes must be excluded. Define a wrapper for encoding such pre-serialized bytes in this manner. This will allow the forthcoming InvoiceBuilder to construct bytes for an Invoice properly.
1 parent 9d300d2 commit d1755c2

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

lightning/src/offers/merkle.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use bitcoin::hashes::{Hash, HashEngine, sha256};
1313
use bitcoin::secp256k1::{Message, PublicKey, Secp256k1, self};
1414
use bitcoin::secp256k1::schnorr::Signature;
1515
use crate::io;
16-
use crate::util::ser::{BigSize, Readable};
16+
use crate::util::ser::{BigSize, Readable, Writeable, Writer};
1717

1818
use crate::prelude::*;
1919

@@ -194,14 +194,33 @@ impl<'a> Iterator for TlvStream<'a> {
194194
}
195195
}
196196

197+
/// Encoding for a pre-serialized TLV stream by excluding any signature TLV records.
198+
///
199+
/// Panics if the wrapped bytes is not a well-formed TLV stream.
200+
pub(super) struct WithoutSignatures<'a>(pub &'a Vec<u8>);
201+
202+
impl<'a> Writeable for WithoutSignatures<'a> {
203+
#[inline]
204+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
205+
let tlv_stream = TlvStream::new(&self.0[..]);
206+
for record in tlv_stream.skip_signatures() {
207+
writer.write_all(record.record_bytes)?;
208+
}
209+
Ok(())
210+
}
211+
}
212+
197213
#[cfg(test)]
198214
mod tests {
215+
use super::{TlvStream, WithoutSignatures};
216+
199217
use bitcoin::hashes::{Hash, sha256};
200218
use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
201219
use core::convert::Infallible;
202220
use crate::offers::offer::{Amount, OfferBuilder};
203221
use crate::offers::invoice_request::InvoiceRequest;
204222
use crate::offers::parse::Bech32Encode;
223+
use crate::util::ser::Writeable;
205224

206225
#[test]
207226
fn calculates_merkle_root_hash() {
@@ -253,6 +272,36 @@ mod tests {
253272
);
254273
}
255274

275+
#[test]
276+
fn skips_encoding_signature_tlv_records() {
277+
let secp_ctx = Secp256k1::new();
278+
let recipient_pubkey = {
279+
let secret_key = SecretKey::from_slice(&[41; 32]).unwrap();
280+
KeyPair::from_secret_key(&secp_ctx, &secret_key).public_key()
281+
};
282+
let payer_keys = {
283+
let secret_key = SecretKey::from_slice(&[42; 32]).unwrap();
284+
KeyPair::from_secret_key(&secp_ctx, &secret_key)
285+
};
286+
287+
let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey)
288+
.amount_msats(100)
289+
.build_unchecked()
290+
.request_invoice(vec![0; 8], payer_keys.public_key()).unwrap()
291+
.build_unchecked()
292+
.sign::<_, Infallible>(|digest| Ok(secp_ctx.sign_schnorr_no_aux_rand(digest, &payer_keys)))
293+
.unwrap();
294+
295+
let mut bytes_without_signature = Vec::new();
296+
WithoutSignatures(&invoice_request.bytes).write(&mut bytes_without_signature).unwrap();
297+
298+
assert_ne!(bytes_without_signature, invoice_request.bytes);
299+
assert_eq!(
300+
TlvStream::new(&bytes_without_signature).count(),
301+
TlvStream::new(&invoice_request.bytes).count() - 1,
302+
);
303+
}
304+
256305
impl AsRef<[u8]> for InvoiceRequest {
257306
fn as_ref(&self) -> &[u8] {
258307
&self.bytes

0 commit comments

Comments
 (0)