Skip to content

Commit e24ece0

Browse files
committed
Merge pull request #20 from 'test/add-unit-test-for-create-silentpayment-spks'
test(lib): do not report coverage for compute_shared_secret test(send): add unit test for create_silentpayment_scriptpubkeys
2 parents 3318edd + 3586972 commit e24ece0

2 files changed

Lines changed: 167 additions & 0 deletions

File tree

silentpayments/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ pub fn get_smallest_lexicographic_outpoint(outpoints: &[OutPoint]) -> [u8; 36] {
9494
result
9595
}
9696

97+
// Do not report coverage for this function as it is a wrapper around external lib function
98+
// shared_secret_point
99+
#[cfg_attr(coverage_nightly, coverage(off))]
97100
pub fn compute_shared_secret(sk: &SecretKey, pk: &PublicKey) -> PublicKey {
98101
let mut ss_bytes = [0u8; 65];
99102
ss_bytes[0] = 0x04;

silentpayments/src/send/mod.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,167 @@ pub fn create_silentpayment_scriptpubkeys(
115115

116116
Ok(payments)
117117
}
118+
119+
#[cfg(test)]
120+
#[cfg_attr(coverage_nightly, coverage(off))]
121+
mod tests {
122+
use super::*;
123+
use bitcoin::secp256k1::{PublicKey, SecretKey};
124+
use std::str::FromStr;
125+
126+
const SCAN_PK_1: &str = "03f95241dfb00d1d42e2f48fb72e31a06b9fd166c1d6bd12648b41977dd51b9a0b";
127+
const SPEND_PK_1: &str = "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af";
128+
const SCAN_PK_2: &str = "03c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5";
129+
const SPEND_PK_2: &str = "02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9";
130+
const PARTIAL_SECRET_1: &str =
131+
"d5c68eccb3ddd0fab0bf504209b8b6ce3f51832beb136a5f91ade54bc059f9b8";
132+
const PARTIAL_SECRET_2: &str =
133+
"e9b700555d60a8c4a874128c68b07ed7234248910db80d073d298e058df1786f";
134+
135+
fn setup_test_data() -> (SecretKey, Vec<SilentPaymentCode>) {
136+
let partial_secret = SecretKey::from_str(PARTIAL_SECRET_1).expect("reading from constant");
137+
138+
// Create some test SilentPaymentCodes
139+
let scan_1 = PublicKey::from_str(SCAN_PK_1).expect("reading from constant");
140+
let spend_1 = PublicKey::from_str(SPEND_PK_1).expect("reading from constant");
141+
142+
let scan_2 = PublicKey::from_str(SCAN_PK_2).expect("reading from constant");
143+
let spend_2 = PublicKey::from_str(SPEND_PK_2).expect("reading from constant");
144+
145+
let sp_code_1 = SilentPaymentCode::new_v0(scan_1, spend_1, bitcoin::Network::Bitcoin);
146+
147+
let sp_code_2 = SilentPaymentCode::new_v0(scan_2, spend_2, bitcoin::Network::Bitcoin);
148+
149+
let sp_code_3 = sp_code_1.add_label(Scalar::MAX).expect("should succeed");
150+
151+
(partial_secret, vec![sp_code_1, sp_code_2, sp_code_3])
152+
}
153+
154+
#[test]
155+
fn test_create_silentpayment_spk_base() {
156+
let (partial_secret, sp_codes) = setup_test_data();
157+
158+
let result =
159+
create_silentpayment_scriptpubkeys(partial_secret, &sp_codes).expect("should succeed");
160+
161+
assert_eq!(result.len(), 3);
162+
163+
for sp_code in &sp_codes {
164+
assert!(result.contains_key(sp_code));
165+
assert_eq!(result[sp_code].len(), 1);
166+
}
167+
}
168+
169+
#[test]
170+
fn test_create_silentpayment_spk_with_empty_outputs() {
171+
let (partial_secret, _) = setup_test_data();
172+
let empty_outputs: Vec<SilentPaymentCode> = vec![];
173+
174+
let result = create_silentpayment_scriptpubkeys(partial_secret, &empty_outputs)
175+
.expect("should succeed with empty outputs");
176+
177+
assert!(result.is_empty());
178+
}
179+
180+
#[test]
181+
fn test_create_silentpayment_spk_cache_behavior() {
182+
let (partial_secret, sp_codes) = setup_test_data();
183+
184+
assert_eq!(sp_codes[0].scan, sp_codes[2].scan);
185+
186+
let result =
187+
create_silentpayment_scriptpubkeys(partial_secret, &sp_codes).expect("should succeed");
188+
189+
// Get the pubkeys for codes with the same scan key
190+
let pubkeys_1 = &result[&sp_codes[0]];
191+
let pubkeys_3 = &result[&sp_codes[2]];
192+
193+
// They should be different despite having the same scan key
194+
// because the k value is incremented and the spend keys differ
195+
assert_ne!(pubkeys_1[0], pubkeys_3[0]);
196+
}
197+
198+
#[test]
199+
fn test_create_silentpayment_spk_multiple_calls_deterministic() {
200+
let (partial_secret, sp_codes) = setup_test_data();
201+
202+
// Generate sp_codes twice with the same inputs
203+
let result_1 =
204+
create_silentpayment_scriptpubkeys(partial_secret, &sp_codes).expect("should succeed");
205+
let result_2 =
206+
create_silentpayment_scriptpubkeys(partial_secret, &sp_codes).expect("should succeed");
207+
208+
// Results should be identical
209+
assert_eq!(result_1.len(), result_2.len());
210+
211+
for sp_code in &sp_codes {
212+
assert_eq!(result_1[sp_code], result_2[sp_code]);
213+
}
214+
}
215+
216+
#[test]
217+
fn test_create_silentpayment_spk_duplicate_payment_codes() {
218+
let (partial_secret, mut sp_codes) = setup_test_data();
219+
220+
// Add a duplicate of the first code
221+
sp_codes.push(sp_codes[0].clone());
222+
223+
let result = create_silentpayment_scriptpubkeys(partial_secret, &sp_codes)
224+
.expect("should succeed with duplicates");
225+
226+
// Should still have only 3 unique entries
227+
assert_eq!(result.len(), 3);
228+
229+
// First code should have 2 pubkeys now
230+
assert_eq!(result[&sp_codes[0]].len(), 2);
231+
232+
// And the pubkeys should be different due to k incrementing
233+
let pubkeys = &result[&sp_codes[0]];
234+
assert_ne!(pubkeys[0], pubkeys[1]);
235+
}
236+
237+
#[test]
238+
fn test_create_silentpayment_spk_large_number_of_sp_codes() {
239+
let (partial_secret, sp_codes) = setup_test_data();
240+
241+
let base_code = &sp_codes[0];
242+
243+
// Create many codes with the same scan key but different spend keys
244+
let mut sp_codes = Vec::new();
245+
for _ in 0..100 {
246+
let label = Scalar::random();
247+
248+
let code = base_code.add_label(label).expect("should succeed");
249+
250+
sp_codes.push(code);
251+
}
252+
253+
let result = create_silentpayment_scriptpubkeys(partial_secret, &sp_codes)
254+
.expect("should succeed with many sp_codes");
255+
256+
// Should have generated the correct number of sp_codes
257+
assert_eq!(result.len(), 100);
258+
259+
// All generated pubkeys should be unique
260+
let all_pubkeys: Vec<_> = result.values().flat_map(|v| v.iter().cloned()).collect();
261+
let unique_pubkeys: std::collections::HashSet<_> = all_pubkeys.iter().cloned().collect();
262+
assert_eq!(all_pubkeys.len(), unique_pubkeys.len());
263+
}
264+
265+
#[test]
266+
fn test_create_silentpayment_spk_different_partial_secrets() {
267+
let (partial_secret_1, sp_codes) = setup_test_data();
268+
let partial_secret_2 =
269+
SecretKey::from_str(PARTIAL_SECRET_2).expect("creating from constant");
270+
271+
let result_1 = create_silentpayment_scriptpubkeys(partial_secret_1, &sp_codes)
272+
.expect("should succeed");
273+
let result_2 = create_silentpayment_scriptpubkeys(partial_secret_2, &sp_codes)
274+
.expect("should succeed");
275+
276+
// Results should be different with different partial secrets
277+
for sp_code in &sp_codes {
278+
assert_ne!(result_1[sp_code], result_2[sp_code]);
279+
}
280+
}
281+
}

0 commit comments

Comments
 (0)