Skip to content

Commit 22554ef

Browse files
committed
test(send): add unit test for create_silentpayment_partial_secret
1 parent 275448b commit 22554ef

1 file changed

Lines changed: 150 additions & 1 deletion

File tree

silentpayments/src/send/mod.rs

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,21 @@ pub fn create_silentpayment_scriptpubkeys(
124124
#[cfg_attr(coverage_nightly, coverage(off))]
125125
mod tests {
126126
use super::*;
127-
use bitcoin::secp256k1::{PublicKey, SecretKey};
127+
use bitcoin::{
128+
hex::DisplayHex,
129+
opcodes::all::OP_NUMEQUAL,
130+
script::Builder,
131+
secp256k1::{PublicKey, SecretKey},
132+
PrivateKey, PubkeyHash, WPubkeyHash,
133+
};
134+
use miniscript::ToPublicKey;
128135
use std::str::FromStr;
129136

130137
const SCAN_PK_1: &str = "03f95241dfb00d1d42e2f48fb72e31a06b9fd166c1d6bd12648b41977dd51b9a0b";
131138
const SPEND_PK_1: &str = "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af";
132139
const SCAN_PK_2: &str = "03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5";
133140
const SPEND_PK_2: &str = "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9";
141+
const PRIV_KEY: &str = "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy";
134142
const PARTIAL_SECRET_1: &str =
135143
"d5c68eccb3ddd0fab0bf504209b8b6ce3f51832beb136a5f91ade54bc059f9b8";
136144
const PARTIAL_SECRET_2: &str =
@@ -155,6 +163,147 @@ mod tests {
155163
(partial_secret, vec![sp_code_1, sp_code_2, sp_code_3])
156164
}
157165

166+
fn get_smallest_outpoint() -> [u8; 36] {
167+
let mut smallest_outpoint_bytes = [2u8; 36];
168+
smallest_outpoint_bytes[32..36].copy_from_slice(&1u32.to_le_bytes());
169+
smallest_outpoint_bytes
170+
}
171+
172+
#[test]
173+
fn test_create_partial_secret_base() {
174+
let expected_secret = "a2a81adc53cfa31e6e578c085239aab95cb37549f2fb0c8a9028dde883aa4a67";
175+
176+
let smallest_outpoint = get_smallest_outpoint();
177+
let spks_with_keys = {
178+
let secp = Secp256k1::new();
179+
let prv_k = PrivateKey::from_str(PRIV_KEY).expect("reading from constant");
180+
let pk = prv_k.public_key(&secp);
181+
let mut spks_with_keys: Vec<(ScriptBuf, SecretKey)> = vec![];
182+
183+
let script = Builder::new()
184+
.push_opcode(OP_NUMEQUAL)
185+
.push_verify()
186+
.into_script();
187+
let script_hash = script.script_hash();
188+
let pubkey_hash = PubkeyHash::hash(&pk.inner.serialize());
189+
let wpubkey_hash = WPubkeyHash::hash(&pk.inner.serialize());
190+
191+
let p2sh = ScriptBuf::new_p2sh(&script_hash);
192+
spks_with_keys.push((p2sh, prv_k.inner));
193+
194+
let p2pkh = ScriptBuf::new_p2pkh(&pubkey_hash);
195+
spks_with_keys.push((p2pkh, prv_k.inner));
196+
197+
let p2wpkh = ScriptBuf::new_p2wpkh(&wpubkey_hash);
198+
spks_with_keys.push((p2wpkh, prv_k.inner));
199+
200+
let (_, parity) = prv_k.inner.x_only_public_key(&secp);
201+
let even_sk = if parity == Parity::Odd {
202+
prv_k.inner.negate()
203+
} else {
204+
prv_k.inner
205+
};
206+
let pk = even_sk.public_key(&secp);
207+
let x_only_pubkey = pk.to_x_only_pubkey();
208+
let p2tr = ScriptBuf::new_p2tr(&secp, x_only_pubkey, None);
209+
spks_with_keys.push((p2tr, even_sk));
210+
211+
spks_with_keys
212+
};
213+
214+
let partial_secret =
215+
create_silentpayment_partial_secret(&smallest_outpoint, &spks_with_keys)
216+
.expect("should succeed");
217+
218+
assert_eq!(
219+
expected_secret,
220+
partial_secret.secret_bytes().as_hex().to_string()
221+
);
222+
}
223+
224+
#[test]
225+
fn test_create_partial_secret_no_inputs_for_secret_derivation() {
226+
let smallest_outpoint = get_smallest_outpoint();
227+
let spks_with_keys = {
228+
let secp = Secp256k1::new();
229+
let prv_k = PrivateKey::from_str(PRIV_KEY).expect("reading from constant");
230+
let pk = prv_k.public_key(&secp);
231+
let p2pk = ScriptBuf::new_p2pk(&pk);
232+
vec![(p2pk, prv_k.inner)]
233+
};
234+
235+
let error = create_silentpayment_partial_secret(&smallest_outpoint, &spks_with_keys)
236+
.expect_err("should fail");
237+
238+
assert_eq!(
239+
"No available inputs for shared secret derivation",
240+
error.to_string()
241+
);
242+
}
243+
244+
#[test]
245+
fn test_create_partial_secret_flip_p2tr_key() {
246+
let expected_secret = "1449c8855c10392e73734e7b4267c573667bc233d8bc69ce505341cb4a8b58a7";
247+
248+
let smallest_outpoint = get_smallest_outpoint();
249+
let spks_with_keys = {
250+
let secp = Secp256k1::new();
251+
let prv_k = PrivateKey::from_str(PRIV_KEY).expect("reading from constant");
252+
253+
let (_, parity) = prv_k.inner.x_only_public_key(&secp);
254+
// Flip the secret key so create_silentpayment_partial_secret flips it again
255+
let even_sk = if parity == Parity::Even {
256+
prv_k.inner.negate()
257+
} else {
258+
prv_k.inner
259+
};
260+
let pk = even_sk.public_key(&secp);
261+
let x_only_pubkey = pk.to_x_only_pubkey();
262+
let p2tr = ScriptBuf::new_p2tr(&secp, x_only_pubkey, None);
263+
264+
vec![(p2tr, even_sk)]
265+
};
266+
267+
let partial_secret =
268+
create_silentpayment_partial_secret(&smallest_outpoint, &spks_with_keys)
269+
.expect("should succeed");
270+
271+
assert_eq!(
272+
expected_secret,
273+
partial_secret.secret_bytes().as_hex().to_string()
274+
);
275+
}
276+
277+
#[test]
278+
fn test_create_partial_secret_point_to_infinity() {
279+
let smallest_outpoint = get_smallest_outpoint();
280+
let spks_with_keys = {
281+
let secp = Secp256k1::new();
282+
let prv_k = PrivateKey::from_str(PRIV_KEY).expect("reading from constant");
283+
let pk = prv_k.public_key(&secp);
284+
let mut spks_with_keys: Vec<(ScriptBuf, SecretKey)> = vec![];
285+
286+
let pubkey_hash = PubkeyHash::hash(&pk.inner.serialize());
287+
288+
let p2pkh = ScriptBuf::new_p2pkh(&pubkey_hash);
289+
spks_with_keys.push((p2pkh, prv_k.inner));
290+
291+
let neg_sk = prv_k.inner.negate();
292+
let neg_pk = neg_sk.public_key(&secp);
293+
let neg_pubkey_hash = PubkeyHash::hash(&neg_pk.serialize());
294+
let neg_p2pkh = ScriptBuf::new_p2pkh(&neg_pubkey_hash);
295+
296+
spks_with_keys.push((neg_p2pkh, neg_sk));
297+
298+
spks_with_keys
299+
};
300+
301+
let error = create_silentpayment_partial_secret(&smallest_outpoint, &spks_with_keys)
302+
.expect_err("should fail");
303+
304+
assert_eq!("Silent payment sending error: bad tweak", error.to_string());
305+
}
306+
158307
#[test]
159308
fn test_create_silentpayment_spk_base() {
160309
let (partial_secret, sp_codes) = setup_test_data();

0 commit comments

Comments
 (0)