Skip to content

Commit 1dffc0f

Browse files
committed
test(receive): add unit tests for extract_pubkey
1 parent 46f5e3c commit 1dffc0f

1 file changed

Lines changed: 349 additions & 0 deletions

File tree

  • silentpayments/src/receive

silentpayments/src/receive/mod.rs

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,352 @@ pub fn compute_tweak_data(
266266

267267
Ok(A_sum.mul_tweak(&secp, &input_hash)?)
268268
}
269+
270+
#[cfg(test)]
271+
#[cfg_attr(coverage_nightly, coverage(off))]
272+
mod tests {
273+
use super::{extract_pubkey, ScriptBuf, TxIn};
274+
275+
use bitcoin::{
276+
hex::test_hex_unwrap as hex,
277+
secp256k1::{self, PublicKey},
278+
OutPoint, Sequence, Witness,
279+
};
280+
281+
use std::str::FromStr;
282+
283+
use crate::SpInputs;
284+
285+
#[test]
286+
fn test_extract_pubkey_wrapped_segwit_ok() {
287+
let script_pubkey = ScriptBuf::from_hex("a914809b71783f1b55eeadeb1678baef0c994adc425987")
288+
.expect("should succeed");
289+
// third input from testnet tx 65eb5594eda20b3a2437c2e2c28ba7633f0492cbb33f62ee31469b913ce8a5ca
290+
let txin = TxIn {
291+
previous_output: OutPoint{
292+
txid: "04d984cdcf728975c173c45c49a242cedee2da5dc200b2f83ca6a98aecf11280"
293+
.parse()
294+
.unwrap(),
295+
vout: 1,
296+
},
297+
script_sig: ScriptBuf::from_hex("1600146a721dcca372f3c17b2c649b2ba61aa0fda98a91")
298+
.unwrap(),
299+
sequence: Sequence::MAX,
300+
witness: Witness::from_slice(&[hex!(
301+
"304402204ebf033caf3a1a210623e98b49acb41db2220c531843106d5c50736b144b15aa02201a006be1ebc2ffef0927d4458e3bb5e41e5abc7e44fc5ceb920049b46f87971101"
302+
), hex!("02ae68d299cbb8ab99bf24c9af79a7b13d28ac8cd21f6f7f750300eda41a589a5d")]),
303+
};
304+
305+
let expected_pubkey = PublicKey::from_str(
306+
"02ae68d299cbb8ab99bf24c9af79a7b13d28ac8cd21f6f7f750300eda41a589a5d",
307+
)
308+
.expect("should work");
309+
let maybe_pubkey = extract_pubkey(txin, &script_pubkey);
310+
311+
assert!(maybe_pubkey.is_some());
312+
313+
let (input_type, parsed_pubkey) = maybe_pubkey.expect("is some");
314+
315+
assert_eq!(SpInputs::WrappedSegwit, input_type);
316+
317+
assert_eq!(expected_pubkey, parsed_pubkey);
318+
}
319+
320+
#[test]
321+
fn test_extract_pubkey_p2wpkh_ok() {
322+
let script_pubkey = ScriptBuf::from_hex("001453d9c40342ee880e766522c3e2b854d37f2b3cbf")
323+
.expect("should succeed");
324+
// only input from mainnet tx 091d2aaadc409298fd8353a4cd94c319481a0b4623fb00872fe240448e93fcbe
325+
let txin = TxIn {
326+
previous_output: OutPoint {
327+
txid: "a7115c7267dbb4aab62b37818d431b784fe731f4d2f9fa0939a9980d581690ec"
328+
.parse()
329+
.unwrap(),
330+
vout: 1,
331+
},
332+
script_sig: ScriptBuf::new(),
333+
sequence: Sequence::MAX,
334+
witness: Witness::from_slice(&[
335+
hex!("3044022025f63cdce46c749ff1953200b4fda615c7bbd6aa1717850c39297ce1087071ca0220675349fe9f9c6cf626f66abfd4ea1381b470a8315d1a8922d2573dc1410c661501"),
336+
hex!("03eb01a0190cb4d5da80878b20ff3823cc45b4fe55288393ee5d9f8a7f5eb65bbb"),
337+
]),
338+
};
339+
340+
let expected_pubkey = PublicKey::from_str(
341+
"03eb01a0190cb4d5da80878b20ff3823cc45b4fe55288393ee5d9f8a7f5eb65bbb",
342+
)
343+
.expect("should succeed");
344+
let maybe_pubkey = extract_pubkey(txin, &script_pubkey);
345+
346+
assert!(maybe_pubkey.is_some());
347+
348+
let (input_type, parsed_pubkey) = maybe_pubkey.expect("is some");
349+
350+
assert_eq!(SpInputs::P2WPKH, input_type);
351+
352+
assert_eq!(expected_pubkey, parsed_pubkey);
353+
}
354+
355+
#[test]
356+
fn test_extract_pubkey_p2tr_ok() {
357+
let script_pubkey = ScriptBuf::from_hex(
358+
"51200f0c8db753acbd17343a39c2f3f4e35e4be6da749f9e35137ab220e7b238a667",
359+
)
360+
.expect("should succeed");
361+
// only input from mainnet tx 091d2aaadc409298fd8353a4cd94c319481a0b4623fb00872fe240448e93fcbe
362+
let txin = TxIn {
363+
previous_output: OutPoint {
364+
txid: "a7115c7267dbb4aab62b37818d431b784fe731f4d2f9fa0939a9980d581690ec"
365+
.parse()
366+
.unwrap(),
367+
vout: 0,
368+
},
369+
script_sig: ScriptBuf::new(),
370+
sequence: Sequence::MAX,
371+
witness: Witness::from_slice(&[hex!(
372+
"b693a0797b24bae12ed0516a2f5ba765618dca89b75e498ba5b745b71644362298a45ca39230d10a02ee6290a91cebf9839600f7e35158a447ea182ea0e022ae01"
373+
)]),
374+
};
375+
376+
let expected_pubkey = PublicKey::from_str(
377+
"020f0c8db753acbd17343a39c2f3f4e35e4be6da749f9e35137ab220e7b238a667",
378+
)
379+
.expect("should succeed");
380+
381+
let maybe_pubkey = extract_pubkey(txin, &script_pubkey);
382+
383+
assert!(maybe_pubkey.is_some());
384+
385+
let (input_type, parsed_pubkey) = maybe_pubkey.expect("is some");
386+
387+
assert_eq!(SpInputs::P2TR, input_type);
388+
389+
assert_eq!(expected_pubkey, parsed_pubkey);
390+
}
391+
392+
#[test]
393+
fn test_extract_pubkey_p2pkh_ok() {
394+
let script_pubkey =
395+
ScriptBuf::from_hex("76a9140c443537e6e31f06e6edb2d4bb80f8481e2831ac88ac")
396+
.expect("should succeed");
397+
// only input from mainnet tx 4316fe7be359937317f42ffaf05ab02554297fb83096a0beb985a25f9e338215
398+
let txin = TxIn {
399+
previous_output: OutPoint {
400+
txid: "40e331b67c0fe7750bb3b1943b378bf702dce86124dc12fa5980f975db7ec930"
401+
.parse()
402+
.unwrap(),
403+
vout: 0,
404+
},
405+
script_sig: ScriptBuf::from_hex("473044022076baac422976af25b32479ccb81df8a2d7f4f73cfb2ff98cfe10241feefdb43702204c08a9fc646150a9aceb3ebc26344e1596ddd6b7bc8aa44cb116a3adca173e3701210360a953b3da3f5cc0ec246a99411c19916fab7e72b59e105955b6e3e9d3a44773").expect("should succeed"),
406+
sequence: Sequence::MAX,
407+
witness: Witness::new(),
408+
};
409+
410+
let expected_pubkey = PublicKey::from_str(
411+
"0360a953b3da3f5cc0ec246a99411c19916fab7e72b59e105955b6e3e9d3a44773",
412+
)
413+
.expect("should succeed");
414+
let maybe_pubkey = extract_pubkey(txin, &script_pubkey);
415+
416+
assert!(maybe_pubkey.is_some());
417+
418+
let (input_type, parsed_pubkey) = maybe_pubkey.expect("is some");
419+
420+
assert_eq!(SpInputs::P2PKH, input_type);
421+
422+
assert_eq!(expected_pubkey, parsed_pubkey);
423+
}
424+
425+
#[test]
426+
fn test_extract_pubkey_malleated_p2pkh_ok() {
427+
let script_pubkey =
428+
ScriptBuf::from_hex("76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac")
429+
.expect("should succeed");
430+
// only input from mainnet tx 4316fe7be359937317f42ffaf05ab02554297fb83096a0beb985a25f9e338215
431+
let txin = TxIn {
432+
previous_output: OutPoint {
433+
txid: "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
434+
.parse()
435+
.unwrap(),
436+
vout: 1,
437+
},
438+
script_sig: ScriptBuf::from_hex("0075473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338").expect("should succeed"),
439+
sequence: Sequence::MAX,
440+
witness: Witness::new(),
441+
};
442+
443+
let expected_pubkey = PublicKey::from_str(
444+
"03782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338",
445+
)
446+
.expect("should succeed");
447+
448+
let maybe_pubkey = extract_pubkey(txin, &script_pubkey);
449+
450+
assert!(maybe_pubkey.is_some());
451+
452+
let (input_type, parsed_pubkey) = maybe_pubkey.expect("is some");
453+
454+
assert_eq!(SpInputs::P2PKH, input_type);
455+
456+
assert_eq!(expected_pubkey, parsed_pubkey);
457+
}
458+
459+
#[test]
460+
fn test_extract_pubkey_wrapped_segwit_invalid_key() {
461+
let script_pubkey = ScriptBuf::from_hex("a914809b71783f1b55eeadeb1678baef0c994adc425987")
462+
.expect("should succeed");
463+
// crafted using third input in testnet tx 65eb5594eda20b3a2437c2e2c28ba7633f0492cbb33f62ee31469b913ce8a5ca as template
464+
let txin = TxIn {
465+
previous_output: OutPoint{
466+
txid: "04d984cdcf728975c173c45c49a242cedee2da5dc200b2f83ca6a98aecf11280"
467+
.parse()
468+
.unwrap(),
469+
vout: 1,
470+
},
471+
script_sig: ScriptBuf::from_hex("1600146a721dcca372f3c17b2c649b2ba61aa0fda98a91")
472+
.unwrap(),
473+
sequence: Sequence::MAX,
474+
witness: Witness::from_slice(&[hex!(
475+
"304402204ebf033caf3a1a210623e98b49acb41db2220c531843106d5c50736b144b15aa02201a006be1ebc2ffef0927d4458e3bb5e41e5abc7e44fc5ceb920049b46f87971101"
476+
), secp256k1::constants::ZERO.to_vec()]),
477+
};
478+
479+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
480+
}
481+
482+
#[test]
483+
fn test_extract_pubkey_p2wpkh_invalid_key() {
484+
let script_pubkey = ScriptBuf::from_hex("001453d9c40342ee880e766522c3e2b854d37f2b3cbf")
485+
.expect("should succeed");
486+
// crafted using the only input from mainnet tx 091d2aaadc409298fd8353a4cd94c319481a0b4623fb00872fe240448e93fcbe as template
487+
let txin = TxIn {
488+
previous_output: OutPoint {
489+
txid: "a7115c7267dbb4aab62b37818d431b784fe731f4d2f9fa0939a9980d581690ec"
490+
.parse()
491+
.unwrap(),
492+
vout: 1,
493+
},
494+
script_sig: ScriptBuf::new(),
495+
sequence: Sequence::MAX,
496+
witness: Witness::from_slice(&[
497+
hex!("3044022025f63cdce46c749ff1953200b4fda615c7bbd6aa1717850c39297ce1087071ca0220675349fe9f9c6cf626f66abfd4ea1381b470a8315d1a8922d2573dc1410c661501"),
498+
secp256k1::constants::ZERO.to_vec()
499+
]),
500+
};
501+
502+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
503+
}
504+
505+
#[test]
506+
fn test_extract_pubkey_p2tr_invalid_key() {
507+
let script_pubkey = ScriptBuf::from_hex(
508+
"51200000000000000000000000000000000000000000000000000000000000000000",
509+
)
510+
.expect("should succeed");
511+
// crafted using only input from mainnet tx 091d2aaadc409298fd8353a4cd94c319481a0b4623fb00872fe240448e93fcbe as template
512+
let txin = TxIn {
513+
previous_output: OutPoint {
514+
txid: "a7115c7267dbb4aab62b37818d431b784fe731f4d2f9fa0939a9980d581690ec"
515+
.parse()
516+
.unwrap(),
517+
vout: 0,
518+
},
519+
script_sig: ScriptBuf::new(),
520+
sequence: Sequence::MAX,
521+
witness: Witness::from_slice(&[hex!(
522+
"b693a0797b24bae12ed0516a2f5ba765618dca89b75e498ba5b745b71644362298a45ca39230d10a02ee6290a91cebf9839600f7e35158a447ea182ea0e022ae01"
523+
)]),
524+
};
525+
526+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
527+
}
528+
529+
#[test]
530+
fn test_extract_pubkey_p2pkh_invalid_key() {
531+
let script_pubkey =
532+
ScriptBuf::from_hex("76a9140c443537e6e31f06e6edb2d4bb80f8481e2831ac88ac")
533+
.expect("should succeed");
534+
// only input from mainnet tx 4316fe7be359937317f42ffaf05ab02554297fb83096a0beb985a25f9e338215
535+
let txin = TxIn {
536+
previous_output: OutPoint {
537+
txid: "40e331b67c0fe7750bb3b1943b378bf702dce86124dc12fa5980f975db7ec930"
538+
.parse()
539+
.unwrap(),
540+
vout: 0,
541+
},
542+
script_sig: ScriptBuf::from_hex("473044022076baac422976af25b32479ccb81df8a2d7f4f73cfb2ff98cfe10241feefdb43702204c08a9fc646150a9aceb3ebc26344e1596ddd6b7bc8aa44cb116a3adca173e370121000000000000000000000000000000000000000000000000000000000000000000").expect("should succeed"),
543+
sequence: Sequence::MAX,
544+
witness: Witness::new(),
545+
};
546+
547+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
548+
}
549+
550+
#[test]
551+
fn test_extract_pubkey_wrapped_segwit_uncompressed() {
552+
let script_pubkey = ScriptBuf::from_hex("a914809b71783f1b55eeadeb1678baef0c994adc425987")
553+
.expect("should succeed");
554+
// crafted using third input from testnet tx 65eb5594eda20b3a2437c2e2c28ba7633f0492cbb33f62ee31469b913ce8a5ca as template
555+
let txin = TxIn {
556+
previous_output: OutPoint{
557+
txid: "04d984cdcf728975c173c45c49a242cedee2da5dc200b2f83ca6a98aecf11280"
558+
.parse()
559+
.unwrap(),
560+
vout: 1,
561+
},
562+
script_sig: ScriptBuf::from_hex("1600146a721dcca372f3c17b2c649b2ba61aa0fda98a91")
563+
.unwrap(),
564+
sequence: Sequence::MAX,
565+
witness: Witness::from_slice(&[hex!(
566+
"304402204ebf033caf3a1a210623e98b49acb41db2220c531843106d5c50736b144b15aa02201a006be1ebc2ffef0927d4458e3bb5e41e5abc7e44fc5ceb920049b46f87971101"
567+
// notice uncompressed public key here, at the end of the witness
568+
), hex!("04ae68d299cbb8ab99bf24c9af79a7b13d28ac8cd21f6f7f750300eda41a589a5d6a7210f279e3be22089aef2e29cf359a7eb0067d8caebae4298c5bec56ca41c2")]),
569+
};
570+
571+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
572+
}
573+
574+
#[test]
575+
fn test_extract_pubkey_p2wpkh_uncompressed() {
576+
let script_pubkey = ScriptBuf::from_hex("001453d9c40342ee880e766522c3e2b854d37f2b3cbf")
577+
.expect("should succeed");
578+
// crafted using the only input from mainnet tx 091d2aaadc409298fd8353a4cd94c319481a0b4623fb00872fe240448e93fcbe as template
579+
let txin = TxIn {
580+
previous_output: OutPoint {
581+
txid: "a7115c7267dbb4aab62b37818d431b784fe731f4d2f9fa0939a9980d581690ec"
582+
.parse()
583+
.unwrap(),
584+
vout: 1,
585+
},
586+
script_sig: ScriptBuf::new(),
587+
sequence: Sequence::MAX,
588+
witness: Witness::from_slice(&[
589+
hex!("3044022025f63cdce46c749ff1953200b4fda615c7bbd6aa1717850c39297ce1087071ca0220675349fe9f9c6cf626f66abfd4ea1381b470a8315d1a8922d2573dc1410c661501"),
590+
hex!("04eb01a0190cb4d5da80878b20ff3823cc45b4fe55288393ee5d9f8a7f5eb65bbb8ac7e2a9044b74ce6284ebb08a92ebe489c27b43e542355e783b661b62ed76fd"),
591+
]),
592+
};
593+
594+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
595+
}
596+
#[test]
597+
fn test_extract_pubkey_malleated_p2pkh_wrong_pubkey_hash() {
598+
// Use a not matching script pubkey to make the pubkey hash differ
599+
let script_pubkey =
600+
ScriptBuf::from_hex("76a914b675771222403e064d9fb4d676fcfef47585b07f88ac")
601+
.expect("should succeed");
602+
// only input from mainnet tx 4316fe7be359937317f42ffaf05ab02554297fb83096a0beb985a25f9e338215
603+
let txin = TxIn {
604+
previous_output: OutPoint {
605+
txid: "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16"
606+
.parse()
607+
.unwrap(),
608+
vout: 1,
609+
},
610+
script_sig: ScriptBuf::from_hex("0075473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338").expect("should succeed"),
611+
sequence: Sequence::MAX,
612+
witness: Witness::new(),
613+
};
614+
615+
assert!(extract_pubkey(txin, &script_pubkey).is_none());
616+
}
617+
}

0 commit comments

Comments
 (0)