@@ -292,11 +292,24 @@ impl Plan {
292292 } )
293293 . into_script ( ) ,
294294 ) ,
295- DescriptorType :: Wpkh
296- | DescriptorType :: Wsh
297- | DescriptorType :: WshSortedMulti
298- | DescriptorType :: Tr => ( stack, ScriptBuf :: new ( ) ) ,
299- DescriptorType :: ShWsh | DescriptorType :: ShWshSortedMulti | DescriptorType :: ShWpkh => {
295+ DescriptorType :: Wpkh | DescriptorType :: Tr => ( stack, ScriptBuf :: new ( ) ) ,
296+ DescriptorType :: Wsh | DescriptorType :: WshSortedMulti => {
297+ let mut stack = stack;
298+ let witness_script = self
299+ . descriptor
300+ . explicit_script ( )
301+ . expect ( "descriptor is wsh" ) ;
302+ stack. push ( witness_script. into_bytes ( ) ) ;
303+ ( stack, ScriptBuf :: new ( ) )
304+ }
305+ DescriptorType :: ShWpkh => ( stack, self . descriptor . unsigned_script_sig ( ) ) ,
306+ DescriptorType :: ShWsh | DescriptorType :: ShWshSortedMulti => {
307+ let mut stack = stack;
308+ let witness_script = self
309+ . descriptor
310+ . explicit_script ( )
311+ . expect ( "descriptor is sh-wsh" ) ;
312+ stack. push ( witness_script. into_bytes ( ) ) ;
300313 ( stack, self . descriptor . unsigned_script_sig ( ) )
301314 }
302315 } )
@@ -1154,4 +1167,114 @@ mod test {
11541167 assert ! ( psbt_input. redeem_script. is_none( ) , "Redeem script present" ) ;
11551168 assert_eq ! ( psbt_input. bip32_derivation. len( ) , 2 , "Unexpected number of bip32_derivation" ) ;
11561169 }
1170+
1171+ #[ test]
1172+ fn test_plan_satisfy_wsh ( ) {
1173+ use std:: collections:: BTreeMap ;
1174+
1175+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
1176+
1177+ let secp = Secp256k1 :: new ( ) ;
1178+ // Generate a key from deterministic secret key
1179+ let sk =
1180+ secp256k1:: SecretKey :: from_slice ( & b"sally was a secret key, she said" [ ..] ) . unwrap ( ) ;
1181+ let pk = bitcoin:: PublicKey :: new ( secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ) ;
1182+ let msg = secp256k1:: Message :: from_digest_slice ( & b"michael was a message, amusingly" [ ..] )
1183+ . expect ( "32 bytes" ) ;
1184+ let sig = secp. sign_ecdsa ( & msg, & sk) ;
1185+ let ecdsa_sig = bitcoin:: ecdsa:: Signature {
1186+ signature : sig,
1187+ sighash_type : bitcoin:: sighash:: EcdsaSighashType :: All ,
1188+ } ;
1189+
1190+ // Create a wsh(pk(key)) descriptor - simple single key
1191+ let desc_str = format ! ( "wsh(pk({}))" , pk) ;
1192+ let desc = Descriptor :: < DefiniteDescriptorKey > :: from_str ( & desc_str) . unwrap ( ) ;
1193+
1194+ // Get the witness script for comparison
1195+ let witness_script = desc. explicit_script ( ) . expect ( "wsh has explicit script" ) ;
1196+
1197+ // Create the DefiniteDescriptorKey for the satisfier and DescriptorPublicKey for assets
1198+ let pk_str = pk. to_string ( ) ;
1199+ let definite_key = DefiniteDescriptorKey :: from_str ( & pk_str) . unwrap ( ) ;
1200+ let descriptor_key = DescriptorPublicKey :: from_str ( & pk_str) . unwrap ( ) ;
1201+
1202+ // Create a BTreeMap satisfier with the signature
1203+ let mut sig_map: BTreeMap < DefiniteDescriptorKey , bitcoin:: ecdsa:: Signature > =
1204+ BTreeMap :: new ( ) ;
1205+ sig_map. insert ( definite_key, ecdsa_sig) ;
1206+
1207+ // Create assets and get a plan
1208+ let assets = Assets :: new ( ) . add ( descriptor_key) ;
1209+ let plan = desc. plan ( & assets) . expect ( "plan should succeed" ) ;
1210+
1211+ // Call plan.satisfy() with the signature satisfier
1212+ let ( witness, script_sig) = plan. satisfy ( & sig_map) . expect ( "satisfy should succeed" ) ;
1213+
1214+ // For native P2WSH:
1215+ // - script_sig should be empty
1216+ // - witness should contain [signature, witness_script]
1217+ assert ! ( script_sig. is_empty( ) , "P2WSH script_sig should be empty" ) ;
1218+ assert_eq ! ( witness. len( ) , 2 , "P2WSH witness should have 2 elements (sig + witness_script)" ) ;
1219+ assert_eq ! (
1220+ witness. last( ) . unwrap( ) ,
1221+ & witness_script. into_bytes( ) ,
1222+ "Last witness element should be the witness script"
1223+ ) ;
1224+ }
1225+
1226+ #[ test]
1227+ fn test_plan_satisfy_sh_wsh ( ) {
1228+ use std:: collections:: BTreeMap ;
1229+
1230+ use bitcoin:: secp256k1:: { self , Secp256k1 } ;
1231+
1232+ let secp = Secp256k1 :: new ( ) ;
1233+ let sk =
1234+ secp256k1:: SecretKey :: from_slice ( & b"sally was a secret key, she said" [ ..] ) . unwrap ( ) ;
1235+ let pk = bitcoin:: PublicKey :: new ( secp256k1:: PublicKey :: from_secret_key ( & secp, & sk) ) ;
1236+ let msg = secp256k1:: Message :: from_digest_slice ( & b"michael was a message, amusingly" [ ..] )
1237+ . expect ( "32 bytes" ) ;
1238+ let sig = secp. sign_ecdsa ( & msg, & sk) ;
1239+ let ecdsa_sig = bitcoin:: ecdsa:: Signature {
1240+ signature : sig,
1241+ sighash_type : bitcoin:: sighash:: EcdsaSighashType :: All ,
1242+ } ;
1243+
1244+ // Create a sh(wsh(pk(key))) descriptor
1245+ let desc_str = format ! ( "sh(wsh(pk({})))" , pk) ;
1246+ let desc = Descriptor :: < DefiniteDescriptorKey > :: from_str ( & desc_str) . unwrap ( ) ;
1247+
1248+ // Get the witness script (inner script of the wsh)
1249+ let witness_script = desc. explicit_script ( ) . expect ( "sh-wsh has explicit script" ) ;
1250+
1251+ // Create the DefiniteDescriptorKey for the satisfier and DescriptorPublicKey for assets
1252+ let pk_str = pk. to_string ( ) ;
1253+ let definite_key = DefiniteDescriptorKey :: from_str ( & pk_str) . unwrap ( ) ;
1254+ let descriptor_key = DescriptorPublicKey :: from_str ( & pk_str) . unwrap ( ) ;
1255+
1256+ let mut sig_map: BTreeMap < DefiniteDescriptorKey , bitcoin:: ecdsa:: Signature > =
1257+ BTreeMap :: new ( ) ;
1258+ sig_map. insert ( definite_key, ecdsa_sig) ;
1259+
1260+ let assets = Assets :: new ( ) . add ( descriptor_key) ;
1261+ let plan = desc. plan ( & assets) . expect ( "plan should succeed" ) ;
1262+
1263+ let ( witness, script_sig) = plan. satisfy ( & sig_map) . expect ( "satisfy should succeed" ) ;
1264+
1265+ // For P2SH-P2WSH:
1266+ // - script_sig should contain the P2WSH script (witness script hash)
1267+ // - witness should contain [signature, witness_script]
1268+ assert ! ( !script_sig. is_empty( ) , "P2SH-P2WSH script_sig should not be empty" ) ;
1269+ assert_eq ! (
1270+ witness. len( ) ,
1271+ 2 ,
1272+ "P2SH-P2WSH witness should have 2 elements (sig + witness_script)"
1273+ ) ;
1274+ assert_eq ! (
1275+ witness. last( ) . unwrap( ) ,
1276+ & witness_script. into_bytes( ) ,
1277+ "Last witness element should be the witness script"
1278+ ) ;
1279+ }
11571280}
0 commit comments