|
10 | 10 | //! Tagged hashes for use in signature calculation and verification. |
11 | 11 |
|
12 | 12 | use crate::io; |
| 13 | +use crate::offers::invoice::{EXPERIMENTAL_INVOICE_TYPES, INVOICE_TYPES}; |
| 14 | +use crate::offers::offer::{EXPERIMENTAL_OFFER_TYPES, OFFER_TYPES}; |
13 | 15 | use crate::util::ser::{BigSize, Readable, Writeable, Writer}; |
14 | 16 | use bitcoin::hashes::{sha256, Hash, HashEngine}; |
15 | 17 | use bitcoin::secp256k1::schnorr::Signature; |
@@ -396,39 +398,40 @@ pub(super) fn compute_selective_disclosure<'a>( |
396 | 398 |
|
397 | 399 | /// Compute omitted markers per BOLT 12 payer proof spec. |
398 | 400 | /// |
399 | | -/// Each omitted TLV gets a marker that is one greater than the previous included |
400 | | -/// TLV type or the previous marker, except that a marker of 239 (the top of the |
401 | | -/// low marker range) is followed by 1_000_000_000 (the start of the high range) |
402 | | -/// to skip the signature type range. TLV type 0 is implicitly omitted (never |
403 | | -/// assigned a marker). |
| 401 | +/// Each omitted TLV gets a marker one greater than the previous included TLV |
| 402 | +/// type or the previous marker. If that value would land in the gap between the |
| 403 | +/// invoice TLV range and the experimental range, it jumps to the start of the |
| 404 | +/// experimental range instead. TLV type 0 is implicitly omitted (never assigned |
| 405 | +/// a marker). |
404 | 406 | fn compute_omitted_markers<'a>( |
405 | 407 | tlv_data: impl Iterator<Item = &'a TlvMerkleData> + 'a, |
406 | 408 | ) -> impl Iterator<Item = u64> + 'a { |
407 | 409 | tlv_data |
408 | 410 | .filter(|data| data.tlv_type != 0) |
409 | | - .scan((0u64, false), |(prev_value, prev_included), data| { |
| 411 | + .scan(0u64, |prev_value, data| { |
410 | 412 | if data.is_included { |
411 | 413 | *prev_value = data.tlv_type; |
412 | | - *prev_included = true; |
413 | 414 | Some(None) |
414 | 415 | } else { |
415 | | - // Per BOLT 12 PR 1295, omitted-TLV markers live in either `1..=239` |
416 | | - // or `1_000_000_000..=3_999_999_999`. When the previous marker was |
417 | | - // 239 the next one jumps to the start of the high range rather than |
418 | | - // entering the signature type range. |
419 | | - let marker = if !*prev_included && *prev_value == 239 { |
420 | | - 1_000_000_000 |
| 416 | + // Per BOLT 12 PR 1295, omitted-TLV markers live in either the |
| 417 | + // invoice TLV range or the experimental range. A marker that would |
| 418 | + // land in the gap between them (the signature/payer-proof range) |
| 419 | + // jumps to the start of the experimental range. |
| 420 | + let next = prev_value.saturating_add(1); |
| 421 | + let marker = if (INVOICE_TYPES.end..EXPERIMENTAL_OFFER_TYPES.start).contains(&next) |
| 422 | + { |
| 423 | + EXPERIMENTAL_OFFER_TYPES.start |
421 | 424 | } else { |
422 | | - *prev_value + 1 |
| 425 | + next |
423 | 426 | }; |
424 | 427 | *prev_value = marker; |
425 | | - *prev_included = false; |
426 | 428 | // Real BOLT 12 invoices have far fewer than 239 non-signature TLVs, |
427 | | - // so the high range is never reached in practice; this assert |
428 | | - // documents and guards the invariant. |
| 429 | + // so the experimental range is never reached in practice; this |
| 430 | + // assert documents and guards the invariant. |
429 | 431 | debug_assert!( |
430 | | - (1..=239).contains(&marker) |
431 | | - || (1_000_000_000..=3_999_999_999).contains(&marker), |
| 432 | + (OFFER_TYPES.start..INVOICE_TYPES.end).contains(&marker) |
| 433 | + || (EXPERIMENTAL_OFFER_TYPES.start..EXPERIMENTAL_INVOICE_TYPES.end) |
| 434 | + .contains(&marker), |
432 | 435 | "compute_omitted_markers produced marker {} outside spec ranges", |
433 | 436 | marker, |
434 | 437 | ); |
@@ -1101,6 +1104,34 @@ mod tests { |
1101 | 1104 | assert_eq!(markers, expected); |
1102 | 1105 | } |
1103 | 1106 |
|
| 1107 | + /// An *included* TLV at the top of the low range (type 239) followed by an |
| 1108 | + /// omitted TLV: the marker must skip the signature/payer-proof gap and jump |
| 1109 | + /// to the start of the experimental range, not land on 240. |
| 1110 | + #[test] |
| 1111 | + fn compute_omitted_markers_jumps_after_included_at_top_of_low_range() { |
| 1112 | + let dummy_hash = sha256::Hash::all_zeros(); |
| 1113 | + let tlv_data = vec![ |
| 1114 | + TlvMerkleData { tlv_type: 239, per_tlv_hash: dummy_hash, is_included: true }, |
| 1115 | + TlvMerkleData { tlv_type: 1_500_000_000, per_tlv_hash: dummy_hash, is_included: false }, |
| 1116 | + ]; |
| 1117 | + let markers: Vec<u64> = compute_omitted_markers(tlv_data.iter()).collect(); |
| 1118 | + assert_eq!(markers, vec![1_000_000_000]); |
| 1119 | + } |
| 1120 | + |
| 1121 | + /// After a jump into the experimental range, subsequent omitted markers |
| 1122 | + /// continue sequentially within that range. |
| 1123 | + #[test] |
| 1124 | + fn compute_omitted_markers_continue_in_experimental_range_after_jump() { |
| 1125 | + let dummy_hash = sha256::Hash::all_zeros(); |
| 1126 | + let tlv_data = vec![ |
| 1127 | + TlvMerkleData { tlv_type: 239, per_tlv_hash: dummy_hash, is_included: true }, |
| 1128 | + TlvMerkleData { tlv_type: 3_000_000_000, per_tlv_hash: dummy_hash, is_included: false }, |
| 1129 | + TlvMerkleData { tlv_type: 3_000_000_001, per_tlv_hash: dummy_hash, is_included: false }, |
| 1130 | + ]; |
| 1131 | + let markers: Vec<u64> = compute_omitted_markers(tlv_data.iter()).collect(); |
| 1132 | + assert_eq!(markers, vec![1_000_000_000, 1_000_000_001]); |
| 1133 | + } |
| 1134 | + |
1104 | 1135 | #[test] |
1105 | 1136 | fn test_tlv_record_read_value_rejects_trailing_bytes() { |
1106 | 1137 | use bitcoin::secp256k1::PublicKey; |
|
0 commit comments