@@ -124,13 +124,21 @@ pub fn create_silentpayment_scriptpubkeys(
124124#[ cfg_attr( coverage_nightly, coverage( off) ) ]
125125mod 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