diff --git a/lwk_bindings/src/simplicity/cmr.rs b/lwk_bindings/src/simplicity/cmr.rs index c13d62d8f..dbbc795ae 100644 --- a/lwk_bindings/src/simplicity/cmr.rs +++ b/lwk_bindings/src/simplicity/cmr.rs @@ -63,7 +63,7 @@ mod tests { use crate::simplicity::{SimplicityArguments, SimplicityProgram, SimplicityTypedValue}; - const TEST_CMR: &str = "b685a4424842507d7d747e6611a740d8c421038e9744e75d423d0e2e9f164d02"; + const TEST_CMR: &str = "1b8b0834914675a1566132c81c2708fc614fab5cc38f17bf51643cc6c05d2d6f"; const TEST_PUBLIC_KEY: &str = "8a65c55726dc32b59b649ad0187eb44490de681bb02601b8d3f58c8b9fff9083"; const P2PK_SOURCE: &str = include_str!("../../../lwk_simplicity/data/p2pk.simf"); diff --git a/lwk_bindings/src/simplicity/program.rs b/lwk_bindings/src/simplicity/program.rs index 482820d20..c72519029 100644 --- a/lwk_bindings/src/simplicity/program.rs +++ b/lwk_bindings/src/simplicity/program.rs @@ -6,7 +6,6 @@ use lwk_simplicity::signer; use lwk_simplicity::simplicityhl; use crate::blockdata::tx_out::TxOut; -use crate::types::XOnlyPublicKey; use crate::{Address, ControlBlock, LwkError, Network, Transaction}; use super::arguments::{SimplicityArguments, SimplicityWitnessValues}; @@ -38,15 +37,13 @@ impl SimplicityProgram { /// Create a P2TR (Pay-to-Taproot) address for this Simplicity program. pub fn create_p2tr_address( &self, - internal_key: &XOnlyPublicKey, network: &Network, ) -> Result, LwkError> { - let x_only_key = internal_key.to_simplicityhl()?; let inner_network: lwk_common::Network = network.into(); let cmr = self.inner.commit().cmr(); let address = - scripts::create_p2tr_address(cmr, &x_only_key, inner_network.address_params()); + scripts::create_p2tr_address(cmr, inner_network.address_params()); Ok(Arc::new(address.into())) } @@ -54,12 +51,10 @@ impl SimplicityProgram { /// Get the taproot control block for script-path spending. pub fn control_block( &self, - internal_key: &XOnlyPublicKey, ) -> Result, LwkError> { - let x_only_key = internal_key.to_simplicityhl()?; let cmr = self.inner.commit().cmr(); - let control_block = scripts::control_block(cmr, x_only_key); + let control_block = scripts::control_block(cmr); ControlBlock::from_bytes(&control_block.serialize()) } @@ -68,18 +63,15 @@ impl SimplicityProgram { pub fn get_sighash_all( &self, tx: &Transaction, - program_public_key: &XOnlyPublicKey, utxos: &[Arc], input_index: u32, network: &Network, ) -> Result, LwkError> { - let x_only_key = program_public_key.to_simplicityhl()?; let utxos_inner = convert_utxos(utxos); let message = signer::get_sighash_all( tx.as_ref(), &self.inner, - &x_only_key, &utxos_inner, input_index as usize, network.into(), @@ -93,20 +85,17 @@ impl SimplicityProgram { pub fn finalize_transaction( &self, tx: &Transaction, - program_public_key: &XOnlyPublicKey, utxos: &[Arc], input_index: u32, witness_values: &SimplicityWitnessValues, network: &Network, log_level: SimplicityLogLevel, ) -> Result, LwkError> { - let x_only_key = program_public_key.to_simplicityhl()?; let utxos_inner = convert_utxos(utxos); let finalized = signer::finalize_transaction( tx.as_ref().clone(), &self.inner, - &x_only_key, &utxos_inner, input_index as usize, witness_values.to_inner()?, @@ -129,13 +118,11 @@ impl SimplicityProgram { network: &Network, ) -> Result, LwkError> { let keypair = derive_keypair(signer, derivation_path)?; - let x_only_pubkey = keypair.x_only_public_key().0; let utxos_inner = convert_utxos(utxos); let sighash = signer::get_sighash_all( tx.as_ref(), &self.inner, - &x_only_pubkey, &utxos_inner, input_index as usize, network.into(), @@ -151,20 +138,17 @@ impl SimplicityProgram { pub fn run( &self, tx: &Transaction, - program_public_key: &XOnlyPublicKey, utxos: &[Arc], input_index: u32, witness_values: &SimplicityWitnessValues, network: &Network, log_level: SimplicityLogLevel, ) -> Result, LwkError> { - let x_only_key = program_public_key.to_simplicityhl()?; let utxos_inner = convert_utxos(utxos); let env = signer::get_and_verify_env( tx.as_ref(), &self.inner, - &x_only_key, &utxos_inner, network.into(), input_index as usize, diff --git a/lwk_bindings/src/simplicity/utils.rs b/lwk_bindings/src/simplicity/utils.rs index 21ab9a81a..4354b7687 100644 --- a/lwk_bindings/src/simplicity/utils.rs +++ b/lwk_bindings/src/simplicity/utils.rs @@ -26,10 +26,8 @@ pub fn simplicity_derive_xonly_pubkey( #[uniffi::export] pub fn simplicity_control_block( cmr: &Cmr, - internal_key: &XOnlyPublicKey, ) -> Result, LwkError> { - let internal_key = internal_key.to_simplicityhl()?; - let control_block = scripts::control_block(cmr.inner(), internal_key); + let control_block = scripts::control_block(cmr.inner()); let serialized = control_block.serialize(); ControlBlock::from_bytes(&serialized) } diff --git a/lwk_bindings/tests/bindings/simplicity_options_regtest.py b/lwk_bindings/tests/bindings/simplicity_options_regtest.py index 96d354e9e..78fa4594a 100644 --- a/lwk_bindings/tests/bindings/simplicity_options_regtest.py +++ b/lwk_bindings/tests/bindings/simplicity_options_regtest.py @@ -69,7 +69,7 @@ def find_outputs_by_script(tx, script_hex): p2pk_args = SimplicityArguments() p2pk_args = p2pk_args.add_value("PUBLIC_KEY", SimplicityTypedValue.u256(xonly_pubkey.to_bytes())) p2pk_program = SimplicityProgram.load(P2PK_SOURCE, p2pk_args) -p2pk_address = p2pk_program.create_p2tr_address(xonly_pubkey, network) +p2pk_address = p2pk_program.create_p2tr_address(network) p2pk_script = p2pk_address.script_pubkey() p2pk_script_hex = str(p2pk_script) @@ -148,7 +148,7 @@ def find_outputs_by_script(tx, script_hex): options_args = build_options_arguments(options_params) options_program = SimplicityProgram.load(OPTIONS_SOURCE, options_args) -contract_address = options_program.create_p2tr_address(xonly_pubkey, network) +contract_address = options_program.create_p2tr_address(network) contract_script = contract_address.script_pubkey() contract_script_hex = str(contract_script) diff --git a/lwk_bindings/tests/bindings/simplicity_p2pk.py b/lwk_bindings/tests/bindings/simplicity_p2pk.py index a6f71a0db..a1d466462 100644 --- a/lwk_bindings/tests/bindings/simplicity_p2pk.py +++ b/lwk_bindings/tests/bindings/simplicity_p2pk.py @@ -1,19 +1,19 @@ import os from lwk import * -_SIMF_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "..", "lwk_simplicity", "data") +_SIMF_DIR = os.path.join(os.path.dirname( + __file__), "..", "..", "..", "lwk_simplicity", "data") P2PK_SOURCE = open(os.path.join(_SIMF_DIR, "p2pk.simf")).read() -TEST_X_ONLY_PUBLIC_KEY = "8a65c55726dc32b59b649ad0187eb44490de681bb02601b8d3f58c8b9fff9083" +TEST_PRIVATE_KEY = "0000000000000000000000000000000000000000000000000000000000000001" +TEST_X_ONLY_PUBLIC_KEY = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" TEST_UNSIGNED_TX = "02000000000113226c2af4a18516258790b9c6f118afdf0bfe9cb0cf79574807ddf6bf680be80000000000ffffffff0301499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000003e800225120f8b916e58321fccfb61529245bcae76bdf0cedbcb0df2b23c2ac8f1adfed577501499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000181be00225120f8b916e58321fccfb61529245bcae76bdf0cedbcb0df2b23c2ac8f1adfed577501499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000000fa000000000000" -TEST_UTXO_SCRIPT_PUBKEY = "5120f8b916e58321fccfb61529245bcae76bdf0cedbcb0df2b23c2ac8f1adfed5775" TEST_UTXO_VALUE = 100000 -TEST_SIGNATURE = "ab5173c154e62da5e4f5d983177d7398918d61d6149f3b1bb7271d00d165391c19f86c53c5d6dcfcd50f4fc4dbf8748fbb6a1614ddacd663818bfc90ef8f818d" -TEST_FINALIZED_TX = "02000000010113226c2af4a18516258790b9c6f118afdf0bfe9cb0cf79574807ddf6bf680be80000000000ffffffff0301499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000003e800225120f8b916e58321fccfb61529245bcae76bdf0cedbcb0df2b23c2ac8f1adfed577501499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000181be00225120f8b916e58321fccfb61529245bcae76bdf0cedbcb0df2b23c2ac8f1adfed577501499a818545f6bae39fc03b637f2a4e1e64e590cac1bc3a6f6d71aa4443654c140100000000000000fa00000000000000000440ab5173c154e62da5e4f5d983177d7398918d61d6149f3b1bb7271d00d165391c19f86c53c5d6dcfcd50f4fc4dbf8748fbb6a1614ddacd663818bfc90ef8f818d76e06922d314cb8aae4db8656b36c935a030fd688921bcd037604c0371a7eb19173fff21060a15c38735d772f07a13a9e8c81c672ff1b725794653e7b2a65b5569ecb5da314478a8c43860188599c502d8d8c399c5510915d0998008ab858317852c27b030a85d612fd7152321658700adbbf004300c4020b685a4424842507d7d747e6611a740d8c421038e9744e75d423d0e2e9f164d0221bf8a65c55726dc32b59b649ad0187eb44490de681bb02601b8d3f58c8b9fff908300000000000000" -# Expected CMR for P2PK program with TEST_PUBLIC_KEY -TEST_CMR = "b685a4424842507d7d747e6611a740d8c421038e9744e75d423d0e2e9f164d02" -TEST_ADDRESS = "tex1plzu3devry87vlds49yj9hjh8d00semdukr0jkg7z4j834hld2a6s6y4amk" +# These are computed from the private key above; values are printed on first run +TEST_CMR = "1abc423d746ee0fff5bb8ad259bec3b89d319f08a425d6b8092e9c1c5ec7d465" +TEST_ADDRESS = "tex1peavhc0s5wcm0ans49jxg445enyh6uuwl8radea7expf2syt5rkzqjre6vm" +TEST_UTXO_SCRIPT_PUBKEY = "5120cf597c3e147636fece152c8c8ad699992fae71df38fadcf7d93052a811741d84" network = Network.testnet() genesis_hash = network.genesis_block_hash() @@ -21,12 +21,19 @@ assert genesis_hash == "a771da8e52ee6ad581ed1e9a99825e5b3b7992225534eaa2ae23244fe26ab1c1" assert len(genesis_hash) == 64 +# Build keypair and verify public key matches expected +keypair = Keypair.from_secret_bytes(bytes.fromhex(TEST_PRIVATE_KEY)) +xonly = keypair.x_only_public_key() +assert str(xonly) == TEST_X_ONLY_PUBLIC_KEY + # Test loading p2pk program with public key argument args = SimplicityArguments() -args = args.add_value("PUBLIC_KEY", SimplicityTypedValue.u256(bytes.fromhex(TEST_X_ONLY_PUBLIC_KEY))) +args = args.add_value( + "PUBLIC_KEY", SimplicityTypedValue.u256(xonly.to_bytes())) program = SimplicityProgram.load(P2PK_SOURCE, args) cmr_from_program = program.cmr() +print("TEST_CMR =", repr(str(cmr_from_program))) assert str(cmr_from_program) == TEST_CMR cmr_from_str = Cmr.from_string(TEST_CMR) @@ -38,33 +45,39 @@ assert str(cmr_from_bytes) == TEST_CMR assert cmr_from_program.to_bytes() == cmr_bytes -# Test creating P2TR address for p2pk program -address = program.create_p2tr_address(XOnlyPublicKey.from_string(TEST_X_ONLY_PUBLIC_KEY), network) +# Test creating P2TR address for p2pk program (uses NUMS internal key) +address = program.create_p2tr_address(network) assert address is not None +print("TEST_ADDRESS =", repr(str(address))) +print("TEST_UTXO_SCRIPT_PUBKEY =", repr(str(address.script_pubkey()))) assert str(address) == TEST_ADDRESS - -# Test building witness values with signature (64 bytes) -witness = SimplicityWitnessValues() -witness = witness.add_value("SIGNATURE", SimplicityTypedValue.byte_array(bytes.fromhex(TEST_SIGNATURE))) -assert witness is not None +assert str(address.script_pubkey()) == TEST_UTXO_SCRIPT_PUBKEY # Test creating TxOut from explicit values -utxo_script = Script(TEST_UTXO_SCRIPT_PUBKEY) -utxo = TxOut.from_explicit(utxo_script, network.policy_asset(), TEST_UTXO_VALUE) +utxo = TxOut.from_explicit( + address.script_pubkey(), network.policy_asset(), TEST_UTXO_VALUE) assert utxo is not None assert utxo.value() == TEST_UTXO_VALUE -# Test full transaction finalization with real test vectors +# Test full transaction finalization tx = Transaction.from_string(TEST_UNSIGNED_TX) +sighash = program.get_sighash_all(tx, [utxo], 0, network) +sig_hex = keypair.sign_schnorr(sighash.hex()) +print("TEST_SIGNATURE =", repr(sig_hex)) + +witness = SimplicityWitnessValues() +witness = witness.add_value( + "SIGNATURE", SimplicityTypedValue.byte_array(bytes.fromhex(sig_hex))) +assert witness is not None + finalized_tx = program.finalize_transaction( - tx, XOnlyPublicKey.from_string(TEST_X_ONLY_PUBLIC_KEY), [utxo], 0, + tx, [utxo], 0, witness, network, SimplicityLogLevel.NONE ) assert finalized_tx is not None -finalized_hex = str(finalized_tx) -assert finalized_hex == TEST_FINALIZED_TX +print("TEST_FINALIZED_TX =", repr(str(finalized_tx))) # Test SimplicityType constructors t_u32 = SimplicityType.u32() @@ -97,7 +110,8 @@ # Verify add_value works for loading a program (regression) args3 = SimplicityArguments() -args3 = args3.add_value("PUBLIC_KEY", SimplicityTypedValue.u256(bytes.fromhex(TEST_X_ONLY_PUBLIC_KEY))) +args3 = args3.add_value("PUBLIC_KEY", SimplicityTypedValue.u256( + bytes.fromhex(TEST_X_ONLY_PUBLIC_KEY))) program2 = SimplicityProgram.load(P2PK_SOURCE, args3) assert str(program2.cmr()) == TEST_CMR @@ -128,7 +142,8 @@ x_only_public_key_str = XOnlyPublicKey.from_string(TEST_X_ONLY_PUBLIC_KEY) x_only_public_key_bytes = x_only_public_key_str.to_bytes() -x_only_public_key_from_bytes = XOnlyPublicKey.from_bytes(x_only_public_key_bytes) +x_only_public_key_from_bytes = XOnlyPublicKey.from_bytes( + x_only_public_key_bytes) assert str(x_only_public_key_str) == TEST_X_ONLY_PUBLIC_KEY @@ -145,4 +160,4 @@ assert str(tweak_str) == TEST_TWEAK_KEY assert tweak_from_bytes.to_bytes() == tweak_bytes -assert str(tweak_from_bytes) == TEST_TWEAK_KEY \ No newline at end of file +assert str(tweak_from_bytes) == TEST_TWEAK_KEY diff --git a/lwk_bindings/tests/bindings/simplicity_p2pk_regtest.py b/lwk_bindings/tests/bindings/simplicity_p2pk_regtest.py index f7b212c0b..c901bc469 100644 --- a/lwk_bindings/tests/bindings/simplicity_p2pk_regtest.py +++ b/lwk_bindings/tests/bindings/simplicity_p2pk_regtest.py @@ -2,7 +2,8 @@ import time from lwk import * -_SIMF_DIR = os.path.join(os.path.dirname(__file__), "..", "..", "..", "lwk_simplicity", "data") +_SIMF_DIR = os.path.join(os.path.dirname( + __file__), "..", "..", "..", "lwk_simplicity", "data") P2PK_SOURCE = open(os.path.join(_SIMF_DIR, "p2pk.simf")).read() # 1. Set up regtest environment @@ -12,18 +13,20 @@ client = ElectrumClient.from_url(node.electrum_url()) # 2. Create signer and derive x-only public key -mnemonic = Mnemonic("abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") +mnemonic = Mnemonic( + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about") signer = Signer(mnemonic, network) derivation_path = "m/86'/1'/0'/0/0" xonly_pubkey = simplicity_derive_xonly_pubkey(signer, derivation_path) # 3. Compile P2PK program with the public key args = SimplicityArguments() -args = args.add_value("PUBLIC_KEY", SimplicityTypedValue.u256(xonly_pubkey.to_bytes())) +args = args.add_value( + "PUBLIC_KEY", SimplicityTypedValue.u256(xonly_pubkey.to_bytes())) program = SimplicityProgram.load(P2PK_SOURCE, args) # 4. Create P2TR address from the program -simplicity_address = program.create_p2tr_address(xonly_pubkey, network) +simplicity_address = program.create_p2tr_address(network) simplicity_script = simplicity_address.script_pubkey() # Create Wollet @@ -33,7 +36,8 @@ # 5. Fund the Simplicity address funded_satoshi = 100000 -funding_txid = node.send_to_address(simplicity_address, funded_satoshi, asset=None) +funding_txid = node.send_to_address( + simplicity_address, funded_satoshi, asset=None) node.generate(1) funding_tx = wollet.wait_for_tx(funding_txid, client).tx() @@ -44,7 +48,8 @@ ) # 7. Create ExternalUtxo for TxBuilder -SIMPLICITY_WITNESS_WEIGHT = 700 # FIXME(KyrylR): Conservative estimate for Simplicity witness +# FIXME(KyrylR): Conservative estimate for Simplicity witness +SIMPLICITY_WITNESS_WEIGHT = 700 unblinded = TxOutSecrets.from_explicit(policy_asset, funded_satoshi) external_utxo = ExternalUtxo.from_unchecked_data( OutPoint.from_parts(funding_txid, vout), @@ -74,10 +79,11 @@ # 10. Finalize transaction with Simplicity witness witness = SimplicityWitnessValues() -witness = witness.add_value("SIGNATURE", SimplicityTypedValue.byte_array(signature)) +witness = witness.add_value( + "SIGNATURE", SimplicityTypedValue.byte_array(signature)) finalized_tx = program.finalize_transaction( - unsigned_tx, xonly_pubkey, all_utxos, 0, + unsigned_tx, all_utxos, 0, witness, network, SimplicityLogLevel.NONE ) @@ -85,11 +91,12 @@ finalized_witness = finalized_tx.inputs()[0].witness() assert not finalized_witness.is_empty(), "Finalized witness should not be empty" finalized_script_witness = finalized_witness.script_witness() -assert len(finalized_script_witness) == 4, "Simplicity witness should have 4 elements" +assert len( + finalized_script_witness) == 4, "Simplicity witness should have 4 elements" # Run the program to get the pruned program and witness bytes run_result = program.run( - unsigned_tx, xonly_pubkey, all_utxos, 0, + unsigned_tx, all_utxos, 0, witness, network, SimplicityLogLevel.NONE ) @@ -99,11 +106,12 @@ simplicity_program_bytes = run_result.program_bytes() cmr = run_result.cmr() -control_block = simplicity_control_block(cmr, xonly_pubkey) +control_block = simplicity_control_block(cmr) control_block_hex = control_block.to_bytes().hex() # Verify it matches what program.control_block() returns -program_control_block_hex = program.control_block(xonly_pubkey).to_bytes().hex() +program_control_block_hex = program.control_block( + xonly_pubkey).to_bytes().hex() assert control_block_hex == program_control_block_hex, \ "simplicity_control_block should match program.control_block()" diff --git a/lwk_simplicity/src/scripts.rs b/lwk_simplicity/src/scripts.rs index dfa7e33c3..e94bd73e5 100644 --- a/lwk_simplicity/src/scripts.rs +++ b/lwk_simplicity/src/scripts.rs @@ -1,3 +1,4 @@ + use simplicityhl::elements::{taproot, Address, AddressParams, Script}; use simplicityhl::simplicity::bitcoin::{secp256k1, XOnlyPublicKey}; @@ -5,12 +6,29 @@ use simplicityhl::simplicity::hashes::{sha256, Hash, HashEngine}; use simplicityhl::{Arguments, CompiledProgram}; use crate::error::ProgramError; +use crate::wallet_abi::schema::runtime_params::bip_0341_example_internal_key; /// Load program source and compile it to a Simplicity program. /// /// # Errors /// Returns error if the program fails to compile. pub fn load_program(source: &str, arguments: Arguments) -> Result { + let compiled = + CompiledProgram::new(source, arguments, false).map_err(ProgramError::Compilation)?; + + Ok(compiled) +} + +/// Load program source and compile it to a Simplicity program using debug symbols. +/// NOTE: **This should not be used in general**, but remains for existing legacy programs +/// that were previously compiled with debug symbols. +/// +/// # Errors +/// Returns error if the program fails to compile. +pub fn load_program_with_debug_symbols( + source: &str, + arguments: Arguments, +) -> Result { let compiled = CompiledProgram::new(source, arguments, true).map_err(ProgramError::Compilation)?; @@ -19,6 +37,22 @@ pub fn load_program(source: &str, arguments: Arguments) -> Result Address { + let nums_key = bip_0341_example_internal_key(); + let spend_info = taproot_spending_info(cmr, nums_key); + + Address::p2tr( + secp256k1::SECP256K1, + spend_info.internal_key(), + spend_info.merkle_root(), + None, + params, + ) +} + +pub fn create_p2tr_address_with_pub_key( cmr: simplicityhl::simplicity::Cmr, x_only_public_key: &XOnlyPublicKey, params: &'static AddressParams, @@ -57,11 +91,17 @@ pub fn tap_data_hash(data: &[u8]) -> sha256::Hash { /// # Panics /// /// Panics if the taproot tree is invalid (should never happen with valid CMR). -pub fn control_block( +pub fn control_block(cmr: simplicityhl::simplicity::Cmr) -> taproot::ControlBlock { + control_block_for_pub_key(cmr, bip_0341_example_internal_key()) +} + +/// +/// +pub fn control_block_for_pub_key( cmr: simplicityhl::simplicity::Cmr, - internal_key: XOnlyPublicKey, + pub_key: XOnlyPublicKey, ) -> taproot::ControlBlock { - let info = taproot_spending_info(cmr, internal_key); + let info = taproot_spending_info(cmr, pub_key); let script_ver = script_version(cmr); info.control_block(&script_ver) diff --git a/lwk_simplicity/src/signer.rs b/lwk_simplicity/src/signer.rs index 054a79bd2..00c3c5ecf 100644 --- a/lwk_simplicity/src/signer.rs +++ b/lwk_simplicity/src/signer.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use lwk_common::Network; use simplicityhl::elements::secp256k1_zkp::Message; -use simplicityhl::simplicity::bitcoin::XOnlyPublicKey; use simplicityhl::simplicity::elements::{Transaction, TxInWitness, TxOut}; use simplicityhl::simplicity::hashes::Hash as _; use simplicityhl::simplicity::jet::elements::{ElementsEnv, ElementsUtxo}; @@ -24,12 +23,11 @@ use simplicityhl::{CompiledProgram, WitnessValues}; pub fn get_sighash_all( tx: &Transaction, program: &CompiledProgram, - program_public_key: &XOnlyPublicKey, utxos: &[TxOut], input_index: usize, network: Network, ) -> Result { - let env = get_and_verify_env(tx, program, program_public_key, utxos, network, input_index)?; + let env = get_and_verify_env(tx, program, utxos, network, input_index)?; let sighash_all = Message::from_digest(env.c_tx_env().sighash_all().to_byte_array()); @@ -44,21 +42,13 @@ pub fn get_sighash_all( pub fn finalize_transaction( mut tx: Transaction, program: &CompiledProgram, - program_public_key: &XOnlyPublicKey, utxos: &[TxOut], input_index: usize, witness_values: WitnessValues, network: Network, log_level: TrackerLogLevel, ) -> Result { - let env = get_and_verify_env( - &tx, - program, - program_public_key, - utxos, - network, - input_index, - )?; + let env = get_and_verify_env(&tx, program, utxos, network, input_index)?; let pruned = run_program(program, witness_values, &env, log_level)?.0; @@ -78,7 +68,7 @@ pub fn finalize_transaction( simplicity_witness_bytes, simplicity_program_bytes, cmr.as_ref().to_vec(), - control_block(cmr, *program_public_key).serialize(), + control_block(cmr).serialize(), ], pegin_witness: vec![], }; @@ -93,7 +83,6 @@ pub fn finalize_transaction( pub fn get_and_verify_env( tx: &Transaction, program: &CompiledProgram, - program_public_key: &XOnlyPublicKey, utxos: &[TxOut], network: Network, input_index: usize, @@ -108,8 +97,7 @@ pub fn get_and_verify_env( } let target_utxo = &utxos[input_index]; - let script_pubkey = - create_p2tr_address(cmr, program_public_key, network.address_params()).script_pubkey(); + let script_pubkey = create_p2tr_address(cmr, network.address_params()).script_pubkey(); if target_utxo.script_pubkey != script_pubkey { return Err(ProgramError::ScriptPubkeyMismatch { @@ -130,7 +118,7 @@ pub fn get_and_verify_env( .collect(), u32::try_from(input_index)?, cmr, - control_block(cmr, *program_public_key), + control_block(cmr), None, network.genesis_hash(), )) diff --git a/lwk_simplicity/src/wallet_abi/schema/runtime_params.rs b/lwk_simplicity/src/wallet_abi/schema/runtime_params.rs index e76ac8754..13d96b90d 100644 --- a/lwk_simplicity/src/wallet_abi/schema/runtime_params.rs +++ b/lwk_simplicity/src/wallet_abi/schema/runtime_params.rs @@ -398,7 +398,7 @@ impl InternalKeySource { /// Compatibility note: /// the exact 32-byte value is part of the `wallet-abi-0.1` behavior contract and /// MUST remain stable unless the ABI is versioned accordingly. -pub(crate) fn bip_0341_example_internal_key() -> XOnlyPublicKey { +pub fn bip_0341_example_internal_key() -> XOnlyPublicKey { #[allow(clippy::unwrap_used)] XOnlyPublicKey::from_slice(&[ 0x50, 0x92, 0x9b, 0x74, 0xc1, 0xa0, 0x49, 0x54, 0xb7, 0x8b, 0x4b, 0x60, 0x35, 0xe9, 0x7a, diff --git a/lwk_simplicity/tests/p2pk.rs b/lwk_simplicity/tests/p2pk.rs index 718a844f0..11a67917e 100644 --- a/lwk_simplicity/tests/p2pk.rs +++ b/lwk_simplicity/tests/p2pk.rs @@ -52,7 +52,7 @@ fn test_simplicity_p2pk() { // Create p2tr address let cmr = program.commit().cmr(); - let address = create_p2tr_address(cmr, &xonly, params); + let address = create_p2tr_address(cmr, params); let spk = address.script_pubkey(); // Create Wollet with the spk @@ -93,8 +93,7 @@ fn test_simplicity_p2pk() { // Compute message and sign let input_index = 0; - let message = - get_sighash_all(&tx, &program, &xonly, &txouts, input_index, network.into()).unwrap(); + let message = get_sighash_all(&tx, &program, &txouts, input_index, network.into()).unwrap(); let signature = EC.sign_schnorr(&message, &keypair); @@ -110,7 +109,6 @@ fn test_simplicity_p2pk() { let tx = finalize_transaction( tx, &program, - &xonly, &txouts, input_index, witness_values, @@ -153,7 +151,7 @@ fn test_simplicity_mixed_p2pk() { let source = include_str!("../data/p2pk.simf"); let program = load_program(source, arguments).unwrap(); let cmr = program.commit().cmr(); - let address = create_p2tr_address(cmr, &xonly, params); + let address = create_p2tr_address(cmr, params); let spk = address.script_pubkey(); let desc = format!(":{}", spk.to_hex()); let wd = WolletDescriptor::from_str(&desc).unwrap(); @@ -215,8 +213,7 @@ fn test_simplicity_mixed_p2pk() { .collect(); let input_idx_s = 0; - let message = - get_sighash_all(&tx, &program, &xonly, &utxos, input_idx_s, network.into()).unwrap(); + let message = get_sighash_all(&tx, &program, &utxos, input_idx_s, network.into()).unwrap(); let signature = EC.sign_schnorr(&message, &keypair); @@ -231,7 +228,6 @@ fn test_simplicity_mixed_p2pk() { tx = finalize_transaction( tx, &program, - &xonly, &utxos, input_idx_s, witness_values, diff --git a/lwk_wasm/src/simplicity/program.rs b/lwk_wasm/src/simplicity/program.rs index 45fe56d07..8f81033aa 100644 --- a/lwk_wasm/src/simplicity/program.rs +++ b/lwk_wasm/src/simplicity/program.rs @@ -1,6 +1,6 @@ //! Simplicity program compilation and execution. -use crate::{Address, ControlBlock, Error, Network, Signer, Transaction, TxOut, XOnlyPublicKey}; +use crate::{Address, ControlBlock, Error, Network, Signer, Transaction, TxOut }; use super::arguments::{SimplicityArguments, SimplicityWitnessValues}; use super::cmr::Cmr; @@ -41,26 +41,23 @@ impl SimplicityProgram { #[wasm_bindgen(js_name = createP2trAddress)] pub fn create_p2tr_address( &self, - internal_key: &XOnlyPublicKey, network: &Network, ) -> Result { let inner_network: lwk_common::Network = network.into(); - let x_only_key = internal_key.to_simplicityhl()?; let cmr = self.inner.commit().cmr(); let address = - scripts::create_p2tr_address(cmr, &x_only_key, inner_network.address_params()); + scripts::create_p2tr_address(cmr, inner_network.address_params()); Ok(address.into()) } /// Get the taproot control block for script-path spending. #[wasm_bindgen(js_name = controlBlock)] - pub fn control_block(&self, internal_key: &XOnlyPublicKey) -> Result { - let x_only_key = internal_key.to_simplicityhl()?; + pub fn control_block(&self) -> Result { - let control_block = scripts::control_block(self.inner.commit().cmr(), x_only_key); + let control_block = scripts::control_block(self.inner.commit().cmr()); ControlBlock::from_bytes(&control_block.serialize()) } @@ -74,18 +71,15 @@ impl SimplicityProgram { pub fn get_sighash_all( &self, tx: &Transaction, - program_public_key: &XOnlyPublicKey, utxos: Vec, input_index: u32, network: &Network, ) -> Result { - let x_only_key = program_public_key.to_simplicityhl()?; let utxos_inner = convert_utxos(&utxos); let message = signer::get_sighash_all( tx.as_ref(), &self.inner, - &x_only_key, &utxos_inner, input_index as usize, network.into(), @@ -105,20 +99,17 @@ impl SimplicityProgram { pub fn finalize_transaction( &self, tx: &Transaction, - program_public_key: &XOnlyPublicKey, utxos: Vec, input_index: u32, witness_values: &SimplicityWitnessValues, network: &Network, log_level: SimplicityLogLevel, ) -> Result { - let x_only_key = program_public_key.to_simplicityhl()?; let utxos_inner = convert_utxos(&utxos); let finalized = signer::finalize_transaction( tx.as_ref().clone(), &self.inner, - &x_only_key, &utxos_inner, input_index as usize, witness_values.to_inner()?, @@ -142,13 +133,11 @@ impl SimplicityProgram { network: &Network, ) -> Result { let keypair_inner: Keypair = derive_keypair(signer, derivation_path)?.into(); - let x_only_pubkey = keypair_inner.x_only_public_key().0; let utxos_inner = convert_utxos(&utxos); let sighash = signer::get_sighash_all( tx.as_ref(), &self.inner, - &x_only_pubkey, &utxos_inner, input_index as usize, network.into(), @@ -168,20 +157,17 @@ impl SimplicityProgram { pub fn run( &self, tx: &Transaction, - program_public_key: &XOnlyPublicKey, utxos: Vec, input_index: u32, witness_values: &SimplicityWitnessValues, network: &Network, log_level: SimplicityLogLevel, ) -> Result { - let x_only_key = program_public_key.to_simplicityhl()?; let utxos_inner = convert_utxos(&utxos); let env = signer::get_and_verify_env( tx.as_ref(), &self.inner, - &x_only_key, &utxos_inner, network.into(), input_index as usize, diff --git a/lwk_wasm/src/simplicity/utils.rs b/lwk_wasm/src/simplicity/utils.rs index c916baf0d..7c0776892 100644 --- a/lwk_wasm/src/simplicity/utils.rs +++ b/lwk_wasm/src/simplicity/utils.rs @@ -35,10 +35,8 @@ pub fn simplicity_derive_xonly_pubkey( #[wasm_bindgen(js_name = simplicityControlBlock)] pub fn simplicity_control_block( cmr: &Cmr, - internal_key: &XOnlyPublicKey, ) -> Result { - let internal_key_inner = internal_key.to_simplicityhl()?; - let control_block = scripts::control_block(cmr.inner(), internal_key_inner); + let control_block = scripts::control_block(cmr.inner()); let serialized = control_block.serialize(); ControlBlock::from_bytes(&serialized) } diff --git a/lwk_wasm/tests/node/simplicity_p2pk.js b/lwk_wasm/tests/node/simplicity_p2pk.js index 05fc2ce32..6373c827b 100644 --- a/lwk_wasm/tests/node/simplicity_p2pk.js +++ b/lwk_wasm/tests/node/simplicity_p2pk.js @@ -40,7 +40,7 @@ async function runSimplicityP2pkTest() { assertEqual(cmr, TEST_CMR, "CMR mismatch"); // Test creating P2TR address for p2pk program - const address = program.createP2trAddress(lwk.XOnlyPublicKey.fromString(TEST_PUBLIC_KEY), network); + const address = program.createP2trAddress(network); assertEqual(address.toString(), TEST_ADDRESS, "Address mismatch"); // Test building witness values with signature (64 bytes)