From 35404a4fa7d479e7b21d2f53278669ab062b37bc Mon Sep 17 00:00:00 2001 From: Fernando Pelliccioni Date: Mon, 11 May 2026 20:12:09 +0200 Subject: [PATCH] sync: bring py-native up to date with the C-API surface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings the Python bindings level with the C-API headers shipped since the last py-native sync. The generator's full surface is now emitted to this repo: every class that ships in `kth/capi/` with a registered `py_root` has a matching `kth_py_native_*` wrapper here. Two return shapes that the Python backend used to reject — `pair` and `expected>` — are now bound, so `cashaddr_decode` and `coin_selection::create_tx_template` reach Python alongside everything else. ## New classes exposed to Python * **chain** — `input_point`, plus the new `abla` / `abla_config` / `abla_state` opaque-handles and the `abla_*_validity` enums (BCH 2024 May Elastic Block Adjustment Algorithm). * **vm** — `big_number`, `number`, `script_execution_context`. * **wallet** — `bitcoin_uri`, `cashaddr` (encode + decode), `coin_selection` (incl. `create_tx_template` / `create_tx_template_default_ratios` / `create_token_split_tx_template`) + `coin_selection_result`, `ek_private` / `ek_public` / `ek_token` (BIP38), `encrypted_keys` (BIP38 free fns), `language` (BIP39 wordlists), `message` (BIP137), `mnemonic` (BIP39), `stealth_address` / `stealth_receiver` / `stealth_sender` (BIP63). ## Pre-existing classes that gained new methods * `vm/program` — `pop_number` / `pop_big_number` / `pop_simple` / `top_number` / `top_big_number` (the BigInt opcode surface that landed on the C-API recently). * `chain/output_point`, `wallet/wallet_data` — minor regen tweaks. ## Tests Hand-written, patterned after the existing per-class test files. One file per new class covering smoke + round-trip: * `test_chain_input_point.py` * `test_vm_big_number.py` * `test_wallet_bitcoin_uri.py` * `test_wallet_cashaddr.py` (covers the new pair-returning `decode`) * `test_wallet_ek_private.py` * `test_wallet_language.py` * `test_wallet_message.py` * `test_wallet_mnemonic.py` ## Plumbing * `module.c` auto-emit picks up the new includes + 21 `KTH_REGISTER_METHODS` lines. * `setup.py` extended with the 21 new `.cpp` files under the existing chain / wallet / vm groups. * `kth_native.pyi` type stubs refreshed. * `capsule_names.h` — new capsule names for the new opaque handles. ## Out of scope * `recovery_id_to_magic` / `magic_to_recovery_id` — the Python backend models their out-pointer scalar params as scalar inputs, so the wrappers don't write back through the pointers. Pinned as a follow-up; the bindings are in this PR, but no test covers them yet. --- include/kth/py-native/capsule_names.h | 39 ++ include/kth/py-native/chain/abla.h | 27 + include/kth/py-native/chain/abla_config.h | 42 ++ include/kth/py-native/chain/abla_state.h | 32 + include/kth/py-native/chain/input_point.h | 40 ++ include/kth/py-native/chain/output_point.h | 1 + include/kth/py-native/vm/big_number.h | 53 ++ include/kth/py-native/vm/number.h | 54 ++ include/kth/py-native/vm/program.h | 8 +- .../py-native/vm/script_execution_context.h | 31 + include/kth/py-native/wallet/bitcoin_uri.h | 51 ++ include/kth/py-native/wallet/cashaddr.h | 24 + include/kth/py-native/wallet/coin_selection.h | 29 + .../py-native/wallet/coin_selection_result.h | 27 + include/kth/py-native/wallet/ek_private.h | 32 + include/kth/py-native/wallet/ek_public.h | 32 + include/kth/py-native/wallet/ek_token.h | 32 + include/kth/py-native/wallet/encrypted_keys.h | 23 + include/kth/py-native/wallet/language.h | 33 + include/kth/py-native/wallet/message.h | 29 + include/kth/py-native/wallet/mnemonic.h | 25 + .../kth/py-native/wallet/stealth_address.h | 38 ++ .../kth/py-native/wallet/stealth_receiver.h | 29 + include/kth/py-native/wallet/stealth_sender.h | 29 + include/kth/py-native/wallet/wallet_data.h | 1 + kth_native.pyi | 451 ++++++++++++- setup.py | 21 + src/chain/abla.cpp | 92 +++ src/chain/abla_config.cpp | 288 +++++++++ src/chain/abla_state.cpp | 178 +++++ src/chain/input_point.cpp | 306 +++++++++ src/chain/output_point.cpp | 16 + src/module.c | 42 ++ src/vm/big_number.cpp | 559 ++++++++++++++++ src/vm/number.cpp | 609 ++++++++++++++++++ src/vm/program.cpp | 218 ++++++- src/vm/script_execution_context.cpp | 159 +++++ src/wallet/bitcoin_uri.cpp | 476 ++++++++++++++ src/wallet/cashaddr.cpp | 74 +++ src/wallet/coin_selection.cpp | 373 +++++++++++ src/wallet/coin_selection_result.cpp | 93 +++ src/wallet/ek_private.cpp | 195 ++++++ src/wallet/ek_public.cpp | 195 ++++++ src/wallet/ek_token.cpp | 195 ++++++ src/wallet/encrypted_keys.cpp | 69 ++ src/wallet/language.cpp | 144 +++++ src/wallet/message.cpp | 165 +++++ src/wallet/mnemonic.cpp | 82 +++ src/wallet/stealth_address.cpp | 306 +++++++++ src/wallet/stealth_receiver.cpp | 193 ++++++ src/wallet/stealth_sender.cpp | 184 ++++++ src/wallet/wallet_data.cpp | 28 +- tests/test_chain_input_point.py | 73 +++ tests/test_vm_big_number.py | 57 ++ tests/test_wallet_bitcoin_uri.py | 42 ++ tests/test_wallet_cashaddr.py | 52 ++ tests/test_wallet_ek_private.py | 38 ++ tests/test_wallet_language.py | 40 ++ tests/test_wallet_message.py | 34 + tests/test_wallet_mnemonic.py | 33 + 60 files changed, 6834 insertions(+), 7 deletions(-) create mode 100644 include/kth/py-native/chain/abla.h create mode 100644 include/kth/py-native/chain/abla_config.h create mode 100644 include/kth/py-native/chain/abla_state.h create mode 100644 include/kth/py-native/chain/input_point.h create mode 100644 include/kth/py-native/vm/big_number.h create mode 100644 include/kth/py-native/vm/number.h create mode 100644 include/kth/py-native/vm/script_execution_context.h create mode 100644 include/kth/py-native/wallet/bitcoin_uri.h create mode 100644 include/kth/py-native/wallet/cashaddr.h create mode 100644 include/kth/py-native/wallet/coin_selection.h create mode 100644 include/kth/py-native/wallet/coin_selection_result.h create mode 100644 include/kth/py-native/wallet/ek_private.h create mode 100644 include/kth/py-native/wallet/ek_public.h create mode 100644 include/kth/py-native/wallet/ek_token.h create mode 100644 include/kth/py-native/wallet/encrypted_keys.h create mode 100644 include/kth/py-native/wallet/language.h create mode 100644 include/kth/py-native/wallet/message.h create mode 100644 include/kth/py-native/wallet/mnemonic.h create mode 100644 include/kth/py-native/wallet/stealth_address.h create mode 100644 include/kth/py-native/wallet/stealth_receiver.h create mode 100644 include/kth/py-native/wallet/stealth_sender.h create mode 100644 src/chain/abla.cpp create mode 100644 src/chain/abla_config.cpp create mode 100644 src/chain/abla_state.cpp create mode 100644 src/chain/input_point.cpp create mode 100644 src/vm/big_number.cpp create mode 100644 src/vm/number.cpp create mode 100644 src/vm/script_execution_context.cpp create mode 100644 src/wallet/bitcoin_uri.cpp create mode 100644 src/wallet/cashaddr.cpp create mode 100644 src/wallet/coin_selection.cpp create mode 100644 src/wallet/coin_selection_result.cpp create mode 100644 src/wallet/ek_private.cpp create mode 100644 src/wallet/ek_public.cpp create mode 100644 src/wallet/ek_token.cpp create mode 100644 src/wallet/encrypted_keys.cpp create mode 100644 src/wallet/language.cpp create mode 100644 src/wallet/message.cpp create mode 100644 src/wallet/mnemonic.cpp create mode 100644 src/wallet/stealth_address.cpp create mode 100644 src/wallet/stealth_receiver.cpp create mode 100644 src/wallet/stealth_sender.cpp create mode 100644 tests/test_chain_input_point.py create mode 100644 tests/test_vm_big_number.py create mode 100644 tests/test_wallet_bitcoin_uri.py create mode 100644 tests/test_wallet_cashaddr.py create mode 100644 tests/test_wallet_ek_private.py create mode 100644 tests/test_wallet_language.py create mode 100644 tests/test_wallet_message.py create mode 100644 tests/test_wallet_mnemonic.py diff --git a/include/kth/py-native/capsule_names.h b/include/kth/py-native/capsule_names.h index 06afd30..adf131c 100644 --- a/include/kth/py-native/capsule_names.h +++ b/include/kth/py-native/capsule_names.h @@ -25,6 +25,9 @@ extern "C" { #endif +#define KTH_PY_CAPSULE_CHAIN_ABLA "kth.chain.abla" +#define KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG "kth.chain.abla_config" +#define KTH_PY_CAPSULE_CHAIN_ABLA_STATE "kth.chain.abla_state" #define KTH_PY_CAPSULE_CHAIN_BLOCK "kth.chain.block" #define KTH_PY_CAPSULE_CHAIN_BLOCK_LIST "kth.chain.block_list" #define KTH_PY_CAPSULE_CHAIN_CHAIN_STATE "kth.chain.chain_state" @@ -39,6 +42,7 @@ extern "C" { #define KTH_PY_CAPSULE_CHAIN_HISTORY_COMPACT_LIST "kth.chain.history_compact_list" #define KTH_PY_CAPSULE_CHAIN_INPUT "kth.chain.input" #define KTH_PY_CAPSULE_CHAIN_INPUT_LIST "kth.chain.input_list" +#define KTH_PY_CAPSULE_CHAIN_INPUT_POINT "kth.chain.input_point" #define KTH_PY_CAPSULE_CHAIN_MERKLE_BLOCK "kth.chain.merkle_block" #define KTH_PY_CAPSULE_CHAIN_METRICS "kth.chain.metrics" #define KTH_PY_CAPSULE_CHAIN_OPERATION "kth.chain.operation" @@ -61,23 +65,46 @@ extern "C" { #define KTH_PY_CAPSULE_CHAIN_UTXO_LIST "kth.chain.utxo_list" #define KTH_PY_CAPSULE_CORE_BINARY "kth.core.binary" #define KTH_PY_CAPSULE_CORE_BOOL_LIST "kth.core.bool_list" +#define KTH_PY_CAPSULE_CORE_DOUBLE_LIST "kth.core.double_list" #define KTH_PY_CAPSULE_CORE_HASH_LIST "kth.core.hash_list" #define KTH_PY_CAPSULE_CORE_STRING_LIST "kth.core.string_list" +#define KTH_PY_CAPSULE_CORE_U32_LIST "kth.core.u32_list" #define KTH_PY_CAPSULE_CORE_U64_LIST "kth.core.u64_list" +#define KTH_PY_CAPSULE_VM_BIG_NUMBER "kth.vm.big_number" #define KTH_PY_CAPSULE_VM_DEBUG_SNAPSHOT "kth.vm.debug_snapshot" #define KTH_PY_CAPSULE_VM_DEBUG_SNAPSHOT_LIST "kth.vm.debug_snapshot_list" #define KTH_PY_CAPSULE_VM_INTERPRETER "kth.vm.interpreter" #define KTH_PY_CAPSULE_VM_METRICS "kth.vm.metrics" +#define KTH_PY_CAPSULE_VM_NUMBER "kth.vm.number" #define KTH_PY_CAPSULE_VM_PROGRAM "kth.vm.program" +#define KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT "kth.vm.script_execution_context" +#define KTH_PY_CAPSULE_WALLET_BITCOIN_URI "kth.wallet.bitcoin_uri" +#define KTH_PY_CAPSULE_WALLET_CASHADDR "kth.wallet.cashaddr" +#define KTH_PY_CAPSULE_WALLET_COIN_SELECTION "kth.wallet.coin_selection" +#define KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT "kth.wallet.coin_selection_result" +#define KTH_PY_CAPSULE_WALLET_DICTIONARY "kth.wallet.dictionary" +#define KTH_PY_CAPSULE_WALLET_DICTIONARY_LIST "kth.wallet.dictionary_list" #define KTH_PY_CAPSULE_WALLET_EC_COMPRESSED_LIST "kth.wallet.ec_compressed_list" #define KTH_PY_CAPSULE_WALLET_EC_PRIVATE "kth.wallet.ec_private" #define KTH_PY_CAPSULE_WALLET_EC_PUBLIC "kth.wallet.ec_public" +#define KTH_PY_CAPSULE_WALLET_EK_PRIVATE "kth.wallet.ek_private" +#define KTH_PY_CAPSULE_WALLET_EK_PUBLIC "kth.wallet.ek_public" +#define KTH_PY_CAPSULE_WALLET_EK_TOKEN "kth.wallet.ek_token" +#define KTH_PY_CAPSULE_WALLET_ENCRYPTED_KEYS "kth.wallet.encrypted_keys" #define KTH_PY_CAPSULE_WALLET_HD_PRIVATE "kth.wallet.hd_private" #define KTH_PY_CAPSULE_WALLET_HD_PUBLIC "kth.wallet.hd_public" +#define KTH_PY_CAPSULE_WALLET_LANGUAGE "kth.wallet.language" +#define KTH_PY_CAPSULE_WALLET_MESSAGE "kth.wallet.message" +#define KTH_PY_CAPSULE_WALLET_MNEMONIC "kth.wallet.mnemonic" #define KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS "kth.wallet.payment_address" #define KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS_LIST "kth.wallet.payment_address_list" +#define KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS "kth.wallet.stealth_address" +#define KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER "kth.wallet.stealth_receiver" +#define KTH_PY_CAPSULE_WALLET_STEALTH_SENDER "kth.wallet.stealth_sender" #define KTH_PY_CAPSULE_WALLET_WALLET_DATA "kth.wallet.wallet_data" +void kth_py_native_chain_abla_config_capsule_dtor(PyObject* capsule); +void kth_py_native_chain_abla_state_capsule_dtor(PyObject* capsule); void kth_py_native_chain_block_capsule_dtor(PyObject* capsule); void kth_py_native_chain_block_list_capsule_dtor(PyObject* capsule); void kth_py_native_chain_compact_block_capsule_dtor(PyObject* capsule); @@ -90,6 +117,7 @@ void kth_py_native_chain_history_compact_capsule_dtor(PyObject* capsule); void kth_py_native_chain_history_compact_list_capsule_dtor(PyObject* capsule); void kth_py_native_chain_input_capsule_dtor(PyObject* capsule); void kth_py_native_chain_input_list_capsule_dtor(PyObject* capsule); +void kth_py_native_chain_input_point_capsule_dtor(PyObject* capsule); void kth_py_native_chain_merkle_block_capsule_dtor(PyObject* capsule); void kth_py_native_chain_operation_capsule_dtor(PyObject* capsule); void kth_py_native_chain_operation_list_capsule_dtor(PyObject* capsule); @@ -110,16 +138,27 @@ void kth_py_native_chain_transaction_list_capsule_dtor(PyObject* capsule); void kth_py_native_chain_utxo_capsule_dtor(PyObject* capsule); void kth_py_native_chain_utxo_list_capsule_dtor(PyObject* capsule); void kth_py_native_core_binary_capsule_dtor(PyObject* capsule); +void kth_py_native_vm_big_number_capsule_dtor(PyObject* capsule); void kth_py_native_vm_debug_snapshot_capsule_dtor(PyObject* capsule); void kth_py_native_vm_debug_snapshot_list_capsule_dtor(PyObject* capsule); void kth_py_native_vm_metrics_capsule_dtor(PyObject* capsule); +void kth_py_native_vm_number_capsule_dtor(PyObject* capsule); void kth_py_native_vm_program_capsule_dtor(PyObject* capsule); +void kth_py_native_vm_script_execution_context_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_bitcoin_uri_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_coin_selection_result_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_ec_private_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_ec_public_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_ek_private_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_ek_public_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_ek_token_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_hd_private_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_hd_public_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_payment_address_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_payment_address_list_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_stealth_address_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_stealth_receiver_capsule_dtor(PyObject* capsule); +void kth_py_native_wallet_stealth_sender_capsule_dtor(PyObject* capsule); void kth_py_native_wallet_wallet_data_capsule_dtor(PyObject* capsule); #ifdef __cplusplus diff --git a/include/kth/py-native/chain/abla.h b/include/kth/py-native/chain/abla.h new file mode 100644 index 0000000..4b5bb1d --- /dev/null +++ b/include/kth/py-native/chain/abla.h @@ -0,0 +1,27 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_CHAIN_ABLA_H_ +#define KTH_PY_NATIVE_CHAIN_ABLA_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_chain_abla_set_max(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_default_config(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_validate_config(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_block_size_limit(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_validate_state(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_chain_abla_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_CHAIN_ABLA_H_ diff --git a/include/kth/py-native/chain/abla_config.h b/include/kth/py-native/chain/abla_config.h new file mode 100644 index 0000000..f196bab --- /dev/null +++ b/include/kth/py-native/chain/abla_config.h @@ -0,0 +1,42 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_CHAIN_ABLA_CONFIG_H_ +#define KTH_PY_NATIVE_CHAIN_ABLA_CONFIG_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_chain_abla_config_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_epsilon0(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_epsilon0(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_beta0(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_beta0(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_n0(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_n0(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_gamma_reciprocal(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_gamma_reciprocal(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_zeta_xB7(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_zeta_xB7(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_theta_reciprocal(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_theta_reciprocal(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_delta(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_delta(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_epsilon_max(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_epsilon_max(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_config_beta_max(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_config_set_beta_max(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_chain_abla_config_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_CHAIN_ABLA_CONFIG_H_ diff --git a/include/kth/py-native/chain/abla_state.h b/include/kth/py-native/chain/abla_state.h new file mode 100644 index 0000000..b9c820a --- /dev/null +++ b/include/kth/py-native/chain/abla_state.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_CHAIN_ABLA_STATE_H_ +#define KTH_PY_NATIVE_CHAIN_ABLA_STATE_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_chain_abla_state_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_chain_abla_state_construct(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_state_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_state_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_state_block_size(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_state_set_block_size(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_state_control_block_size(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_state_set_control_block_size(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_abla_state_elastic_buffer_size(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_abla_state_set_elastic_buffer_size(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_chain_abla_state_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_CHAIN_ABLA_STATE_H_ diff --git a/include/kth/py-native/chain/input_point.h b/include/kth/py-native/chain/input_point.h new file mode 100644 index 0000000..64055c8 --- /dev/null +++ b/include/kth/py-native/chain/input_point.h @@ -0,0 +1,40 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_CHAIN_INPUT_POINT_H_ +#define KTH_PY_NATIVE_CHAIN_INPUT_POINT_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_chain_input_point_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_chain_input_point_construct_from_data(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_construct(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_null(PyObject* self, PyObject* args); +PyObject* kth_py_native_chain_input_point_is_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_to_data(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_satoshi_fixed_size(PyObject* self, PyObject* args); +PyObject* kth_py_native_chain_input_point_serialized_size(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_hash(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_set_hash(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_index(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_set_index(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_chain_input_point_checksum(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_is_null(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_input_point_reset(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_chain_input_point_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_CHAIN_INPUT_POINT_H_ diff --git a/include/kth/py-native/chain/output_point.h b/include/kth/py-native/chain/output_point.h index 3d9da1b..8ed70d3 100644 --- a/include/kth/py-native/chain/output_point.h +++ b/include/kth/py-native/chain/output_point.h @@ -18,6 +18,7 @@ PyObject* kth_py_native_chain_output_point_construct_from_hash_index(PyObject* s PyObject* kth_py_native_chain_output_point_construct_from_point(PyObject* self, PyObject* arg); PyObject* kth_py_native_chain_output_point_copy(PyObject* self, PyObject* arg); PyObject* kth_py_native_chain_output_point_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_chain_output_point_null(PyObject* self, PyObject* args); PyObject* kth_py_native_chain_output_point_equals(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_chain_output_point_is_mature(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_chain_output_point_is_valid(PyObject* self, PyObject* arg); diff --git a/include/kth/py-native/vm/big_number.h b/include/kth/py-native/vm/big_number.h new file mode 100644 index 0000000..d243528 --- /dev/null +++ b/include/kth/py-native/vm/big_number.h @@ -0,0 +1,53 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_VM_BIG_NUMBER_H_ +#define KTH_PY_NATIVE_VM_BIG_NUMBER_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_vm_big_number_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_vm_big_number_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_construct_from_decimal_str(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_from_hex(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_serialize(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_deserialize(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_to_string(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_to_hex(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_sign(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_is_zero(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_is_nonzero(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_is_negative(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_to_int32_saturating(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_byte_count(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_compare(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_add(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_subtract(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_multiply(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_abs(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_negate(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_pow(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_pow_mod(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_math_modulo(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_data(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_set_data(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_big_number_is_true(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_is_false(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_big_number_is_minimally_encoded(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_vm_big_number_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_VM_BIG_NUMBER_H_ diff --git a/include/kth/py-native/vm/number.h b/include/kth/py-native/vm/number.h new file mode 100644 index 0000000..f9a6c93 --- /dev/null +++ b/include/kth/py-native/vm/number.h @@ -0,0 +1,54 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_VM_NUMBER_H_ +#define KTH_PY_NATIVE_VM_NUMBER_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_vm_number_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_vm_number_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_from_int(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_valid(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_set_data(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_data(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_int32(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_int64(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_is_true(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_is_false(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_number_greater(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_less(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_greater_or_equal(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_less_or_equal(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_add_int64(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_subtract_int64(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_add_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_subtract_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_multiply(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_add_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_add_int64(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_sub_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_sub_int64(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_mul_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_mul_int64(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_add_number2(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_sub_number2(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_safe_mul_number2(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_is_minimally_encoded(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_number_minimally_encode(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_vm_number_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_VM_NUMBER_H_ diff --git a/include/kth/py-native/vm/program.h b/include/kth/py-native/vm/program.h index 40469bf..711aca3 100644 --- a/include/kth/py-native/vm/program.h +++ b/include/kth/py-native/vm/program.h @@ -43,7 +43,11 @@ PyObject* kth_py_native_vm_program_push(PyObject* self, PyObject* args, PyObject PyObject* kth_py_native_vm_program_push_move(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_push_copy(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_drop(PyObject* self, PyObject* arg); -PyObject* kth_py_native_vm_program_pop(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_program_pop_simple(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_program_pop_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_program_pop_ternary(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_program_pop_big_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_program_pop_big_ternary(PyObject* self, PyObject* arg); PyObject* kth_py_native_vm_program_duplicate(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_swap(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_empty(PyObject* self, PyObject* arg); @@ -54,6 +58,8 @@ PyObject* kth_py_native_vm_program_is_stack_overflow(PyObject* self, PyObject* a PyObject* kth_py_native_vm_program_if_(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_item(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_top(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_program_top_number(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_program_top_big_number(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_vm_program_subscript(PyObject* self, PyObject* arg); PyObject* kth_py_native_vm_program_size(PyObject* self, PyObject* arg); PyObject* kth_py_native_vm_program_conditional_stack_size(PyObject* self, PyObject* arg); diff --git a/include/kth/py-native/vm/script_execution_context.h b/include/kth/py-native/vm/script_execution_context.h new file mode 100644 index 0000000..08de112 --- /dev/null +++ b/include/kth/py-native/vm/script_execution_context.h @@ -0,0 +1,31 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_VM_SCRIPT_EXECUTION_CONTEXT_H_ +#define KTH_PY_NATIVE_VM_SCRIPT_EXECUTION_CONTEXT_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_vm_script_execution_context_construct(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_vm_script_execution_context_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_input_index(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_transaction(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_input_count(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_output_count(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_tx_version(PyObject* self, PyObject* arg); +PyObject* kth_py_native_vm_script_execution_context_tx_locktime(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_vm_script_execution_context_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_VM_SCRIPT_EXECUTION_CONTEXT_H_ diff --git a/include/kth/py-native/wallet/bitcoin_uri.h b/include/kth/py-native/wallet/bitcoin_uri.h new file mode 100644 index 0000000..d565fc7 --- /dev/null +++ b/include/kth/py-native/wallet/bitcoin_uri.h @@ -0,0 +1,51 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_BITCOIN_URI_H_ +#define KTH_PY_NATIVE_WALLET_BITCOIN_URI_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_bitcoin_uri_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_bitcoin_uri_construct(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_less(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_encoded(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_amount(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_label(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_message(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_r(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_address(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_payment(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_stealth(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_bitcoin_uri_parameter(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_amount(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_label(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_message(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_r(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_address_string(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_address_payment_address(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_address_stealth_address(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_strict(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_scheme(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_authority(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_path(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_fragment(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_bitcoin_uri_set_parameter(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_bitcoin_uri_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_BITCOIN_URI_H_ diff --git a/include/kth/py-native/wallet/cashaddr.h b/include/kth/py-native/wallet/cashaddr.h new file mode 100644 index 0000000..6c21ad1 --- /dev/null +++ b/include/kth/py-native/wallet/cashaddr.h @@ -0,0 +1,24 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_CASHADDR_H_ +#define KTH_PY_NATIVE_WALLET_CASHADDR_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_cashaddr_encode(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_cashaddr_decode(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_cashaddr_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_CASHADDR_H_ diff --git a/include/kth/py-native/wallet/coin_selection.h b/include/kth/py-native/wallet/coin_selection.h new file mode 100644 index 0000000..7f15d00 --- /dev/null +++ b/include/kth/py-native/wallet/coin_selection.h @@ -0,0 +1,29 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_COIN_SELECTION_H_ +#define KTH_PY_NATIVE_WALLET_COIN_SELECTION_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_coin_selection_select_utxos(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_coin_selection_select_utxos_send_all(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_coin_selection_select_utxos_both(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_coin_selection_create_token_split_tx_template(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_coin_selection_create_tx_template(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_coin_selection_create_tx_template_default_ratios(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_coin_selection_make_change_ratios(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_coin_selection_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_COIN_SELECTION_H_ diff --git a/include/kth/py-native/wallet/coin_selection_result.h b/include/kth/py-native/wallet/coin_selection_result.h new file mode 100644 index 0000000..54cc82d --- /dev/null +++ b/include/kth/py-native/wallet/coin_selection_result.h @@ -0,0 +1,27 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_COIN_SELECTION_RESULT_H_ +#define KTH_PY_NATIVE_WALLET_COIN_SELECTION_RESULT_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_coin_selection_result_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_coin_selection_result_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_coin_selection_result_total_selected_bch(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_coin_selection_result_total_selected_token(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_coin_selection_result_estimated_size(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_wallet_coin_selection_result_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_COIN_SELECTION_RESULT_H_ diff --git a/include/kth/py-native/wallet/ek_private.h b/include/kth/py-native/wallet/ek_private.h new file mode 100644 index 0000000..e9f68a6 --- /dev/null +++ b/include/kth/py-native/wallet/ek_private.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_EK_PRIVATE_H_ +#define KTH_PY_NATIVE_WALLET_EK_PRIVATE_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_ek_private_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_ek_private_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_private_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_private_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_private_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_private_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_private_less(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_private_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_private_encoded(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_private_private_key(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_wallet_ek_private_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_EK_PRIVATE_H_ diff --git a/include/kth/py-native/wallet/ek_public.h b/include/kth/py-native/wallet/ek_public.h new file mode 100644 index 0000000..3d2cc33 --- /dev/null +++ b/include/kth/py-native/wallet/ek_public.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_EK_PUBLIC_H_ +#define KTH_PY_NATIVE_WALLET_EK_PUBLIC_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_ek_public_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_ek_public_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_public_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_public_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_public_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_public_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_public_less(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_public_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_public_encoded(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_public_public_key(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_wallet_ek_public_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_EK_PUBLIC_H_ diff --git a/include/kth/py-native/wallet/ek_token.h b/include/kth/py-native/wallet/ek_token.h new file mode 100644 index 0000000..7c76b4b --- /dev/null +++ b/include/kth/py-native/wallet/ek_token.h @@ -0,0 +1,32 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_EK_TOKEN_H_ +#define KTH_PY_NATIVE_WALLET_EK_TOKEN_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_ek_token_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_ek_token_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_token_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_token_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_token_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_token_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_token_less(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_ek_token_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_token_encoded(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_ek_token_token(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_wallet_ek_token_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_EK_TOKEN_H_ diff --git a/include/kth/py-native/wallet/encrypted_keys.h b/include/kth/py-native/wallet/encrypted_keys.h new file mode 100644 index 0000000..8b2296b --- /dev/null +++ b/include/kth/py-native/wallet/encrypted_keys.h @@ -0,0 +1,23 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_ENCRYPTED_KEYS_H_ +#define KTH_PY_NATIVE_WALLET_ENCRYPTED_KEYS_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_encrypted_keys_create_key_pair(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_encrypted_keys_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_ENCRYPTED_KEYS_H_ diff --git a/include/kth/py-native/wallet/language.h b/include/kth/py-native/wallet/language.h new file mode 100644 index 0000000..4e2954f --- /dev/null +++ b/include/kth/py-native/wallet/language.h @@ -0,0 +1,33 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_LANGUAGE_H_ +#define KTH_PY_NATIVE_WALLET_LANGUAGE_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_language_en(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_es(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_ja(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_it(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_fr(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_cs(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_ru(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_uk(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_zh_Hans(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_zh_Hant(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_language_all(PyObject* self, PyObject* args); + +extern PyMethodDef kth_py_native_wallet_language_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_LANGUAGE_H_ diff --git a/include/kth/py-native/wallet/message.h b/include/kth/py-native/wallet/message.h new file mode 100644 index 0000000..e5bb9fe --- /dev/null +++ b/include/kth/py-native/wallet/message.h @@ -0,0 +1,29 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_MESSAGE_H_ +#define KTH_PY_NATIVE_WALLET_MESSAGE_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_message_hash_message(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_message_sign_message_ec_private(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_message_sign_message_string(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_message_sign_message_hash(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_message_verify_message(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_message_recovery_id_to_magic(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_message_magic_to_recovery_id(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_message_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_MESSAGE_H_ diff --git a/include/kth/py-native/wallet/mnemonic.h b/include/kth/py-native/wallet/mnemonic.h new file mode 100644 index 0000000..7b13e1a --- /dev/null +++ b/include/kth/py-native/wallet/mnemonic.h @@ -0,0 +1,25 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_MNEMONIC_H_ +#define KTH_PY_NATIVE_WALLET_MNEMONIC_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_mnemonic_create_mnemonic(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_mnemonic_validate_mnemonic_dictionary(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_mnemonic_validate_mnemonic_dictionary_list(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_mnemonic_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_MNEMONIC_H_ diff --git a/include/kth/py-native/wallet/stealth_address.h b/include/kth/py-native/wallet/stealth_address.h new file mode 100644 index 0000000..f2205fd --- /dev/null +++ b/include/kth/py-native/wallet/stealth_address.h @@ -0,0 +1,38 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_STEALTH_ADDRESS_H_ +#define KTH_PY_NATIVE_WALLET_STEALTH_ADDRESS_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_stealth_address_construct_default(PyObject* self, PyObject* args); +PyObject* kth_py_native_wallet_stealth_address_construct_from_decoded(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_address_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_address_construct_from_binary_scan_key_spend_keys_signatures_version(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_address_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_equals(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_address_less(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_address_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_encoded(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_version(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_scan_key(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_spend_keys(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_signatures(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_filter(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_address_to_chunk(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_wallet_stealth_address_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_STEALTH_ADDRESS_H_ diff --git a/include/kth/py-native/wallet/stealth_receiver.h b/include/kth/py-native/wallet/stealth_receiver.h new file mode 100644 index 0000000..f5b9afb --- /dev/null +++ b/include/kth/py-native/wallet/stealth_receiver.h @@ -0,0 +1,29 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_STEALTH_RECEIVER_H_ +#define KTH_PY_NATIVE_WALLET_STEALTH_RECEIVER_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_stealth_receiver_construct(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_receiver_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_receiver_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_receiver_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_receiver_stealth_address(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_receiver_derive_address(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_receiver_derive_private(PyObject* self, PyObject* args, PyObject* kwds); + +extern PyMethodDef kth_py_native_wallet_stealth_receiver_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_STEALTH_RECEIVER_H_ diff --git a/include/kth/py-native/wallet/stealth_sender.h b/include/kth/py-native/wallet/stealth_sender.h new file mode 100644 index 0000000..91b8c7e --- /dev/null +++ b/include/kth/py-native/wallet/stealth_sender.h @@ -0,0 +1,29 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef KTH_PY_NATIVE_WALLET_STEALTH_SENDER_H_ +#define KTH_PY_NATIVE_WALLET_STEALTH_SENDER_H_ + +#define PY_SSIZE_T_CLEAN +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* kth_py_native_wallet_stealth_sender_construct_from_stealth_address_seed_binary_version(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_sender_construct_from_ephemeral_private_stealth_address_seed_binary_version(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_stealth_sender_copy(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_sender_destruct(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_sender_valid(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_sender_stealth_script(PyObject* self, PyObject* arg); +PyObject* kth_py_native_wallet_stealth_sender_payment_address(PyObject* self, PyObject* arg); + +extern PyMethodDef kth_py_native_wallet_stealth_sender_methods[]; + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // KTH_PY_NATIVE_WALLET_STEALTH_SENDER_H_ diff --git a/include/kth/py-native/wallet/wallet_data.h b/include/kth/py-native/wallet/wallet_data.h index b719f18..845b4dd 100644 --- a/include/kth/py-native/wallet/wallet_data.h +++ b/include/kth/py-native/wallet/wallet_data.h @@ -21,6 +21,7 @@ PyObject* kth_py_native_wallet_wallet_data_set_xpub(PyObject* self, PyObject* ar PyObject* kth_py_native_wallet_wallet_data_encrypted_seed(PyObject* self, PyObject* arg); PyObject* kth_py_native_wallet_wallet_data_set_encrypted_seed(PyObject* self, PyObject* args, PyObject* kwds); PyObject* kth_py_native_wallet_wallet_data_create(PyObject* self, PyObject* args, PyObject* kwds); +PyObject* kth_py_native_wallet_wallet_data_create_simple(PyObject* self, PyObject* args, PyObject* kwds); extern PyMethodDef kth_py_native_wallet_wallet_data_methods[]; diff --git a/kth_native.pyi b/kth_native.pyi index 2c5ed1e..6bd8d6c 100644 --- a/kth_native.pyi +++ b/kth_native.pyi @@ -618,6 +618,33 @@ def chain_point_list_nth(list: PointList, index: int) -> Point: ... def chain_point_list_assign_at(list: PointList, index: int, elem: Point) -> None: ... def chain_point_list_erase(list: PointList, index: int) -> None: ... +# ─── InputPoint (auto-generated, do not edit) ───────────────────────── + +class InputPoint: + """Opaque handle to a `kth::domain::chain::point`. Constructed by + `chain_input_point_construct_*` and released by + `chain_input_point_destruct`.""" + ... + +def chain_input_point_construct_default() -> InputPoint: ... +def chain_input_point_construct_from_data(reader: bytes, wire: bool) -> InputPoint: ... +def chain_input_point_construct(hash: bytes, index: int) -> InputPoint: ... +def chain_input_point_copy(self: InputPoint) -> InputPoint: ... +def chain_input_point_destruct(self: InputPoint) -> None: ... +def chain_input_point_equals(self: InputPoint, other: InputPoint) -> bool: ... +def chain_input_point_null() -> "Point" | None: ... +def chain_input_point_is_valid(self: InputPoint) -> bool: ... +def chain_input_point_to_data(self: InputPoint, wire: bool) -> bytes: ... +def chain_input_point_satoshi_fixed_size() -> int: ... +def chain_input_point_serialized_size(self: InputPoint, wire: bool) -> int: ... +def chain_input_point_hash(self: InputPoint) -> bytes: ... +def chain_input_point_set_hash(self: InputPoint, value: bytes) -> None: ... +def chain_input_point_index(self: InputPoint) -> int: ... +def chain_input_point_set_index(self: InputPoint, value: int) -> None: ... +def chain_input_point_checksum(self: InputPoint) -> int: ... +def chain_input_point_is_null(self: InputPoint) -> bool: ... +def chain_input_point_reset(self: InputPoint) -> None: ... + # ─── OutputPoint (auto-generated, do not edit) ───────────────────────── class OutputPoint: @@ -632,6 +659,7 @@ def chain_output_point_construct_from_hash_index(hash: bytes, index: int) -> Out def chain_output_point_construct_from_point(x: "Point") -> OutputPoint: ... def chain_output_point_copy(self: OutputPoint) -> OutputPoint: ... def chain_output_point_destruct(self: OutputPoint) -> None: ... +def chain_output_point_null() -> "OutputPoint" | None: ... def chain_output_point_equals(self: OutputPoint, other: OutputPoint) -> bool: ... def chain_output_point_is_mature(self: OutputPoint, height: int) -> bool: ... def chain_output_point_is_valid(self: OutputPoint) -> bool: ... @@ -1471,6 +1499,68 @@ def chain_utxo_list_nth(list: UtxoList, index: int) -> Utxo: ... def chain_utxo_list_assign_at(list: UtxoList, index: int, elem: Utxo) -> None: ... def chain_utxo_list_erase(list: UtxoList, index: int) -> None: ... +# ─── AblaConfig (auto-generated, do not edit) ───────────────────────── + +class AblaConfig: + """Opaque handle to a `kth::domain::chain::abla::config`. Constructed by + `chain_abla_config_construct_*` and released by + `chain_abla_config_destruct`.""" + ... + +def chain_abla_config_copy(self: AblaConfig) -> AblaConfig: ... +def chain_abla_config_destruct(self: AblaConfig) -> None: ... +def chain_abla_config_epsilon0(self: AblaConfig) -> int: ... +def chain_abla_config_set_epsilon0(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_beta0(self: AblaConfig) -> int: ... +def chain_abla_config_set_beta0(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_n0(self: AblaConfig) -> int: ... +def chain_abla_config_set_n0(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_gamma_reciprocal(self: AblaConfig) -> int: ... +def chain_abla_config_set_gamma_reciprocal(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_zeta_xB7(self: AblaConfig) -> int: ... +def chain_abla_config_set_zeta_xB7(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_theta_reciprocal(self: AblaConfig) -> int: ... +def chain_abla_config_set_theta_reciprocal(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_delta(self: AblaConfig) -> int: ... +def chain_abla_config_set_delta(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_epsilon_max(self: AblaConfig) -> int: ... +def chain_abla_config_set_epsilon_max(self: AblaConfig, value: int) -> None: ... +def chain_abla_config_beta_max(self: AblaConfig) -> int: ... +def chain_abla_config_set_beta_max(self: AblaConfig, value: int) -> None: ... + +# ─── AblaState (auto-generated, do not edit) ───────────────────────── + +class AblaState: + """Opaque handle to a `kth::domain::chain::abla::state`. Constructed by + `chain_abla_state_construct_*` and released by + `chain_abla_state_destruct`.""" + ... + +def chain_abla_state_construct_default() -> AblaState: ... +def chain_abla_state_construct(cfg: "AblaConfig", block_size: int) -> AblaState: ... +def chain_abla_state_copy(self: AblaState) -> AblaState: ... +def chain_abla_state_destruct(self: AblaState) -> None: ... +def chain_abla_state_block_size(self: AblaState) -> int: ... +def chain_abla_state_set_block_size(self: AblaState, value: int) -> None: ... +def chain_abla_state_control_block_size(self: AblaState) -> int: ... +def chain_abla_state_set_control_block_size(self: AblaState, value: int) -> None: ... +def chain_abla_state_elastic_buffer_size(self: AblaState) -> int: ... +def chain_abla_state_set_elastic_buffer_size(self: AblaState, value: int) -> None: ... + +# ─── Abla (auto-generated, do not edit) ───────────────────────── + +class Abla: + """Opaque handle to a `kth::domain::chain::abla`. Constructed by + `chain_abla_construct_*` and released by + `chain_abla_destruct`.""" + ... + +def chain_abla_set_max(cfg: "AblaConfig") -> None: ... +def chain_abla_default_config(default_block_size: int, fixed_size: bool) -> "AblaConfig" | None: ... +def chain_abla_validate_config(cfg: "AblaConfig") -> int: ... +def chain_abla_block_size_limit(st: "AblaState") -> int: ... +def chain_abla_validate_state(st: "AblaState", cfg: "AblaConfig") -> int: ... + # ─── Program (auto-generated, do not edit) ───────────────────────── class Program: @@ -1510,7 +1600,11 @@ def vm_program_push(self: Program, value: bool) -> None: ... def vm_program_push_move(self: Program, item: bytes) -> None: ... def vm_program_push_copy(self: Program, item: bytes) -> None: ... def vm_program_drop(self: Program) -> None: ... -def vm_program_pop(self: Program) -> bytes: ... +def vm_program_pop_simple(self: Program) -> bytes: ... +def vm_program_pop_number(self: Program, maximum_size: int) -> "Number": ... +def vm_program_pop_ternary(self: Program) -> tuple["Number", "Number", "Number"]: ... +def vm_program_pop_big_number(self: Program, maximum_size: int) -> "BigNumber": ... +def vm_program_pop_big_ternary(self: Program) -> tuple["BigNumber", "BigNumber", "BigNumber"]: ... def vm_program_duplicate(self: Program, index: int) -> None: ... def vm_program_swap(self: Program, index_left: int, index_right: int) -> None: ... def vm_program_empty(self: Program) -> bool: ... @@ -1521,6 +1615,8 @@ def vm_program_is_stack_overflow(self: Program, extra: int) -> bool: ... def vm_program_if_(self: Program, op: "Operation") -> bool: ... def vm_program_item(self: Program, index: int) -> bytes: ... def vm_program_top(self: Program) -> bytes: ... +def vm_program_top_number(self: Program, maximum_size: int) -> "Number": ... +def vm_program_top_big_number(self: Program, maximum_size: int) -> "BigNumber": ... def vm_program_subscript(self: Program) -> "OperationList" | None: ... def vm_program_size(self: Program) -> int: ... def vm_program_conditional_stack_size(self: Program) -> int: ... @@ -1611,6 +1707,105 @@ def vm_metrics_set_native_script_limits(self: Metrics, standard: bool, script_si def vm_metrics_composite_op_cost_script_flags(self: Metrics, flags: int) -> int: ... def vm_metrics_composite_op_cost_bool(self: Metrics, standard: bool) -> int: ... +# ─── ScriptExecutionContext (auto-generated, do not edit) ───────────────────────── + +class ScriptExecutionContext: + """Opaque handle to a `kth::domain::machine::script_execution_context`. Constructed by + `vm_script_execution_context_construct_*` and released by + `vm_script_execution_context_destruct`.""" + ... + +def vm_script_execution_context_construct(input_index: int, transaction: "Transaction") -> ScriptExecutionContext: ... +def vm_script_execution_context_copy(self: ScriptExecutionContext) -> ScriptExecutionContext: ... +def vm_script_execution_context_destruct(self: ScriptExecutionContext) -> None: ... +def vm_script_execution_context_input_index(self: ScriptExecutionContext) -> int: ... +def vm_script_execution_context_transaction(self: ScriptExecutionContext) -> "Transaction" | None: ... +def vm_script_execution_context_input_count(self: ScriptExecutionContext) -> int: ... +def vm_script_execution_context_output_count(self: ScriptExecutionContext) -> int: ... +def vm_script_execution_context_tx_version(self: ScriptExecutionContext) -> int: ... +def vm_script_execution_context_tx_locktime(self: ScriptExecutionContext) -> int: ... + +# ─── Number (auto-generated, do not edit) ───────────────────────── + +class Number: + """Opaque handle to a `kth::infrastructure::machine::number`. Constructed by + `vm_number_construct_*` and released by + `vm_number_destruct`.""" + ... + +def vm_number_construct_default() -> Number: ... +def vm_number_copy(self: Number) -> Number: ... +def vm_number_destruct(self: Number) -> None: ... +def vm_number_from_int(value: int) -> "Number": ... +def vm_number_valid(self: Number, max_size: int) -> bool: ... +def vm_number_set_data(self: Number, data: bytes, max_size: int) -> bool: ... +def vm_number_data(self: Number) -> bytes: ... +def vm_number_int32(self: Number) -> int: ... +def vm_number_int64(self: Number) -> int: ... +def vm_number_is_true(self: Number) -> bool: ... +def vm_number_is_false(self: Number) -> bool: ... +def vm_number_greater(self: Number, value: int) -> bool: ... +def vm_number_less(self: Number, value: int) -> bool: ... +def vm_number_greater_or_equal(self: Number, value: int) -> bool: ... +def vm_number_less_or_equal(self: Number, value: int) -> bool: ... +def vm_number_equals(self: Number, other: Number) -> bool: ... +def vm_number_add_int64(self: Number, value: int) -> "Number" | None: ... +def vm_number_subtract_int64(self: Number, value: int) -> "Number" | None: ... +def vm_number_add_number(self: Number, x: "Number") -> "Number" | None: ... +def vm_number_subtract_number(self: Number, x: "Number") -> "Number" | None: ... +def vm_number_multiply(self: Number, x: "Number") -> "Number" | None: ... +def vm_number_safe_add_number(self: Number, x: "Number") -> bool: ... +def vm_number_safe_add_int64(self: Number, x: int) -> bool: ... +def vm_number_safe_sub_number(self: Number, x: "Number") -> bool: ... +def vm_number_safe_sub_int64(self: Number, x: int) -> bool: ... +def vm_number_safe_mul_number(self: Number, x: "Number") -> bool: ... +def vm_number_safe_mul_int64(self: Number, x: int) -> bool: ... +def vm_number_safe_add_number2(x: "Number", y: "Number") -> "Number": ... +def vm_number_safe_sub_number2(x: "Number", y: "Number") -> "Number": ... +def vm_number_safe_mul_number2(x: "Number", y: "Number") -> "Number": ... +def vm_number_is_minimally_encoded(data: bytes, max_integer_size: int) -> bool: ... +def vm_number_minimally_encode(data: bytes) -> bool: ... + +# ─── BigNumber (auto-generated, do not edit) ───────────────────────── + +class BigNumber: + """Opaque handle to a `kth::infrastructure::machine::big_number_gmp`. Constructed by + `vm_big_number_construct_*` and released by + `vm_big_number_destruct`.""" + ... + +def vm_big_number_construct_default() -> BigNumber: ... +def vm_big_number_construct_from_value(value: int) -> BigNumber: ... +def vm_big_number_construct_from_decimal_str(decimal_str: str) -> BigNumber: ... +def vm_big_number_copy(self: BigNumber) -> BigNumber: ... +def vm_big_number_destruct(self: BigNumber) -> None: ... +def vm_big_number_from_hex(hex_str: str) -> "BigNumber" | None: ... +def vm_big_number_serialize(self: BigNumber) -> bytes: ... +def vm_big_number_deserialize(self: BigNumber, data: bytes) -> bool: ... +def vm_big_number_to_string(self: BigNumber) -> str | None: ... +def vm_big_number_to_hex(self: BigNumber) -> str | None: ... +def vm_big_number_sign(self: BigNumber) -> int: ... +def vm_big_number_is_zero(self: BigNumber) -> bool: ... +def vm_big_number_is_nonzero(self: BigNumber) -> bool: ... +def vm_big_number_is_negative(self: BigNumber) -> bool: ... +def vm_big_number_to_int32_saturating(self: BigNumber) -> int: ... +def vm_big_number_byte_count(self: BigNumber) -> int: ... +def vm_big_number_compare(self: BigNumber, other: "BigNumber") -> int: ... +def vm_big_number_equals(self: BigNumber, other: BigNumber) -> bool: ... +def vm_big_number_add(self: BigNumber, other: "BigNumber") -> "BigNumber" | None: ... +def vm_big_number_subtract(self: BigNumber, other: "BigNumber") -> "BigNumber" | None: ... +def vm_big_number_multiply(self: BigNumber, other: "BigNumber") -> "BigNumber" | None: ... +def vm_big_number_abs(self: BigNumber) -> "BigNumber" | None: ... +def vm_big_number_negate(self: BigNumber) -> None: ... +def vm_big_number_pow(self: BigNumber, exp: "BigNumber") -> "BigNumber" | None: ... +def vm_big_number_pow_mod(self: BigNumber, exp: "BigNumber", mod: "BigNumber") -> "BigNumber" | None: ... +def vm_big_number_math_modulo(self: BigNumber, mod: "BigNumber") -> "BigNumber" | None: ... +def vm_big_number_data(self: BigNumber) -> bytes: ... +def vm_big_number_set_data(self: BigNumber, d: bytes, max_size: int) -> bool: ... +def vm_big_number_is_true(self: BigNumber) -> bool: ... +def vm_big_number_is_false(self: BigNumber) -> bool: ... +def vm_big_number_is_minimally_encoded(data: bytes, max_size: int) -> bool: ... + # ─── WalletData (auto-generated, do not edit) ───────────────────────── class WalletData: @@ -1627,5 +1822,257 @@ def wallet_wallet_data_xpub(self: WalletData) -> "HdPublic" | None: ... def wallet_wallet_data_set_xpub(self: WalletData, value: "HdPublic") -> None: ... def wallet_wallet_data_encrypted_seed(self: WalletData) -> bytes: ... def wallet_wallet_data_set_encrypted_seed(self: WalletData, value: bytes) -> None: ... -def wallet_wallet_data_create(password: str, normalized_passphrase: str) -> "WalletData": ... +def wallet_wallet_data_create(password: str, normalized_passphrase: str, lexicon: "Dictionary") -> "WalletData": ... +def wallet_wallet_data_create_simple(password: str, normalized_passphrase: str) -> "WalletData": ... + +# ─── Message (auto-generated, do not edit) ───────────────────────── + +class Message: + """Opaque handle to a `kth::domain::wallet`. Constructed by + `wallet_message_construct_*` and released by + `wallet_message_destruct`.""" + ... + +def wallet_message_hash_message(message: bytes) -> bytes: ... +def wallet_message_sign_message_ec_private(out_signature: bytes, message: bytes, secret: "EcPrivate") -> bool: ... +def wallet_message_sign_message_string(out_signature: bytes, message: bytes, wif: str) -> bool: ... +def wallet_message_sign_message_hash(out_signature: bytes, message: bytes, secret: bytes, compressed: bool) -> bool: ... +def wallet_message_verify_message(message: bytes, address: "PaymentAddress", signature: bytes) -> bool: ... +def wallet_message_recovery_id_to_magic(out_magic: int, recovery_id: int, compressed: bool) -> bool: ... +def wallet_message_magic_to_recovery_id(out_recovery_id: int, out_compressed: bool, magic: int) -> bool: ... + +# ─── StealthAddress (auto-generated, do not edit) ───────────────────────── + +class StealthAddress: + """Opaque handle to a `kth::domain::wallet::stealth_address`. Constructed by + `wallet_stealth_address_construct_*` and released by + `wallet_stealth_address_destruct`.""" + ... + +def wallet_stealth_address_construct_default() -> StealthAddress: ... +def wallet_stealth_address_construct_from_decoded(decoded: bytes) -> StealthAddress: ... +def wallet_stealth_address_construct_from_encoded(encoded: str) -> StealthAddress: ... +def wallet_stealth_address_construct_from_binary_scan_key_spend_keys_signatures_version(filter: "Binary", scan_key: bytes, spend_keys: object, signatures: int, version: int) -> StealthAddress: ... +def wallet_stealth_address_copy(self: StealthAddress) -> StealthAddress: ... +def wallet_stealth_address_destruct(self: StealthAddress) -> None: ... +def wallet_stealth_address_equals(self: StealthAddress, other: StealthAddress) -> bool: ... +def wallet_stealth_address_less(self: StealthAddress, x: "StealthAddress") -> bool: ... +def wallet_stealth_address_valid(self: StealthAddress) -> bool: ... +def wallet_stealth_address_encoded(self: StealthAddress) -> str | None: ... +def wallet_stealth_address_version(self: StealthAddress) -> int: ... +def wallet_stealth_address_scan_key(self: StealthAddress) -> bytes: ... +def wallet_stealth_address_spend_keys(self: StealthAddress) -> object | None: ... +def wallet_stealth_address_signatures(self: StealthAddress) -> int: ... +def wallet_stealth_address_filter(self: StealthAddress) -> "Binary" | None: ... +def wallet_stealth_address_to_chunk(self: StealthAddress) -> bytes: ... + +# ─── StealthReceiver (auto-generated, do not edit) ───────────────────────── + +class StealthReceiver: + """Opaque handle to a `kth::domain::wallet::stealth_receiver`. Constructed by + `wallet_stealth_receiver_construct_*` and released by + `wallet_stealth_receiver_destruct`.""" + ... + +def wallet_stealth_receiver_construct(scan_private: bytes, spend_private: bytes, filter: "Binary", version: int) -> StealthReceiver: ... +def wallet_stealth_receiver_copy(self: StealthReceiver) -> StealthReceiver: ... +def wallet_stealth_receiver_destruct(self: StealthReceiver) -> None: ... +def wallet_stealth_receiver_valid(self: StealthReceiver) -> bool: ... +def wallet_stealth_receiver_stealth_address(self: StealthReceiver) -> "StealthAddress" | None: ... +def wallet_stealth_receiver_derive_address(self: StealthReceiver, out_address: "PaymentAddress", ephemeral_public: bytes) -> bool: ... +def wallet_stealth_receiver_derive_private(self: StealthReceiver, out_private: bytes, ephemeral_public: bytes) -> bool: ... + +# ─── StealthSender (auto-generated, do not edit) ───────────────────────── + +class StealthSender: + """Opaque handle to a `kth::domain::wallet::stealth_sender`. Constructed by + `wallet_stealth_sender_construct_*` and released by + `wallet_stealth_sender_destruct`.""" + ... + +def wallet_stealth_sender_construct_from_stealth_address_seed_binary_version(address: "StealthAddress", seed: bytes, filter: "Binary", version: int) -> StealthSender: ... +def wallet_stealth_sender_construct_from_ephemeral_private_stealth_address_seed_binary_version(ephemeral_private: bytes, address: "StealthAddress", seed: bytes, filter: "Binary", version: int) -> StealthSender: ... +def wallet_stealth_sender_copy(self: StealthSender) -> StealthSender: ... +def wallet_stealth_sender_destruct(self: StealthSender) -> None: ... +def wallet_stealth_sender_valid(self: StealthSender) -> bool: ... +def wallet_stealth_sender_stealth_script(self: StealthSender) -> "Script" | None: ... +def wallet_stealth_sender_payment_address(self: StealthSender) -> "PaymentAddress" | None: ... + +# ─── Cashaddr (auto-generated, do not edit) ───────────────────────── + +class Cashaddr: + """Opaque handle to a `kth::domain::wallet::cashaddr`. Constructed by + `wallet_cashaddr_construct_*` and released by + `wallet_cashaddr_destruct`.""" + ... + +def wallet_cashaddr_encode(prefix: str, payload: bytes) -> str | None: ... +def wallet_cashaddr_decode(str: str, default_prefix: str) -> tuple[str, bytes] | None: ... + +# ─── BitcoinUri (auto-generated, do not edit) ───────────────────────── + +class BitcoinUri: + """Opaque handle to a `kth::domain::wallet::bitcoin_uri`. Constructed by + `wallet_bitcoin_uri_construct_*` and released by + `wallet_bitcoin_uri_destruct`.""" + ... + +def wallet_bitcoin_uri_construct_default() -> BitcoinUri: ... +def wallet_bitcoin_uri_construct(uri: str, strict: bool) -> BitcoinUri: ... +def wallet_bitcoin_uri_copy(self: BitcoinUri) -> BitcoinUri: ... +def wallet_bitcoin_uri_destruct(self: BitcoinUri) -> None: ... +def wallet_bitcoin_uri_equals(self: BitcoinUri, other: BitcoinUri) -> bool: ... +def wallet_bitcoin_uri_less(self: BitcoinUri, x: "BitcoinUri") -> bool: ... +def wallet_bitcoin_uri_valid(self: BitcoinUri) -> bool: ... +def wallet_bitcoin_uri_encoded(self: BitcoinUri) -> str | None: ... +def wallet_bitcoin_uri_amount(self: BitcoinUri) -> int: ... +def wallet_bitcoin_uri_label(self: BitcoinUri) -> str | None: ... +def wallet_bitcoin_uri_message(self: BitcoinUri) -> str | None: ... +def wallet_bitcoin_uri_r(self: BitcoinUri) -> str | None: ... +def wallet_bitcoin_uri_address(self: BitcoinUri) -> str | None: ... +def wallet_bitcoin_uri_payment(self: BitcoinUri) -> "PaymentAddress" | None: ... +def wallet_bitcoin_uri_stealth(self: BitcoinUri) -> "StealthAddress" | None: ... +def wallet_bitcoin_uri_parameter(self: BitcoinUri, key: str) -> str | None: ... +def wallet_bitcoin_uri_set_amount(self: BitcoinUri, satoshis: int) -> None: ... +def wallet_bitcoin_uri_set_label(self: BitcoinUri, label: str) -> None: ... +def wallet_bitcoin_uri_set_message(self: BitcoinUri, message: str) -> None: ... +def wallet_bitcoin_uri_set_r(self: BitcoinUri, r: str) -> None: ... +def wallet_bitcoin_uri_set_address_string(self: BitcoinUri, address: str) -> bool: ... +def wallet_bitcoin_uri_set_address_payment_address(self: BitcoinUri, payment: "PaymentAddress") -> None: ... +def wallet_bitcoin_uri_set_address_stealth_address(self: BitcoinUri, stealth: "StealthAddress") -> None: ... +def wallet_bitcoin_uri_set_strict(self: BitcoinUri, strict: bool) -> None: ... +def wallet_bitcoin_uri_set_scheme(self: BitcoinUri, scheme: str) -> bool: ... +def wallet_bitcoin_uri_set_authority(self: BitcoinUri, authority: str) -> bool: ... +def wallet_bitcoin_uri_set_path(self: BitcoinUri, path: str) -> bool: ... +def wallet_bitcoin_uri_set_fragment(self: BitcoinUri, fragment: str) -> bool: ... +def wallet_bitcoin_uri_set_parameter(self: BitcoinUri, key: str, value: str) -> bool: ... + +# ─── Language (auto-generated, do not edit) ───────────────────────── + +class Language: + """Opaque handle to a `kth::domain::wallet::languages`. Constructed by + `wallet_language_construct_*` and released by + `wallet_language_destruct`.""" + ... + +def wallet_language_en() -> "Dictionary" | None: ... +def wallet_language_es() -> "Dictionary" | None: ... +def wallet_language_ja() -> "Dictionary" | None: ... +def wallet_language_it() -> "Dictionary" | None: ... +def wallet_language_fr() -> "Dictionary" | None: ... +def wallet_language_cs() -> "Dictionary" | None: ... +def wallet_language_ru() -> "Dictionary" | None: ... +def wallet_language_uk() -> "Dictionary" | None: ... +def wallet_language_zh_Hans() -> "Dictionary" | None: ... +def wallet_language_zh_Hant() -> "Dictionary" | None: ... +def wallet_language_all() -> object | None: ... + +# ─── Mnemonic (auto-generated, do not edit) ───────────────────────── + +class Mnemonic: + """Opaque handle to a `kth::domain::wallet`. Constructed by + `wallet_mnemonic_construct_*` and released by + `wallet_mnemonic_destruct`.""" + ... + +def wallet_mnemonic_create_mnemonic(entropy: bytes, lexicon: "Dictionary") -> object | None: ... +def wallet_mnemonic_validate_mnemonic_dictionary(words: object, lexicon: "Dictionary") -> bool: ... +def wallet_mnemonic_validate_mnemonic_dictionary_list(mnemonic: object, lexicons: "DictionaryList") -> bool: ... + +# ─── EkPrivate (auto-generated, do not edit) ───────────────────────── + +class EkPrivate: + """Opaque handle to a `kth::domain::wallet::ek_private`. Constructed by + `wallet_ek_private_construct_*` and released by + `wallet_ek_private_destruct`.""" + ... + +def wallet_ek_private_construct_default() -> EkPrivate: ... +def wallet_ek_private_construct_from_encoded(encoded: str) -> EkPrivate: ... +def wallet_ek_private_construct_from_value(value: bytes) -> EkPrivate: ... +def wallet_ek_private_copy(self: EkPrivate) -> EkPrivate: ... +def wallet_ek_private_destruct(self: EkPrivate) -> None: ... +def wallet_ek_private_equals(self: EkPrivate, other: EkPrivate) -> bool: ... +def wallet_ek_private_less(self: EkPrivate, x: "EkPrivate") -> bool: ... +def wallet_ek_private_valid(self: EkPrivate) -> bool: ... +def wallet_ek_private_encoded(self: EkPrivate) -> str | None: ... +def wallet_ek_private_private_key(self: EkPrivate) -> bytes: ... + +# ─── EkPublic (auto-generated, do not edit) ───────────────────────── + +class EkPublic: + """Opaque handle to a `kth::domain::wallet::ek_public`. Constructed by + `wallet_ek_public_construct_*` and released by + `wallet_ek_public_destruct`.""" + ... + +def wallet_ek_public_construct_default() -> EkPublic: ... +def wallet_ek_public_construct_from_encoded(encoded: str) -> EkPublic: ... +def wallet_ek_public_construct_from_value(value: bytes) -> EkPublic: ... +def wallet_ek_public_copy(self: EkPublic) -> EkPublic: ... +def wallet_ek_public_destruct(self: EkPublic) -> None: ... +def wallet_ek_public_equals(self: EkPublic, other: EkPublic) -> bool: ... +def wallet_ek_public_less(self: EkPublic, x: "EkPublic") -> bool: ... +def wallet_ek_public_valid(self: EkPublic) -> bool: ... +def wallet_ek_public_encoded(self: EkPublic) -> str | None: ... +def wallet_ek_public_public_key(self: EkPublic) -> bytes: ... + +# ─── EkToken (auto-generated, do not edit) ───────────────────────── + +class EkToken: + """Opaque handle to a `kth::domain::wallet::ek_token`. Constructed by + `wallet_ek_token_construct_*` and released by + `wallet_ek_token_destruct`.""" + ... + +def wallet_ek_token_construct_default() -> EkToken: ... +def wallet_ek_token_construct_from_encoded(encoded: str) -> EkToken: ... +def wallet_ek_token_construct_from_value(value: bytes) -> EkToken: ... +def wallet_ek_token_copy(self: EkToken) -> EkToken: ... +def wallet_ek_token_destruct(self: EkToken) -> None: ... +def wallet_ek_token_equals(self: EkToken, other: EkToken) -> bool: ... +def wallet_ek_token_less(self: EkToken, x: "EkToken") -> bool: ... +def wallet_ek_token_valid(self: EkToken) -> bool: ... +def wallet_ek_token_encoded(self: EkToken) -> str | None: ... +def wallet_ek_token_token(self: EkToken) -> bytes: ... + +# ─── CoinSelectionResult (auto-generated, do not edit) ───────────────────────── + +class CoinSelectionResult: + """Opaque handle to a `kth::domain::wallet::coin_selection_result`. Constructed by + `wallet_coin_selection_result_construct_*` and released by + `wallet_coin_selection_result_destruct`.""" + ... + +def wallet_coin_selection_result_copy(self: CoinSelectionResult) -> CoinSelectionResult: ... +def wallet_coin_selection_result_destruct(self: CoinSelectionResult) -> None: ... +def wallet_coin_selection_result_total_selected_bch(self: CoinSelectionResult) -> int: ... +def wallet_coin_selection_result_total_selected_token(self: CoinSelectionResult) -> int: ... +def wallet_coin_selection_result_estimated_size(self: CoinSelectionResult) -> int: ... + +# ─── CoinSelection (auto-generated, do not edit) ───────────────────────── + +class CoinSelection: + """Opaque handle to a `kth::domain::wallet`. Constructed by + `wallet_coin_selection_construct_*` and released by + `wallet_coin_selection_destruct`.""" + ... + +def wallet_coin_selection_select_utxos(available_utxos: object, amount: int, outputs_size: int, category: bytes, strategy: int) -> "CoinSelectionResult": ... +def wallet_coin_selection_select_utxos_send_all(available_utxos: object, outputs_size: int, category: bytes) -> "CoinSelectionResult": ... +def wallet_coin_selection_select_utxos_both(available_utxos: object, bch_amount: int, token_category: bytes, token_amount: int, outputs_size: int, strategy: int) -> "CoinSelectionResult": ... +def wallet_coin_selection_create_token_split_tx_template(outpoints_to_split: object, available_utxos: object, destination_address: "PaymentAddress") -> tuple["Transaction", object, object]: ... +def wallet_coin_selection_create_tx_template(available_utxos: object, amount_to_send: int, destination_address: "PaymentAddress", change_addresses: object, change_ratios: object, selection_algo: int) -> tuple["Transaction", object, object, object]: ... +def wallet_coin_selection_create_tx_template_default_ratios(available_utxos: object, amount_to_send: int, destination_address: "PaymentAddress", change_addresses: object, selection_algo: int) -> tuple["Transaction", object, object, object]: ... +def wallet_coin_selection_make_change_ratios(change_count: int) -> object | None: ... + +# ─── EncryptedKeys (auto-generated, do not edit) ───────────────────────── + +class EncryptedKeys: + """Opaque handle to a `kth::domain::wallet`. Constructed by + `wallet_encrypted_keys_construct_*` and released by + `wallet_encrypted_keys_destruct`.""" + ... + +def wallet_encrypted_keys_create_key_pair(out_private: bytes, out_point: bytes, token: bytes, seed: bytes, version: int, compressed: bool) -> bool: ... # ── AUTO-GENERATED STUBS END ──────────────────────────────────────── diff --git a/setup.py b/setup.py index 6346bfd..df99b02 100644 --- a/setup.py +++ b/setup.py @@ -214,6 +214,10 @@ def run(self): 'src/chain/token_data.cpp', 'src/chain/utxo.cpp', 'src/chain/utxo_list.cpp', + 'src/chain/input_point.cpp', + 'src/chain/abla.cpp', + 'src/chain/abla_config.cpp', + 'src/chain/abla_state.cpp', # Auto-generated (v2 generator) — wallet classes. 'src/wallet/payment_address.cpp', 'src/wallet/payment_address_list.cpp', @@ -222,12 +226,29 @@ def run(self): 'src/wallet/hd_private.cpp', 'src/wallet/hd_public.cpp', 'src/wallet/wallet_data.cpp', + 'src/wallet/bitcoin_uri.cpp', + 'src/wallet/cashaddr.cpp', + 'src/wallet/coin_selection.cpp', + 'src/wallet/coin_selection_result.cpp', + 'src/wallet/ek_private.cpp', + 'src/wallet/ek_public.cpp', + 'src/wallet/ek_token.cpp', + 'src/wallet/encrypted_keys.cpp', + 'src/wallet/language.cpp', + 'src/wallet/message.cpp', + 'src/wallet/mnemonic.cpp', + 'src/wallet/stealth_address.cpp', + 'src/wallet/stealth_receiver.cpp', + 'src/wallet/stealth_sender.cpp', # Auto-generated (v2 generator) — VM classes. 'src/vm/program.cpp', 'src/vm/interpreter.cpp', 'src/vm/debug_snapshot.cpp', 'src/vm/debug_snapshot_list.cpp', 'src/vm/metrics.cpp', + 'src/vm/big_number.cpp', + 'src/vm/number.cpp', + 'src/vm/script_execution_context.cpp', # Hand-written async-callback bridge to safe_chain; not # generator-driven because the shape doesn't fit ClassConfig. 'src/chain/chain.cpp', diff --git a/src/chain/abla.cpp b/src/chain/abla.cpp new file mode 100644 index 0000000..7be25a0 --- /dev/null +++ b/src/chain/abla.cpp @@ -0,0 +1,92 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_chain_abla_set_max(PyObject* self, PyObject* py_arg0) { + PyObject* py_cfg = py_arg0; + kth_abla_config_mut_t cfg_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_cfg, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (cfg_handle == NULL) return NULL; + kth_chain_abla_set_max(cfg_handle); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_default_config(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"default_block_size", (char*)"fixed_size", NULL}; + unsigned long long default_block_size = 0; + int fixed_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Kp", kwlist, &default_block_size, &fixed_size)) { + return NULL; + } + auto const result = kth_chain_abla_default_config((uint64_t)default_block_size, (kth_bool_t)fixed_size); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG, kth_py_native_chain_abla_config_capsule_dtor); + if (capsule == NULL) { + kth_chain_abla_config_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_abla_validate_config(PyObject* self, PyObject* py_arg0) { + PyObject* py_cfg = py_arg0; + kth_abla_config_const_t cfg_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_cfg, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (cfg_handle == NULL) return NULL; + auto const result = kth_chain_abla_validate_config(cfg_handle); + return PyLong_FromLong((long)result); +} + +PyObject* +kth_py_native_chain_abla_block_size_limit(PyObject* self, PyObject* py_arg0) { + PyObject* py_st = py_arg0; + kth_abla_state_const_t st_handle = (kth_abla_state_const_t)PyCapsule_GetPointer(py_st, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (st_handle == NULL) return NULL; + auto const result = kth_chain_abla_block_size_limit(st_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_validate_state(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"st", (char*)"cfg", NULL}; + PyObject* py_st = NULL; + PyObject* py_cfg = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_st, &py_cfg)) { + return NULL; + } + kth_abla_state_const_t st_handle = (kth_abla_state_const_t)PyCapsule_GetPointer(py_st, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (st_handle == NULL) return NULL; + kth_abla_config_const_t cfg_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_cfg, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (cfg_handle == NULL) return NULL; + auto const result = kth_chain_abla_validate_state(st_handle, cfg_handle); + return PyLong_FromLong((long)result); +} + +PyMethodDef kth_py_native_chain_abla_methods[] = { + {"chain_abla_set_max", (PyCFunction)kth_py_native_chain_abla_set_max, METH_O, NULL}, + {"chain_abla_default_config", (PyCFunction)kth_py_native_chain_abla_default_config, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_validate_config", (PyCFunction)kth_py_native_chain_abla_validate_config, METH_O, NULL}, + {"chain_abla_block_size_limit", (PyCFunction)kth_py_native_chain_abla_block_size_limit, METH_O, NULL}, + {"chain_abla_validate_state", (PyCFunction)kth_py_native_chain_abla_validate_state, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/chain/abla_config.cpp b/src/chain/abla_config.cpp new file mode 100644 index 0000000..b9932a2 --- /dev/null +++ b/src/chain/abla_config.cpp @@ -0,0 +1,288 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_chain_abla_config_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG)) return; + kth_abla_config_mut_t handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (handle != NULL) kth_chain_abla_config_destruct(handle); +} + +PyObject* +kth_py_native_chain_abla_config_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG, kth_py_native_chain_abla_config_capsule_dtor); + if (capsule == NULL) { + kth_chain_abla_config_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_abla_config_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_epsilon0(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_epsilon0(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_epsilon0(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_epsilon0(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_beta0(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_beta0(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_beta0(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_beta0(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_n0(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_n0(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_n0(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_n0(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_gamma_reciprocal(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_gamma_reciprocal(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_gamma_reciprocal(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_gamma_reciprocal(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_zeta_xB7(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_zeta_xB7(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_zeta_xB7(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_zeta_xB7(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_theta_reciprocal(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_theta_reciprocal(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_theta_reciprocal(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_theta_reciprocal(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_delta(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_delta(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_delta(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_delta(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_epsilon_max(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_epsilon_max(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_epsilon_max(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_epsilon_max(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_config_beta_max(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_config_const_t self_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_config_beta_max(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_config_set_beta_max(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_config_mut_t self_handle = (kth_abla_config_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (self_handle == NULL) return NULL; + kth_chain_abla_config_set_beta_max(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyMethodDef kth_py_native_chain_abla_config_methods[] = { + {"chain_abla_config_copy", (PyCFunction)kth_py_native_chain_abla_config_copy, METH_O, NULL}, + {"chain_abla_config_destruct", (PyCFunction)kth_py_native_chain_abla_config_destruct, METH_O, NULL}, + {"chain_abla_config_epsilon0", (PyCFunction)kth_py_native_chain_abla_config_epsilon0, METH_O, NULL}, + {"chain_abla_config_set_epsilon0", (PyCFunction)kth_py_native_chain_abla_config_set_epsilon0, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_beta0", (PyCFunction)kth_py_native_chain_abla_config_beta0, METH_O, NULL}, + {"chain_abla_config_set_beta0", (PyCFunction)kth_py_native_chain_abla_config_set_beta0, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_n0", (PyCFunction)kth_py_native_chain_abla_config_n0, METH_O, NULL}, + {"chain_abla_config_set_n0", (PyCFunction)kth_py_native_chain_abla_config_set_n0, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_gamma_reciprocal", (PyCFunction)kth_py_native_chain_abla_config_gamma_reciprocal, METH_O, NULL}, + {"chain_abla_config_set_gamma_reciprocal", (PyCFunction)kth_py_native_chain_abla_config_set_gamma_reciprocal, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_zeta_xB7", (PyCFunction)kth_py_native_chain_abla_config_zeta_xB7, METH_O, NULL}, + {"chain_abla_config_set_zeta_xB7", (PyCFunction)kth_py_native_chain_abla_config_set_zeta_xB7, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_theta_reciprocal", (PyCFunction)kth_py_native_chain_abla_config_theta_reciprocal, METH_O, NULL}, + {"chain_abla_config_set_theta_reciprocal", (PyCFunction)kth_py_native_chain_abla_config_set_theta_reciprocal, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_delta", (PyCFunction)kth_py_native_chain_abla_config_delta, METH_O, NULL}, + {"chain_abla_config_set_delta", (PyCFunction)kth_py_native_chain_abla_config_set_delta, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_epsilon_max", (PyCFunction)kth_py_native_chain_abla_config_epsilon_max, METH_O, NULL}, + {"chain_abla_config_set_epsilon_max", (PyCFunction)kth_py_native_chain_abla_config_set_epsilon_max, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_config_beta_max", (PyCFunction)kth_py_native_chain_abla_config_beta_max, METH_O, NULL}, + {"chain_abla_config_set_beta_max", (PyCFunction)kth_py_native_chain_abla_config_set_beta_max, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/chain/abla_state.cpp b/src/chain/abla_state.cpp new file mode 100644 index 0000000..e274190 --- /dev/null +++ b/src/chain/abla_state.cpp @@ -0,0 +1,178 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_chain_abla_state_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_CHAIN_ABLA_STATE)) return; + kth_abla_state_mut_t handle = (kth_abla_state_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (handle != NULL) kth_chain_abla_state_destruct(handle); +} + +PyObject* +kth_py_native_chain_abla_state_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_chain_abla_state_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_ABLA_STATE, kth_py_native_chain_abla_state_capsule_dtor); + if (capsule == NULL) { + kth_chain_abla_state_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_abla_state_construct(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"cfg", (char*)"block_size", NULL}; + PyObject* py_cfg = NULL; + unsigned long long block_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_cfg, &block_size)) { + return NULL; + } + kth_abla_config_const_t cfg_handle = (kth_abla_config_const_t)PyCapsule_GetPointer(py_cfg, KTH_PY_CAPSULE_CHAIN_ABLA_CONFIG); + if (cfg_handle == NULL) return NULL; + auto const result = kth_chain_abla_state_construct(cfg_handle, (uint64_t)block_size); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_ABLA_STATE, kth_py_native_chain_abla_state_capsule_dtor); + if (capsule == NULL) { + kth_chain_abla_state_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_abla_state_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_state_const_t self_handle = (kth_abla_state_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_state_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_ABLA_STATE, kth_py_native_chain_abla_state_capsule_dtor); + if (capsule == NULL) { + kth_chain_abla_state_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_abla_state_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_state_mut_t self_handle = (kth_abla_state_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + kth_chain_abla_state_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_state_block_size(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_state_const_t self_handle = (kth_abla_state_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_state_block_size(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_state_set_block_size(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_state_mut_t self_handle = (kth_abla_state_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + kth_chain_abla_state_set_block_size(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_state_control_block_size(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_state_const_t self_handle = (kth_abla_state_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_state_control_block_size(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_state_set_control_block_size(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_state_mut_t self_handle = (kth_abla_state_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + kth_chain_abla_state_set_control_block_size(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_abla_state_elastic_buffer_size(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_abla_state_const_t self_handle = (kth_abla_state_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_abla_state_elastic_buffer_size(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_abla_state_set_elastic_buffer_size(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &value)) { + return NULL; + } + kth_abla_state_mut_t self_handle = (kth_abla_state_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_ABLA_STATE); + if (self_handle == NULL) return NULL; + kth_chain_abla_state_set_elastic_buffer_size(self_handle, (uint64_t)value); + Py_RETURN_NONE; +} + +PyMethodDef kth_py_native_chain_abla_state_methods[] = { + {"chain_abla_state_construct_default", (PyCFunction)kth_py_native_chain_abla_state_construct_default, METH_NOARGS, NULL}, + {"chain_abla_state_construct", (PyCFunction)kth_py_native_chain_abla_state_construct, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_state_copy", (PyCFunction)kth_py_native_chain_abla_state_copy, METH_O, NULL}, + {"chain_abla_state_destruct", (PyCFunction)kth_py_native_chain_abla_state_destruct, METH_O, NULL}, + {"chain_abla_state_block_size", (PyCFunction)kth_py_native_chain_abla_state_block_size, METH_O, NULL}, + {"chain_abla_state_set_block_size", (PyCFunction)kth_py_native_chain_abla_state_set_block_size, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_state_control_block_size", (PyCFunction)kth_py_native_chain_abla_state_control_block_size, METH_O, NULL}, + {"chain_abla_state_set_control_block_size", (PyCFunction)kth_py_native_chain_abla_state_set_control_block_size, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_abla_state_elastic_buffer_size", (PyCFunction)kth_py_native_chain_abla_state_elastic_buffer_size, METH_O, NULL}, + {"chain_abla_state_set_elastic_buffer_size", (PyCFunction)kth_py_native_chain_abla_state_set_elastic_buffer_size, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/chain/input_point.cpp b/src/chain/input_point.cpp new file mode 100644 index 0000000..57f0570 --- /dev/null +++ b/src/chain/input_point.cpp @@ -0,0 +1,306 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_chain_input_point_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_CHAIN_INPUT_POINT)) return; + kth_input_point_mut_t handle = (kth_input_point_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (handle != NULL) kth_chain_input_point_destruct(handle); +} + +PyObject* +kth_py_native_chain_input_point_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_chain_input_point_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_INPUT_POINT, kth_py_native_chain_input_point_capsule_dtor); + if (capsule == NULL) { + kth_chain_input_point_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_input_point_construct_from_data(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"reader", (char*)"wire", NULL}; + char const* reader_buf = NULL; + Py_ssize_t reader_size = 0; + int wire = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#p", kwlist, &reader_buf, &reader_size, &wire)) { + return NULL; + } + kth_input_point_mut_t out = NULL; + kth_error_code_t result = kth_chain_input_point_construct_from_data((uint8_t const*)reader_buf, (kth_size_t)reader_size, (kth_bool_t)wire, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_CHAIN_INPUT_POINT, kth_py_native_chain_input_point_capsule_dtor); + if (capsule == NULL) { + kth_chain_input_point_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_input_point_construct(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"hash", (char*)"index", NULL}; + char const* hash_buf = NULL; + Py_ssize_t hash_size = 0; + unsigned int index = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#I", kwlist, &hash_buf, &hash_size, &index)) { + return NULL; + } + if (hash_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte hash, got %zd", (int)KTH_BITCOIN_HASH_SIZE, hash_size); + return NULL; + } + kth_hash_t hash; + memcpy(hash.hash, hash_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + auto const result = kth_chain_input_point_construct(&hash, (uint32_t)index); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_INPUT_POINT, kth_py_native_chain_input_point_capsule_dtor); + if (capsule == NULL) { + kth_chain_input_point_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_input_point_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_INPUT_POINT, kth_py_native_chain_input_point_capsule_dtor); + if (capsule == NULL) { + kth_chain_input_point_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_input_point_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_mut_t self_handle = (kth_input_point_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + kth_chain_input_point_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_input_point_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + kth_input_point_const_t other_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (other_handle == NULL) return NULL; + auto const result = kth_chain_input_point_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_chain_input_point_null(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_chain_input_point_null(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_POINT, kth_py_native_chain_point_capsule_dtor); + if (capsule == NULL) { + kth_chain_point_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_chain_input_point_is_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_is_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_chain_input_point_to_data(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"wire", NULL}; + PyObject* py_self = NULL; + int wire = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Op", kwlist, &py_self, &wire)) { + return NULL; + } + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + kth_size_t out_size = 0; + auto const result = kth_chain_input_point_to_data(self_handle, (kth_bool_t)wire, &out_size); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: serialization failed"); + return NULL; + } + PyObject* py_result = Py_BuildValue("y#", result, (Py_ssize_t)out_size); + kth_core_destruct_array(result); + return py_result; +} + +PyObject* +kth_py_native_chain_input_point_satoshi_fixed_size(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_chain_input_point_satoshi_fixed_size(); + return PyLong_FromSize_t((size_t)result); +} + +PyObject* +kth_py_native_chain_input_point_serialized_size(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"wire", NULL}; + PyObject* py_self = NULL; + int wire = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Op", kwlist, &py_self, &wire)) { + return NULL; + } + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_serialized_size(self_handle, (kth_bool_t)wire); + return PyLong_FromSize_t((size_t)result); +} + +PyObject* +kth_py_native_chain_input_point_hash(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_hash(self_handle); + return Py_BuildValue("y#", result.hash, (Py_ssize_t)KTH_BITCOIN_HASH_SIZE); +} + +PyObject* +kth_py_native_chain_input_point_set_hash(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + char const* value_buf = NULL; + Py_ssize_t value_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#", kwlist, &py_self, &value_buf, &value_size)) { + return NULL; + } + kth_input_point_mut_t self_handle = (kth_input_point_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + if (value_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte value, got %zd", (int)KTH_BITCOIN_HASH_SIZE, value_size); + return NULL; + } + kth_hash_t value; + memcpy(value.hash, value_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + kth_chain_input_point_set_hash(self_handle, &value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_input_point_index(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_index(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_input_point_set_index(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + unsigned int value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OI", kwlist, &py_self, &value)) { + return NULL; + } + kth_input_point_mut_t self_handle = (kth_input_point_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + kth_chain_input_point_set_index(self_handle, (uint32_t)value); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_chain_input_point_checksum(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_checksum(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_chain_input_point_is_null(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_const_t self_handle = (kth_input_point_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + auto const result = kth_chain_input_point_is_null(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_chain_input_point_reset(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_input_point_mut_t self_handle = (kth_input_point_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_CHAIN_INPUT_POINT); + if (self_handle == NULL) return NULL; + kth_chain_input_point_reset(self_handle); + Py_RETURN_NONE; +} + +PyMethodDef kth_py_native_chain_input_point_methods[] = { + {"chain_input_point_construct_default", (PyCFunction)kth_py_native_chain_input_point_construct_default, METH_NOARGS, NULL}, + {"chain_input_point_construct_from_data", (PyCFunction)kth_py_native_chain_input_point_construct_from_data, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_construct", (PyCFunction)kth_py_native_chain_input_point_construct, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_copy", (PyCFunction)kth_py_native_chain_input_point_copy, METH_O, NULL}, + {"chain_input_point_destruct", (PyCFunction)kth_py_native_chain_input_point_destruct, METH_O, NULL}, + {"chain_input_point_equals", (PyCFunction)kth_py_native_chain_input_point_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_null", (PyCFunction)kth_py_native_chain_input_point_null, METH_NOARGS, NULL}, + {"chain_input_point_is_valid", (PyCFunction)kth_py_native_chain_input_point_is_valid, METH_O, NULL}, + {"chain_input_point_to_data", (PyCFunction)kth_py_native_chain_input_point_to_data, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_satoshi_fixed_size", (PyCFunction)kth_py_native_chain_input_point_satoshi_fixed_size, METH_NOARGS, NULL}, + {"chain_input_point_serialized_size", (PyCFunction)kth_py_native_chain_input_point_serialized_size, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_hash", (PyCFunction)kth_py_native_chain_input_point_hash, METH_O, NULL}, + {"chain_input_point_set_hash", (PyCFunction)kth_py_native_chain_input_point_set_hash, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_index", (PyCFunction)kth_py_native_chain_input_point_index, METH_O, NULL}, + {"chain_input_point_set_index", (PyCFunction)kth_py_native_chain_input_point_set_index, METH_VARARGS | METH_KEYWORDS, NULL}, + {"chain_input_point_checksum", (PyCFunction)kth_py_native_chain_input_point_checksum, METH_O, NULL}, + {"chain_input_point_is_null", (PyCFunction)kth_py_native_chain_input_point_is_null, METH_O, NULL}, + {"chain_input_point_reset", (PyCFunction)kth_py_native_chain_input_point_reset, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/chain/output_point.cpp b/src/chain/output_point.cpp index c27bf4b..92186b0 100644 --- a/src/chain/output_point.cpp +++ b/src/chain/output_point.cpp @@ -136,6 +136,21 @@ kth_py_native_chain_output_point_destruct(PyObject* self, PyObject* py_arg0) { Py_RETURN_NONE; } +PyObject* +kth_py_native_chain_output_point_null(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_chain_output_point_null(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_OUTPUT_POINT, kth_py_native_chain_output_point_capsule_dtor); + if (capsule == NULL) { + kth_chain_output_point_destruct(result); + return NULL; + } + return capsule; +} + PyObject* kth_py_native_chain_output_point_equals(PyObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; @@ -307,6 +322,7 @@ PyMethodDef kth_py_native_chain_output_point_methods[] = { {"chain_output_point_construct_from_point", (PyCFunction)kth_py_native_chain_output_point_construct_from_point, METH_O, NULL}, {"chain_output_point_copy", (PyCFunction)kth_py_native_chain_output_point_copy, METH_O, NULL}, {"chain_output_point_destruct", (PyCFunction)kth_py_native_chain_output_point_destruct, METH_O, NULL}, + {"chain_output_point_null", (PyCFunction)kth_py_native_chain_output_point_null, METH_NOARGS, NULL}, {"chain_output_point_equals", (PyCFunction)kth_py_native_chain_output_point_equals, METH_VARARGS | METH_KEYWORDS, NULL}, {"chain_output_point_is_mature", (PyCFunction)kth_py_native_chain_output_point_is_mature, METH_VARARGS | METH_KEYWORDS, NULL}, {"chain_output_point_is_valid", (PyCFunction)kth_py_native_chain_output_point_is_valid, METH_O, NULL}, diff --git a/src/module.c b/src/module.c index cd6df6e..c814fbc 100644 --- a/src/module.c +++ b/src/module.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -58,12 +59,32 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // ── AUTO-GENERATED INCLUDES END ─────────────────────────────────────── // `word_list.h` is the only hand-written binding still here — every // other class header on this block has migrated into the @@ -899,6 +920,7 @@ PyInit_kth_native(void) { KTH_REGISTER_METHODS(kth_py_native_chain_header_methods); KTH_REGISTER_METHODS(kth_py_native_chain_point_methods); KTH_REGISTER_METHODS(kth_py_native_chain_point_list_methods); + KTH_REGISTER_METHODS(kth_py_native_chain_input_point_methods); KTH_REGISTER_METHODS(kth_py_native_chain_output_point_methods); KTH_REGISTER_METHODS(kth_py_native_chain_output_point_list_methods); KTH_REGISTER_METHODS(kth_py_native_chain_script_methods); @@ -932,12 +954,32 @@ PyInit_kth_native(void) { KTH_REGISTER_METHODS(kth_py_native_chain_token_data_methods); KTH_REGISTER_METHODS(kth_py_native_chain_utxo_methods); KTH_REGISTER_METHODS(kth_py_native_chain_utxo_list_methods); + KTH_REGISTER_METHODS(kth_py_native_chain_abla_config_methods); + KTH_REGISTER_METHODS(kth_py_native_chain_abla_state_methods); + KTH_REGISTER_METHODS(kth_py_native_chain_abla_methods); KTH_REGISTER_METHODS(kth_py_native_vm_program_methods); KTH_REGISTER_METHODS(kth_py_native_vm_debug_snapshot_methods); KTH_REGISTER_METHODS(kth_py_native_vm_debug_snapshot_list_methods); KTH_REGISTER_METHODS(kth_py_native_vm_interpreter_methods); KTH_REGISTER_METHODS(kth_py_native_vm_metrics_methods); + KTH_REGISTER_METHODS(kth_py_native_vm_script_execution_context_methods); + KTH_REGISTER_METHODS(kth_py_native_vm_number_methods); + KTH_REGISTER_METHODS(kth_py_native_vm_big_number_methods); KTH_REGISTER_METHODS(kth_py_native_wallet_wallet_data_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_message_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_stealth_address_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_stealth_receiver_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_stealth_sender_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_cashaddr_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_bitcoin_uri_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_language_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_mnemonic_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_ek_private_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_ek_public_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_ek_token_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_coin_selection_result_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_coin_selection_methods); + KTH_REGISTER_METHODS(kth_py_native_wallet_encrypted_keys_methods); #undef KTH_REGISTER_METHODS // ── AUTO-GENERATED REGISTER END ─────────────────────────────────── diff --git a/src/vm/big_number.cpp b/src/vm/big_number.cpp new file mode 100644 index 0000000..152c7dd --- /dev/null +++ b/src/vm/big_number.cpp @@ -0,0 +1,559 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_vm_big_number_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_VM_BIG_NUMBER)) return; + kth_big_number_mut_t handle = (kth_big_number_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (handle != NULL) kth_vm_big_number_destruct(handle); +} + +PyObject* +kth_py_native_vm_big_number_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_vm_big_number_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"value", NULL}; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "L", kwlist, &value)) { + return NULL; + } + auto const result = kth_vm_big_number_construct_from_value((int64_t)value); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_construct_from_decimal_str(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"decimal_str", NULL}; + char const* decimal_str = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &decimal_str)) { + return NULL; + } + auto const result = kth_vm_big_number_construct_from_decimal_str(decimal_str); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_mut_t self_handle = (kth_big_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_vm_big_number_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_vm_big_number_from_hex(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"hex_str", NULL}; + char const* hex_str = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &hex_str)) { + return NULL; + } + auto const result = kth_vm_big_number_from_hex(hex_str); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_serialize(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_size_t out_size = 0; + auto const result = kth_vm_big_number_serialize(self_handle, &out_size); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: serialization failed"); + return NULL; + } + PyObject* py_result = Py_BuildValue("y#", result, (Py_ssize_t)out_size); + kth_core_destruct_array(result); + return py_result; +} + +PyObject* +kth_py_native_vm_big_number_deserialize(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"data", NULL}; + PyObject* py_self = NULL; + char const* data_buf = NULL; + Py_ssize_t data_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#", kwlist, &py_self, &data_buf, &data_size)) { + return NULL; + } + kth_big_number_mut_t self_handle = (kth_big_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_deserialize(self_handle, (uint8_t const*)data_buf, (kth_size_t)data_size); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_to_string(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_to_string(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_vm_big_number_to_hex(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_to_hex(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_vm_big_number_sign(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_sign(self_handle); + return PyLong_FromLongLong((long long)result); +} + +PyObject* +kth_py_native_vm_big_number_is_zero(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_is_zero(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_is_nonzero(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_is_nonzero(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_is_negative(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_is_negative(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_to_int32_saturating(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_to_int32_saturating(self_handle); + return PyLong_FromLongLong((long long)result); +} + +PyObject* +kth_py_native_vm_big_number_byte_count(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_byte_count(self_handle); + return PyLong_FromSize_t((size_t)result); +} + +PyObject* +kth_py_native_vm_big_number_compare(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t other_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (other_handle == NULL) return NULL; + auto const result = kth_vm_big_number_compare(self_handle, other_handle); + return PyLong_FromLongLong((long long)result); +} + +PyObject* +kth_py_native_vm_big_number_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t other_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (other_handle == NULL) return NULL; + auto const result = kth_vm_big_number_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_add(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t other_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (other_handle == NULL) return NULL; + auto const result = kth_vm_big_number_add(self_handle, other_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_subtract(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t other_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (other_handle == NULL) return NULL; + auto const result = kth_vm_big_number_subtract(self_handle, other_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_multiply(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t other_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (other_handle == NULL) return NULL; + auto const result = kth_vm_big_number_multiply(self_handle, other_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_abs(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_abs(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_negate(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_mut_t self_handle = (kth_big_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_vm_big_number_negate(self_handle); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_vm_big_number_pow(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"exp", NULL}; + PyObject* py_self = NULL; + PyObject* py_exp = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_exp)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t exp_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_exp, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (exp_handle == NULL) return NULL; + auto const result = kth_vm_big_number_pow(self_handle, exp_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_pow_mod(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"exp", (char*)"mod", NULL}; + PyObject* py_self = NULL; + PyObject* py_exp = NULL; + PyObject* py_mod = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OOO", kwlist, &py_self, &py_exp, &py_mod)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t exp_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_exp, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (exp_handle == NULL) return NULL; + kth_big_number_const_t mod_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_mod, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (mod_handle == NULL) return NULL; + auto const result = kth_vm_big_number_pow_mod(self_handle, exp_handle, mod_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_math_modulo(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"mod", NULL}; + PyObject* py_self = NULL; + PyObject* py_mod = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_mod)) { + return NULL; + } + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_big_number_const_t mod_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_mod, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (mod_handle == NULL) return NULL; + auto const result = kth_vm_big_number_math_modulo(self_handle, mod_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_big_number_data(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + kth_size_t out_size = 0; + auto const result = kth_vm_big_number_data(self_handle, &out_size); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: serialization failed"); + return NULL; + } + PyObject* py_result = Py_BuildValue("y#", result, (Py_ssize_t)out_size); + kth_core_destruct_array(result); + return py_result; +} + +PyObject* +kth_py_native_vm_big_number_set_data(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"d", (char*)"max_size", NULL}; + PyObject* py_self = NULL; + char const* d_buf = NULL; + Py_ssize_t d_size = 0; + Py_ssize_t max_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#n", kwlist, &py_self, &d_buf, &d_size, &max_size)) { + return NULL; + } + kth_big_number_mut_t self_handle = (kth_big_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + if (max_size < 0) { + PyErr_Format(PyExc_ValueError, "max_size must be non-negative, got %zd", max_size); + return NULL; + } + auto const result = kth_vm_big_number_set_data(self_handle, (uint8_t const*)d_buf, (kth_size_t)d_size, (kth_size_t)max_size); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_is_true(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_is_true(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_is_false(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_big_number_const_t self_handle = (kth_big_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_BIG_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_big_number_is_false(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_big_number_is_minimally_encoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"data", (char*)"max_size", NULL}; + char const* data_buf = NULL; + Py_ssize_t data_size = 0; + Py_ssize_t max_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#n", kwlist, &data_buf, &data_size, &max_size)) { + return NULL; + } + if (max_size < 0) { + PyErr_Format(PyExc_ValueError, "max_size must be non-negative, got %zd", max_size); + return NULL; + } + auto const result = kth_vm_big_number_is_minimally_encoded((uint8_t const*)data_buf, (kth_size_t)data_size, (kth_size_t)max_size); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_vm_big_number_methods[] = { + {"vm_big_number_construct_default", (PyCFunction)kth_py_native_vm_big_number_construct_default, METH_NOARGS, NULL}, + {"vm_big_number_construct_from_value", (PyCFunction)kth_py_native_vm_big_number_construct_from_value, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_construct_from_decimal_str", (PyCFunction)kth_py_native_vm_big_number_construct_from_decimal_str, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_copy", (PyCFunction)kth_py_native_vm_big_number_copy, METH_O, NULL}, + {"vm_big_number_destruct", (PyCFunction)kth_py_native_vm_big_number_destruct, METH_O, NULL}, + {"vm_big_number_from_hex", (PyCFunction)kth_py_native_vm_big_number_from_hex, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_serialize", (PyCFunction)kth_py_native_vm_big_number_serialize, METH_O, NULL}, + {"vm_big_number_deserialize", (PyCFunction)kth_py_native_vm_big_number_deserialize, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_to_string", (PyCFunction)kth_py_native_vm_big_number_to_string, METH_O, NULL}, + {"vm_big_number_to_hex", (PyCFunction)kth_py_native_vm_big_number_to_hex, METH_O, NULL}, + {"vm_big_number_sign", (PyCFunction)kth_py_native_vm_big_number_sign, METH_O, NULL}, + {"vm_big_number_is_zero", (PyCFunction)kth_py_native_vm_big_number_is_zero, METH_O, NULL}, + {"vm_big_number_is_nonzero", (PyCFunction)kth_py_native_vm_big_number_is_nonzero, METH_O, NULL}, + {"vm_big_number_is_negative", (PyCFunction)kth_py_native_vm_big_number_is_negative, METH_O, NULL}, + {"vm_big_number_to_int32_saturating", (PyCFunction)kth_py_native_vm_big_number_to_int32_saturating, METH_O, NULL}, + {"vm_big_number_byte_count", (PyCFunction)kth_py_native_vm_big_number_byte_count, METH_O, NULL}, + {"vm_big_number_compare", (PyCFunction)kth_py_native_vm_big_number_compare, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_equals", (PyCFunction)kth_py_native_vm_big_number_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_add", (PyCFunction)kth_py_native_vm_big_number_add, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_subtract", (PyCFunction)kth_py_native_vm_big_number_subtract, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_multiply", (PyCFunction)kth_py_native_vm_big_number_multiply, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_abs", (PyCFunction)kth_py_native_vm_big_number_abs, METH_O, NULL}, + {"vm_big_number_negate", (PyCFunction)kth_py_native_vm_big_number_negate, METH_O, NULL}, + {"vm_big_number_pow", (PyCFunction)kth_py_native_vm_big_number_pow, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_pow_mod", (PyCFunction)kth_py_native_vm_big_number_pow_mod, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_math_modulo", (PyCFunction)kth_py_native_vm_big_number_math_modulo, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_data", (PyCFunction)kth_py_native_vm_big_number_data, METH_O, NULL}, + {"vm_big_number_set_data", (PyCFunction)kth_py_native_vm_big_number_set_data, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_big_number_is_true", (PyCFunction)kth_py_native_vm_big_number_is_true, METH_O, NULL}, + {"vm_big_number_is_false", (PyCFunction)kth_py_native_vm_big_number_is_false, METH_O, NULL}, + {"vm_big_number_is_minimally_encoded", (PyCFunction)kth_py_native_vm_big_number_is_minimally_encoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/vm/number.cpp b/src/vm/number.cpp new file mode 100644 index 0000000..6ad1e62 --- /dev/null +++ b/src/vm/number.cpp @@ -0,0 +1,609 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_vm_number_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_VM_NUMBER)) return; + kth_number_mut_t handle = (kth_number_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_VM_NUMBER); + if (handle != NULL) kth_vm_number_destruct(handle); +} + +PyObject* +kth_py_native_vm_number_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_vm_number_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_vm_number_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_vm_number_from_int(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"value", NULL}; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "L", kwlist, &value)) { + return NULL; + } + kth_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_number_from_int((int64_t)value, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_valid(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"max_size", NULL}; + PyObject* py_self = NULL; + Py_ssize_t max_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "On", kwlist, &py_self, &max_size)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + if (max_size < 0) { + PyErr_Format(PyExc_ValueError, "max_size must be non-negative, got %zd", max_size); + return NULL; + } + auto const result = kth_vm_number_valid(self_handle, (kth_size_t)max_size); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_set_data(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"data", (char*)"max_size", NULL}; + PyObject* py_self = NULL; + char const* data_buf = NULL; + Py_ssize_t data_size = 0; + Py_ssize_t max_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#n", kwlist, &py_self, &data_buf, &data_size, &max_size)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + if (max_size < 0) { + PyErr_Format(PyExc_ValueError, "max_size must be non-negative, got %zd", max_size); + return NULL; + } + auto const result = kth_vm_number_set_data(self_handle, (uint8_t const*)data_buf, (kth_size_t)data_size, (kth_size_t)max_size); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_data(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_size_t out_size = 0; + auto const result = kth_vm_number_data(self_handle, &out_size); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: serialization failed"); + return NULL; + } + PyObject* py_result = Py_BuildValue("y#", result, (Py_ssize_t)out_size); + kth_core_destruct_array(result); + return py_result; +} + +PyObject* +kth_py_native_vm_number_int32(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_int32(self_handle); + return PyLong_FromLongLong((long long)result); +} + +PyObject* +kth_py_native_vm_number_int64(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_int64(self_handle); + return PyLong_FromLongLong((long long)result); +} + +PyObject* +kth_py_native_vm_number_is_true(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_is_true(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_is_false(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_is_false(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_greater(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &value)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_greater(self_handle, (int64_t)value); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_less(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &value)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_less(self_handle, (int64_t)value); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_greater_or_equal(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &value)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_greater_or_equal(self_handle, (int64_t)value); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_less_or_equal(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &value)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_less_or_equal(self_handle, (int64_t)value); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t other_handle = (kth_number_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_VM_NUMBER); + if (other_handle == NULL) return NULL; + auto const result = kth_vm_number_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_add_int64(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &value)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_add_int64(self_handle, (int64_t)value); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_subtract_int64(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"value", NULL}; + PyObject* py_self = NULL; + long long value = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &value)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_subtract_int64(self_handle, (int64_t)value); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_add_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + auto const result = kth_vm_number_add_number(self_handle, x_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_subtract_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + auto const result = kth_vm_number_subtract_number(self_handle, x_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_multiply(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_number_const_t self_handle = (kth_number_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + auto const result = kth_vm_number_multiply(self_handle, x_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_safe_add_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + auto const result = kth_vm_number_safe_add_number(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_safe_add_int64(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + long long x = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &x)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_safe_add_int64(self_handle, (int64_t)x); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_safe_sub_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + auto const result = kth_vm_number_safe_sub_number(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_safe_sub_int64(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + long long x = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &x)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_safe_sub_int64(self_handle, (int64_t)x); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_safe_mul_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + auto const result = kth_vm_number_safe_mul_number(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_safe_mul_int64(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + long long x = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OL", kwlist, &py_self, &x)) { + return NULL; + } + kth_number_mut_t self_handle = (kth_number_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_NUMBER); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_number_safe_mul_int64(self_handle, (int64_t)x); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_safe_add_number2(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"x", (char*)"y", NULL}; + PyObject* py_x = NULL; + PyObject* py_y = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_x, &py_y)) { + return NULL; + } + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + kth_number_const_t y_handle = (kth_number_const_t)PyCapsule_GetPointer(py_y, KTH_PY_CAPSULE_VM_NUMBER); + if (y_handle == NULL) return NULL; + kth_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_number_safe_add_number2(x_handle, y_handle, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_safe_sub_number2(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"x", (char*)"y", NULL}; + PyObject* py_x = NULL; + PyObject* py_y = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_x, &py_y)) { + return NULL; + } + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + kth_number_const_t y_handle = (kth_number_const_t)PyCapsule_GetPointer(py_y, KTH_PY_CAPSULE_VM_NUMBER); + if (y_handle == NULL) return NULL; + kth_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_number_safe_sub_number2(x_handle, y_handle, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_safe_mul_number2(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"x", (char*)"y", NULL}; + PyObject* py_x = NULL; + PyObject* py_y = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_x, &py_y)) { + return NULL; + } + kth_number_const_t x_handle = (kth_number_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_VM_NUMBER); + if (x_handle == NULL) return NULL; + kth_number_const_t y_handle = (kth_number_const_t)PyCapsule_GetPointer(py_y, KTH_PY_CAPSULE_VM_NUMBER); + if (y_handle == NULL) return NULL; + kth_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_number_safe_mul_number2(x_handle, y_handle, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_number_is_minimally_encoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"data", (char*)"max_integer_size", NULL}; + char const* data_buf = NULL; + Py_ssize_t data_size = 0; + Py_ssize_t max_integer_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#n", kwlist, &data_buf, &data_size, &max_integer_size)) { + return NULL; + } + if (max_integer_size < 0) { + PyErr_Format(PyExc_ValueError, "max_integer_size must be non-negative, got %zd", max_integer_size); + return NULL; + } + auto const result = kth_vm_number_is_minimally_encoded((uint8_t const*)data_buf, (kth_size_t)data_size, (kth_size_t)max_integer_size); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_vm_number_minimally_encode(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"data", NULL}; + char const* data_buf = NULL; + Py_ssize_t data_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#", kwlist, &data_buf, &data_size)) { + return NULL; + } + auto const result = kth_vm_number_minimally_encode((uint8_t const*)data_buf, (kth_size_t)data_size); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_vm_number_methods[] = { + {"vm_number_construct_default", (PyCFunction)kth_py_native_vm_number_construct_default, METH_NOARGS, NULL}, + {"vm_number_copy", (PyCFunction)kth_py_native_vm_number_copy, METH_O, NULL}, + {"vm_number_destruct", (PyCFunction)kth_py_native_vm_number_destruct, METH_O, NULL}, + {"vm_number_from_int", (PyCFunction)kth_py_native_vm_number_from_int, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_valid", (PyCFunction)kth_py_native_vm_number_valid, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_set_data", (PyCFunction)kth_py_native_vm_number_set_data, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_data", (PyCFunction)kth_py_native_vm_number_data, METH_O, NULL}, + {"vm_number_int32", (PyCFunction)kth_py_native_vm_number_int32, METH_O, NULL}, + {"vm_number_int64", (PyCFunction)kth_py_native_vm_number_int64, METH_O, NULL}, + {"vm_number_is_true", (PyCFunction)kth_py_native_vm_number_is_true, METH_O, NULL}, + {"vm_number_is_false", (PyCFunction)kth_py_native_vm_number_is_false, METH_O, NULL}, + {"vm_number_greater", (PyCFunction)kth_py_native_vm_number_greater, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_less", (PyCFunction)kth_py_native_vm_number_less, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_greater_or_equal", (PyCFunction)kth_py_native_vm_number_greater_or_equal, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_less_or_equal", (PyCFunction)kth_py_native_vm_number_less_or_equal, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_equals", (PyCFunction)kth_py_native_vm_number_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_add_int64", (PyCFunction)kth_py_native_vm_number_add_int64, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_subtract_int64", (PyCFunction)kth_py_native_vm_number_subtract_int64, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_add_number", (PyCFunction)kth_py_native_vm_number_add_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_subtract_number", (PyCFunction)kth_py_native_vm_number_subtract_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_multiply", (PyCFunction)kth_py_native_vm_number_multiply, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_add_number", (PyCFunction)kth_py_native_vm_number_safe_add_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_add_int64", (PyCFunction)kth_py_native_vm_number_safe_add_int64, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_sub_number", (PyCFunction)kth_py_native_vm_number_safe_sub_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_sub_int64", (PyCFunction)kth_py_native_vm_number_safe_sub_int64, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_mul_number", (PyCFunction)kth_py_native_vm_number_safe_mul_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_mul_int64", (PyCFunction)kth_py_native_vm_number_safe_mul_int64, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_add_number2", (PyCFunction)kth_py_native_vm_number_safe_add_number2, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_sub_number2", (PyCFunction)kth_py_native_vm_number_safe_sub_number2, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_safe_mul_number2", (PyCFunction)kth_py_native_vm_number_safe_mul_number2, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_is_minimally_encoded", (PyCFunction)kth_py_native_vm_number_is_minimally_encoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_number_minimally_encode", (PyCFunction)kth_py_native_vm_number_minimally_encode, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/vm/program.cpp b/src/vm/program.cpp index d6c3099..1d7c2d8 100644 --- a/src/vm/program.cpp +++ b/src/vm/program.cpp @@ -484,12 +484,12 @@ kth_py_native_vm_program_drop(PyObject* self, PyObject* py_arg0) { } PyObject* -kth_py_native_vm_program_pop(PyObject* self, PyObject* py_arg0) { +kth_py_native_vm_program_pop_simple(PyObject* self, PyObject* py_arg0) { PyObject* py_self = py_arg0; kth_program_mut_t self_handle = (kth_program_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); if (self_handle == NULL) return NULL; kth_size_t out_size = 0; - auto const result = kth_vm_program_pop(self_handle, &out_size); + auto const result = kth_vm_program_pop_simple(self_handle, &out_size); if (result == NULL) { PyErr_SetString(PyExc_RuntimeError, "kth: serialization failed"); return NULL; @@ -499,6 +499,156 @@ kth_py_native_vm_program_pop(PyObject* self, PyObject* py_arg0) { return py_result; } +PyObject* +kth_py_native_vm_program_pop_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"maximum_size", NULL}; + PyObject* py_self = NULL; + Py_ssize_t maximum_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "On", kwlist, &py_self, &maximum_size)) { + return NULL; + } + kth_program_mut_t self_handle = (kth_program_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); + if (self_handle == NULL) return NULL; + if (maximum_size < 0) { + PyErr_Format(PyExc_ValueError, "maximum_size must be non-negative, got %zd", maximum_size); + return NULL; + } + kth_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_program_pop_number(self_handle, (kth_size_t)maximum_size, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_program_pop_ternary(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_program_mut_t self_handle = (kth_program_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); + if (self_handle == NULL) return NULL; + kth_number_mut_t out_0 = NULL; + kth_number_mut_t out_1 = NULL; + kth_number_mut_t out_2 = NULL; + kth_error_code_t result = kth_vm_program_pop_ternary(self_handle, &out_0, &out_1, &out_2); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule_0 = PyCapsule_New((void*)out_0, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + PyObject* capsule_1 = PyCapsule_New((void*)out_1, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + PyObject* capsule_2 = PyCapsule_New((void*)out_2, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule_0 == NULL) { + kth_vm_number_destruct(out_0); + kth_vm_number_destruct(out_1); + kth_vm_number_destruct(out_2); + return NULL; + } + if (capsule_1 == NULL) { + kth_vm_number_destruct(out_1); + Py_DECREF(capsule_0); + kth_vm_number_destruct(out_2); + return NULL; + } + if (capsule_2 == NULL) { + kth_vm_number_destruct(out_2); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + return NULL; + } + PyObject* py_result = Py_BuildValue("(OOO)", capsule_0, capsule_1, capsule_2); + if (py_result == NULL) { + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return NULL; + } + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return py_result; +} + +PyObject* +kth_py_native_vm_program_pop_big_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"maximum_size", NULL}; + PyObject* py_self = NULL; + Py_ssize_t maximum_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "On", kwlist, &py_self, &maximum_size)) { + return NULL; + } + kth_program_mut_t self_handle = (kth_program_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); + if (self_handle == NULL) return NULL; + if (maximum_size < 0) { + PyErr_Format(PyExc_ValueError, "maximum_size must be non-negative, got %zd", maximum_size); + return NULL; + } + kth_big_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_program_pop_big_number(self_handle, (kth_size_t)maximum_size, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_program_pop_big_ternary(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_program_mut_t self_handle = (kth_program_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); + if (self_handle == NULL) return NULL; + kth_big_number_mut_t out_0 = NULL; + kth_big_number_mut_t out_1 = NULL; + kth_big_number_mut_t out_2 = NULL; + kth_error_code_t result = kth_vm_program_pop_big_ternary(self_handle, &out_0, &out_1, &out_2); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule_0 = PyCapsule_New((void*)out_0, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + PyObject* capsule_1 = PyCapsule_New((void*)out_1, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + PyObject* capsule_2 = PyCapsule_New((void*)out_2, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule_0 == NULL) { + kth_vm_big_number_destruct(out_0); + kth_vm_big_number_destruct(out_1); + kth_vm_big_number_destruct(out_2); + return NULL; + } + if (capsule_1 == NULL) { + kth_vm_big_number_destruct(out_1); + Py_DECREF(capsule_0); + kth_vm_big_number_destruct(out_2); + return NULL; + } + if (capsule_2 == NULL) { + kth_vm_big_number_destruct(out_2); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + return NULL; + } + PyObject* py_result = Py_BuildValue("(OOO)", capsule_0, capsule_1, capsule_2); + if (py_result == NULL) { + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return NULL; + } + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return py_result; +} + PyObject* kth_py_native_vm_program_duplicate(PyObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {(char*)"self", (char*)"index", NULL}; @@ -661,6 +811,62 @@ kth_py_native_vm_program_top(PyObject* self, PyObject* py_arg0) { return py_result; } +PyObject* +kth_py_native_vm_program_top_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"maximum_size", NULL}; + PyObject* py_self = NULL; + Py_ssize_t maximum_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "On", kwlist, &py_self, &maximum_size)) { + return NULL; + } + kth_program_const_t self_handle = (kth_program_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); + if (self_handle == NULL) return NULL; + if (maximum_size < 0) { + PyErr_Format(PyExc_ValueError, "maximum_size must be non-negative, got %zd", maximum_size); + return NULL; + } + kth_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_program_top_number(self_handle, (kth_size_t)maximum_size, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_NUMBER, kth_py_native_vm_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_number_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_program_top_big_number(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"maximum_size", NULL}; + PyObject* py_self = NULL; + Py_ssize_t maximum_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "On", kwlist, &py_self, &maximum_size)) { + return NULL; + } + kth_program_const_t self_handle = (kth_program_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_PROGRAM); + if (self_handle == NULL) return NULL; + if (maximum_size < 0) { + PyErr_Format(PyExc_ValueError, "maximum_size must be non-negative, got %zd", maximum_size); + return NULL; + } + kth_big_number_mut_t out = NULL; + kth_error_code_t result = kth_vm_program_top_big_number(self_handle, (kth_size_t)maximum_size, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_VM_BIG_NUMBER, kth_py_native_vm_big_number_capsule_dtor); + if (capsule == NULL) { + kth_vm_big_number_destruct(out); + return NULL; + } + return capsule; +} + PyObject* kth_py_native_vm_program_subscript(PyObject* self, PyObject* py_arg0) { PyObject* py_self = py_arg0; @@ -819,7 +1025,11 @@ PyMethodDef kth_py_native_vm_program_methods[] = { {"vm_program_push_move", (PyCFunction)kth_py_native_vm_program_push_move, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_push_copy", (PyCFunction)kth_py_native_vm_program_push_copy, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_drop", (PyCFunction)kth_py_native_vm_program_drop, METH_O, NULL}, - {"vm_program_pop", (PyCFunction)kth_py_native_vm_program_pop, METH_O, NULL}, + {"vm_program_pop_simple", (PyCFunction)kth_py_native_vm_program_pop_simple, METH_O, NULL}, + {"vm_program_pop_number", (PyCFunction)kth_py_native_vm_program_pop_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_program_pop_ternary", (PyCFunction)kth_py_native_vm_program_pop_ternary, METH_O, NULL}, + {"vm_program_pop_big_number", (PyCFunction)kth_py_native_vm_program_pop_big_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_program_pop_big_ternary", (PyCFunction)kth_py_native_vm_program_pop_big_ternary, METH_O, NULL}, {"vm_program_duplicate", (PyCFunction)kth_py_native_vm_program_duplicate, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_swap", (PyCFunction)kth_py_native_vm_program_swap, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_empty", (PyCFunction)kth_py_native_vm_program_empty, METH_O, NULL}, @@ -830,6 +1040,8 @@ PyMethodDef kth_py_native_vm_program_methods[] = { {"vm_program_if_", (PyCFunction)kth_py_native_vm_program_if_, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_item", (PyCFunction)kth_py_native_vm_program_item, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_top", (PyCFunction)kth_py_native_vm_program_top, METH_O, NULL}, + {"vm_program_top_number", (PyCFunction)kth_py_native_vm_program_top_number, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_program_top_big_number", (PyCFunction)kth_py_native_vm_program_top_big_number, METH_VARARGS | METH_KEYWORDS, NULL}, {"vm_program_subscript", (PyCFunction)kth_py_native_vm_program_subscript, METH_O, NULL}, {"vm_program_size", (PyCFunction)kth_py_native_vm_program_size, METH_O, NULL}, {"vm_program_conditional_stack_size", (PyCFunction)kth_py_native_vm_program_conditional_stack_size, METH_O, NULL}, diff --git a/src/vm/script_execution_context.cpp b/src/vm/script_execution_context.cpp new file mode 100644 index 0000000..8e67370 --- /dev/null +++ b/src/vm/script_execution_context.cpp @@ -0,0 +1,159 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_vm_script_execution_context_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT)) return; + kth_script_execution_context_mut_t handle = (kth_script_execution_context_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (handle != NULL) kth_vm_script_execution_context_destruct(handle); +} + +PyObject* +kth_py_native_vm_script_execution_context_construct(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"input_index", (char*)"transaction", NULL}; + unsigned int input_index = 0; + PyObject* py_transaction = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "IO", kwlist, &input_index, &py_transaction)) { + return NULL; + } + kth_transaction_const_t transaction_handle = (kth_transaction_const_t)PyCapsule_GetPointer(py_transaction, KTH_PY_CAPSULE_CHAIN_TRANSACTION); + if (transaction_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_construct((uint32_t)input_index, transaction_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT, kth_py_native_vm_script_execution_context_capsule_dtor); + if (capsule == NULL) { + kth_vm_script_execution_context_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_script_execution_context_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT, kth_py_native_vm_script_execution_context_capsule_dtor); + if (capsule == NULL) { + kth_vm_script_execution_context_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_script_execution_context_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_mut_t self_handle = (kth_script_execution_context_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + kth_vm_script_execution_context_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_vm_script_execution_context_input_index(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_input_index(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_vm_script_execution_context_transaction(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_transaction(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_TRANSACTION, kth_py_native_borrowed_parent_dtor); + if (capsule == NULL) return NULL; + Py_INCREF(py_self); + if (PyCapsule_SetContext(capsule, py_self) != 0) { + Py_DECREF(py_self); + Py_DECREF(capsule); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_vm_script_execution_context_input_count(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_input_count(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_vm_script_execution_context_output_count(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_output_count(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_vm_script_execution_context_tx_version(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_tx_version(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_vm_script_execution_context_tx_locktime(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_script_execution_context_const_t self_handle = (kth_script_execution_context_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_VM_SCRIPT_EXECUTION_CONTEXT); + if (self_handle == NULL) return NULL; + auto const result = kth_vm_script_execution_context_tx_locktime(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyMethodDef kth_py_native_vm_script_execution_context_methods[] = { + {"vm_script_execution_context_construct", (PyCFunction)kth_py_native_vm_script_execution_context_construct, METH_VARARGS | METH_KEYWORDS, NULL}, + {"vm_script_execution_context_copy", (PyCFunction)kth_py_native_vm_script_execution_context_copy, METH_O, NULL}, + {"vm_script_execution_context_destruct", (PyCFunction)kth_py_native_vm_script_execution_context_destruct, METH_O, NULL}, + {"vm_script_execution_context_input_index", (PyCFunction)kth_py_native_vm_script_execution_context_input_index, METH_O, NULL}, + {"vm_script_execution_context_transaction", (PyCFunction)kth_py_native_vm_script_execution_context_transaction, METH_O, NULL}, + {"vm_script_execution_context_input_count", (PyCFunction)kth_py_native_vm_script_execution_context_input_count, METH_O, NULL}, + {"vm_script_execution_context_output_count", (PyCFunction)kth_py_native_vm_script_execution_context_output_count, METH_O, NULL}, + {"vm_script_execution_context_tx_version", (PyCFunction)kth_py_native_vm_script_execution_context_tx_version, METH_O, NULL}, + {"vm_script_execution_context_tx_locktime", (PyCFunction)kth_py_native_vm_script_execution_context_tx_locktime, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/bitcoin_uri.cpp b/src/wallet/bitcoin_uri.cpp new file mode 100644 index 0000000..4397d87 --- /dev/null +++ b/src/wallet/bitcoin_uri.cpp @@ -0,0 +1,476 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_bitcoin_uri_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_BITCOIN_URI)) return; + kth_bitcoin_uri_mut_t handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (handle != NULL) kth_wallet_bitcoin_uri_destruct(handle); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_bitcoin_uri_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_BITCOIN_URI, kth_py_native_wallet_bitcoin_uri_capsule_dtor); + if (capsule == NULL) { + kth_wallet_bitcoin_uri_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_construct(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"uri", (char*)"strict", NULL}; + char const* uri = NULL; + int strict = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "sp", kwlist, &uri, &strict)) { + return NULL; + } + auto const result = kth_wallet_bitcoin_uri_construct(uri, (kth_bool_t)strict); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_BITCOIN_URI, kth_py_native_wallet_bitcoin_uri_capsule_dtor); + if (capsule == NULL) { + kth_wallet_bitcoin_uri_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_BITCOIN_URI, kth_py_native_wallet_bitcoin_uri_capsule_dtor); + if (capsule == NULL) { + kth_wallet_bitcoin_uri_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_bitcoin_uri_const_t other_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (other_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_less(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_bitcoin_uri_const_t x_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (x_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_less(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_encoded(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_encoded(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_amount(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_amount(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_label(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_label(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_message(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_message(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_r(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_r(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_address(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_address(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_payment(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_payment(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS, kth_py_native_wallet_payment_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_payment_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_stealth(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_stealth(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_wallet_stealth_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_parameter(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"key", NULL}; + PyObject* py_self = NULL; + char const* key = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &key)) { + return NULL; + } + kth_bitcoin_uri_const_t self_handle = (kth_bitcoin_uri_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_parameter(self_handle, key); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_amount(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"satoshis", NULL}; + PyObject* py_self = NULL; + unsigned long long satoshis = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OK", kwlist, &py_self, &satoshis)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_amount(self_handle, (uint64_t)satoshis); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_label(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"label", NULL}; + PyObject* py_self = NULL; + char const* label = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &label)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_label(self_handle, label); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_message(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"message", NULL}; + PyObject* py_self = NULL; + char const* message = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &message)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_message(self_handle, message); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_r(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"r", NULL}; + PyObject* py_self = NULL; + char const* r = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &r)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_r(self_handle, r); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_address_string(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"address", NULL}; + PyObject* py_self = NULL; + char const* address = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &address)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_set_address_string(self_handle, address); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_address_payment_address(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"payment", NULL}; + PyObject* py_self = NULL; + PyObject* py_payment = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_payment)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_payment_address_const_t payment_handle = (kth_payment_address_const_t)PyCapsule_GetPointer(py_payment, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS); + if (payment_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_address_payment_address(self_handle, payment_handle); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_address_stealth_address(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"stealth", NULL}; + PyObject* py_self = NULL; + PyObject* py_stealth = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_stealth)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_stealth_address_const_t stealth_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_stealth, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (stealth_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_address_stealth_address(self_handle, stealth_handle); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_strict(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"strict", NULL}; + PyObject* py_self = NULL; + int strict = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Op", kwlist, &py_self, &strict)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + kth_wallet_bitcoin_uri_set_strict(self_handle, (kth_bool_t)strict); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_scheme(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"scheme", NULL}; + PyObject* py_self = NULL; + char const* scheme = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &scheme)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_set_scheme(self_handle, scheme); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_authority(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"authority", NULL}; + PyObject* py_self = NULL; + char const* authority = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &authority)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_set_authority(self_handle, authority); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_path(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"path", NULL}; + PyObject* py_self = NULL; + char const* path = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &path)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_set_path(self_handle, path); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_fragment(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"fragment", NULL}; + PyObject* py_self = NULL; + char const* fragment = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Os", kwlist, &py_self, &fragment)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_set_fragment(self_handle, fragment); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_bitcoin_uri_set_parameter(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"key", (char*)"value", NULL}; + PyObject* py_self = NULL; + char const* key = NULL; + char const* value = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oss", kwlist, &py_self, &key, &value)) { + return NULL; + } + kth_bitcoin_uri_mut_t self_handle = (kth_bitcoin_uri_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_BITCOIN_URI); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_bitcoin_uri_set_parameter(self_handle, key, value); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_wallet_bitcoin_uri_methods[] = { + {"wallet_bitcoin_uri_construct_default", (PyCFunction)kth_py_native_wallet_bitcoin_uri_construct_default, METH_NOARGS, NULL}, + {"wallet_bitcoin_uri_construct", (PyCFunction)kth_py_native_wallet_bitcoin_uri_construct, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_copy", (PyCFunction)kth_py_native_wallet_bitcoin_uri_copy, METH_O, NULL}, + {"wallet_bitcoin_uri_destruct", (PyCFunction)kth_py_native_wallet_bitcoin_uri_destruct, METH_O, NULL}, + {"wallet_bitcoin_uri_equals", (PyCFunction)kth_py_native_wallet_bitcoin_uri_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_less", (PyCFunction)kth_py_native_wallet_bitcoin_uri_less, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_valid", (PyCFunction)kth_py_native_wallet_bitcoin_uri_valid, METH_O, NULL}, + {"wallet_bitcoin_uri_encoded", (PyCFunction)kth_py_native_wallet_bitcoin_uri_encoded, METH_O, NULL}, + {"wallet_bitcoin_uri_amount", (PyCFunction)kth_py_native_wallet_bitcoin_uri_amount, METH_O, NULL}, + {"wallet_bitcoin_uri_label", (PyCFunction)kth_py_native_wallet_bitcoin_uri_label, METH_O, NULL}, + {"wallet_bitcoin_uri_message", (PyCFunction)kth_py_native_wallet_bitcoin_uri_message, METH_O, NULL}, + {"wallet_bitcoin_uri_r", (PyCFunction)kth_py_native_wallet_bitcoin_uri_r, METH_O, NULL}, + {"wallet_bitcoin_uri_address", (PyCFunction)kth_py_native_wallet_bitcoin_uri_address, METH_O, NULL}, + {"wallet_bitcoin_uri_payment", (PyCFunction)kth_py_native_wallet_bitcoin_uri_payment, METH_O, NULL}, + {"wallet_bitcoin_uri_stealth", (PyCFunction)kth_py_native_wallet_bitcoin_uri_stealth, METH_O, NULL}, + {"wallet_bitcoin_uri_parameter", (PyCFunction)kth_py_native_wallet_bitcoin_uri_parameter, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_amount", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_amount, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_label", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_label, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_message", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_message, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_r", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_r, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_address_string", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_address_string, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_address_payment_address", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_address_payment_address, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_address_stealth_address", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_address_stealth_address, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_strict", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_strict, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_scheme", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_scheme, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_authority", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_authority, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_path", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_path, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_fragment", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_fragment, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_bitcoin_uri_set_parameter", (PyCFunction)kth_py_native_wallet_bitcoin_uri_set_parameter, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/cashaddr.cpp b/src/wallet/cashaddr.cpp new file mode 100644 index 0000000..6c74f37 --- /dev/null +++ b/src/wallet/cashaddr.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_wallet_cashaddr_encode(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"prefix", (char*)"payload", NULL}; + char const* prefix = NULL; + char const* payload_buf = NULL; + Py_ssize_t payload_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "sy#", kwlist, &prefix, &payload_buf, &payload_size)) { + return NULL; + } + auto const result = kth_wallet_cashaddr_encode(prefix, (uint8_t const*)payload_buf, (kth_size_t)payload_size); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_cashaddr_decode(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"str", (char*)"default_prefix", NULL}; + char const* str = NULL; + char const* default_prefix = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, &str, &default_prefix)) { + return NULL; + } + uint8_t* out_payload = NULL; + kth_size_t out_payload_size = 0; + auto const result = kth_wallet_cashaddr_decode(str, default_prefix, &out_payload, &out_payload_size); + if (result == NULL) { + if (out_payload != NULL) kth_core_destruct_array(out_payload); + Py_RETURN_NONE; + } + PyObject* py_prefix = Py_BuildValue("s", result); + kth_core_destruct_string(result); + if (py_prefix == NULL) { + if (out_payload != NULL) kth_core_destruct_array(out_payload); + return NULL; + } + PyObject* py_payload = Py_BuildValue("y#", out_payload, (Py_ssize_t)out_payload_size); + kth_core_destruct_array(out_payload); + if (py_payload == NULL) { + Py_DECREF(py_prefix); + return NULL; + } + PyObject* py_result = Py_BuildValue("(OO)", py_prefix, py_payload); + Py_DECREF(py_prefix); + Py_DECREF(py_payload); + return py_result; +} + +PyMethodDef kth_py_native_wallet_cashaddr_methods[] = { + {"wallet_cashaddr_encode", (PyCFunction)kth_py_native_wallet_cashaddr_encode, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_cashaddr_decode", (PyCFunction)kth_py_native_wallet_cashaddr_decode, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/coin_selection.cpp b/src/wallet/coin_selection.cpp new file mode 100644 index 0000000..67f4f59 --- /dev/null +++ b/src/wallet/coin_selection.cpp @@ -0,0 +1,373 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_wallet_coin_selection_select_utxos(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"available_utxos", (char*)"amount", (char*)"outputs_size", (char*)"category", (char*)"strategy", NULL}; + PyObject* py_available_utxos = NULL; + unsigned long long amount = 0; + Py_ssize_t outputs_size = 0; + char const* category_buf = NULL; + Py_ssize_t category_size = 0; + unsigned long long strategy = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OKny#K", kwlist, &py_available_utxos, &amount, &outputs_size, &category_buf, &category_size, &strategy)) { + return NULL; + } + kth_utxo_list_const_t available_utxos_handle = (kth_utxo_list_const_t)PyCapsule_GetPointer(py_available_utxos, KTH_PY_CAPSULE_CHAIN_UTXO_LIST); + if (available_utxos_handle == NULL) return NULL; + if (outputs_size < 0) { + PyErr_Format(PyExc_ValueError, "outputs_size must be non-negative, got %zd", outputs_size); + return NULL; + } + if (category_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte category, got %zd", (int)KTH_BITCOIN_HASH_SIZE, category_size); + return NULL; + } + kth_hash_t category; + memcpy(category.hash, category_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + kth_coin_selection_result_mut_t out = NULL; + kth_error_code_t result = kth_wallet_coin_selection_select_utxos(available_utxos_handle, (uint64_t)amount, (kth_size_t)outputs_size, &category, (kth_coin_selection_strategy_t)strategy, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT, kth_py_native_wallet_coin_selection_result_capsule_dtor); + if (capsule == NULL) { + kth_wallet_coin_selection_result_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_coin_selection_select_utxos_send_all(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"available_utxos", (char*)"outputs_size", (char*)"category", NULL}; + PyObject* py_available_utxos = NULL; + Py_ssize_t outputs_size = 0; + char const* category_buf = NULL; + Py_ssize_t category_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Ony#", kwlist, &py_available_utxos, &outputs_size, &category_buf, &category_size)) { + return NULL; + } + kth_utxo_list_const_t available_utxos_handle = (kth_utxo_list_const_t)PyCapsule_GetPointer(py_available_utxos, KTH_PY_CAPSULE_CHAIN_UTXO_LIST); + if (available_utxos_handle == NULL) return NULL; + if (outputs_size < 0) { + PyErr_Format(PyExc_ValueError, "outputs_size must be non-negative, got %zd", outputs_size); + return NULL; + } + if (category_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte category, got %zd", (int)KTH_BITCOIN_HASH_SIZE, category_size); + return NULL; + } + kth_hash_t category; + memcpy(category.hash, category_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + kth_coin_selection_result_mut_t out = NULL; + kth_error_code_t result = kth_wallet_coin_selection_select_utxos_send_all(available_utxos_handle, (kth_size_t)outputs_size, &category, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT, kth_py_native_wallet_coin_selection_result_capsule_dtor); + if (capsule == NULL) { + kth_wallet_coin_selection_result_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_coin_selection_select_utxos_both(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"available_utxos", (char*)"bch_amount", (char*)"token_category", (char*)"token_amount", (char*)"outputs_size", (char*)"strategy", NULL}; + PyObject* py_available_utxos = NULL; + unsigned long long bch_amount = 0; + char const* token_category_buf = NULL; + Py_ssize_t token_category_size = 0; + unsigned long long token_amount = 0; + Py_ssize_t outputs_size = 0; + unsigned long long strategy = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OKy#KnK", kwlist, &py_available_utxos, &bch_amount, &token_category_buf, &token_category_size, &token_amount, &outputs_size, &strategy)) { + return NULL; + } + kth_utxo_list_const_t available_utxos_handle = (kth_utxo_list_const_t)PyCapsule_GetPointer(py_available_utxos, KTH_PY_CAPSULE_CHAIN_UTXO_LIST); + if (available_utxos_handle == NULL) return NULL; + if (token_category_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte token_category, got %zd", (int)KTH_BITCOIN_HASH_SIZE, token_category_size); + return NULL; + } + kth_hash_t token_category; + memcpy(token_category.hash, token_category_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + if (outputs_size < 0) { + PyErr_Format(PyExc_ValueError, "outputs_size must be non-negative, got %zd", outputs_size); + return NULL; + } + kth_coin_selection_result_mut_t out = NULL; + kth_error_code_t result = kth_wallet_coin_selection_select_utxos_both(available_utxos_handle, (uint64_t)bch_amount, &token_category, (uint64_t)token_amount, (kth_size_t)outputs_size, (kth_coin_selection_strategy_t)strategy, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT, kth_py_native_wallet_coin_selection_result_capsule_dtor); + if (capsule == NULL) { + kth_wallet_coin_selection_result_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_coin_selection_create_token_split_tx_template(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"outpoints_to_split", (char*)"available_utxos", (char*)"destination_address", NULL}; + PyObject* py_outpoints_to_split = NULL; + PyObject* py_available_utxos = NULL; + PyObject* py_destination_address = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OOO", kwlist, &py_outpoints_to_split, &py_available_utxos, &py_destination_address)) { + return NULL; + } + kth_output_point_list_const_t outpoints_to_split_handle = (kth_output_point_list_const_t)PyCapsule_GetPointer(py_outpoints_to_split, KTH_PY_CAPSULE_CHAIN_OUTPUT_POINT_LIST); + if (outpoints_to_split_handle == NULL) return NULL; + kth_utxo_list_const_t available_utxos_handle = (kth_utxo_list_const_t)PyCapsule_GetPointer(py_available_utxos, KTH_PY_CAPSULE_CHAIN_UTXO_LIST); + if (available_utxos_handle == NULL) return NULL; + kth_payment_address_const_t destination_address_handle = (kth_payment_address_const_t)PyCapsule_GetPointer(py_destination_address, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS); + if (destination_address_handle == NULL) return NULL; + kth_transaction_mut_t out_0 = NULL; + kth_payment_address_list_mut_t out_1 = NULL; + kth_u64_list_mut_t out_2 = NULL; + kth_error_code_t result = kth_wallet_coin_selection_create_token_split_tx_template(outpoints_to_split_handle, available_utxos_handle, destination_address_handle, &out_0, &out_1, &out_2); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule_0 = PyCapsule_New((void*)out_0, KTH_PY_CAPSULE_CHAIN_TRANSACTION, kth_py_native_chain_transaction_capsule_dtor); + PyObject* capsule_1 = PyCapsule_New((void*)out_1, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS_LIST, kth_py_native_wallet_payment_address_list_capsule_dtor); + PyObject* capsule_2 = PyCapsule_New((void*)out_2, KTH_PY_CAPSULE_CORE_U64_LIST, NULL); + if (capsule_0 == NULL) { + kth_chain_transaction_destruct(out_0); + kth_wallet_payment_address_list_destruct(out_1); + kth_core_u64_list_destruct(out_2); + return NULL; + } + if (capsule_1 == NULL) { + kth_wallet_payment_address_list_destruct(out_1); + Py_DECREF(capsule_0); + kth_core_u64_list_destruct(out_2); + return NULL; + } + if (capsule_2 == NULL) { + kth_core_u64_list_destruct(out_2); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + return NULL; + } + PyObject* py_result = Py_BuildValue("(OOO)", capsule_0, capsule_1, capsule_2); + if (py_result == NULL) { + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return NULL; + } + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return py_result; +} + +PyObject* +kth_py_native_wallet_coin_selection_create_tx_template(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"available_utxos", (char*)"amount_to_send", (char*)"destination_address", (char*)"change_addresses", (char*)"change_ratios", (char*)"selection_algo", NULL}; + PyObject* py_available_utxos = NULL; + unsigned long long amount_to_send = 0; + PyObject* py_destination_address = NULL; + PyObject* py_change_addresses = NULL; + PyObject* py_change_ratios = NULL; + unsigned long long selection_algo = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OKOOOK", kwlist, &py_available_utxos, &amount_to_send, &py_destination_address, &py_change_addresses, &py_change_ratios, &selection_algo)) { + return NULL; + } + kth_utxo_list_const_t available_utxos_handle = (kth_utxo_list_const_t)PyCapsule_GetPointer(py_available_utxos, KTH_PY_CAPSULE_CHAIN_UTXO_LIST); + if (available_utxos_handle == NULL) return NULL; + kth_payment_address_const_t destination_address_handle = (kth_payment_address_const_t)PyCapsule_GetPointer(py_destination_address, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS); + if (destination_address_handle == NULL) return NULL; + kth_payment_address_list_const_t change_addresses_handle = (kth_payment_address_list_const_t)PyCapsule_GetPointer(py_change_addresses, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS_LIST); + if (change_addresses_handle == NULL) return NULL; + kth_double_list_const_t change_ratios_handle = (kth_double_list_const_t)PyCapsule_GetPointer(py_change_ratios, KTH_PY_CAPSULE_CORE_DOUBLE_LIST); + if (change_ratios_handle == NULL) return NULL; + kth_transaction_mut_t out_0 = NULL; + kth_u32_list_mut_t out_1 = NULL; + kth_payment_address_list_mut_t out_2 = NULL; + kth_u64_list_mut_t out_3 = NULL; + kth_error_code_t result = kth_wallet_coin_selection_create_tx_template(available_utxos_handle, (uint64_t)amount_to_send, destination_address_handle, change_addresses_handle, change_ratios_handle, (kth_coin_selection_algorithm_t)selection_algo, &out_0, &out_1, &out_2, &out_3); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule_0 = PyCapsule_New((void*)out_0, KTH_PY_CAPSULE_CHAIN_TRANSACTION, kth_py_native_chain_transaction_capsule_dtor); + PyObject* capsule_1 = PyCapsule_New((void*)out_1, KTH_PY_CAPSULE_CORE_U32_LIST, NULL); + PyObject* capsule_2 = PyCapsule_New((void*)out_2, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS_LIST, kth_py_native_wallet_payment_address_list_capsule_dtor); + PyObject* capsule_3 = PyCapsule_New((void*)out_3, KTH_PY_CAPSULE_CORE_U64_LIST, NULL); + if (capsule_0 == NULL) { + kth_chain_transaction_destruct(out_0); + kth_core_u32_list_destruct(out_1); + kth_wallet_payment_address_list_destruct(out_2); + kth_core_u64_list_destruct(out_3); + return NULL; + } + if (capsule_1 == NULL) { + kth_core_u32_list_destruct(out_1); + Py_DECREF(capsule_0); + kth_wallet_payment_address_list_destruct(out_2); + kth_core_u64_list_destruct(out_3); + return NULL; + } + if (capsule_2 == NULL) { + kth_wallet_payment_address_list_destruct(out_2); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + kth_core_u64_list_destruct(out_3); + return NULL; + } + if (capsule_3 == NULL) { + kth_core_u64_list_destruct(out_3); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return NULL; + } + PyObject* py_result = Py_BuildValue("(OOOO)", capsule_0, capsule_1, capsule_2, capsule_3); + if (py_result == NULL) { + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + Py_DECREF(capsule_3); + return NULL; + } + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + Py_DECREF(capsule_3); + return py_result; +} + +PyObject* +kth_py_native_wallet_coin_selection_create_tx_template_default_ratios(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"available_utxos", (char*)"amount_to_send", (char*)"destination_address", (char*)"change_addresses", (char*)"selection_algo", NULL}; + PyObject* py_available_utxos = NULL; + unsigned long long amount_to_send = 0; + PyObject* py_destination_address = NULL; + PyObject* py_change_addresses = NULL; + unsigned long long selection_algo = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OKOOK", kwlist, &py_available_utxos, &amount_to_send, &py_destination_address, &py_change_addresses, &selection_algo)) { + return NULL; + } + kth_utxo_list_const_t available_utxos_handle = (kth_utxo_list_const_t)PyCapsule_GetPointer(py_available_utxos, KTH_PY_CAPSULE_CHAIN_UTXO_LIST); + if (available_utxos_handle == NULL) return NULL; + kth_payment_address_const_t destination_address_handle = (kth_payment_address_const_t)PyCapsule_GetPointer(py_destination_address, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS); + if (destination_address_handle == NULL) return NULL; + kth_payment_address_list_const_t change_addresses_handle = (kth_payment_address_list_const_t)PyCapsule_GetPointer(py_change_addresses, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS_LIST); + if (change_addresses_handle == NULL) return NULL; + kth_transaction_mut_t out_0 = NULL; + kth_u32_list_mut_t out_1 = NULL; + kth_payment_address_list_mut_t out_2 = NULL; + kth_u64_list_mut_t out_3 = NULL; + kth_error_code_t result = kth_wallet_coin_selection_create_tx_template_default_ratios(available_utxos_handle, (uint64_t)amount_to_send, destination_address_handle, change_addresses_handle, (kth_coin_selection_algorithm_t)selection_algo, &out_0, &out_1, &out_2, &out_3); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule_0 = PyCapsule_New((void*)out_0, KTH_PY_CAPSULE_CHAIN_TRANSACTION, kth_py_native_chain_transaction_capsule_dtor); + PyObject* capsule_1 = PyCapsule_New((void*)out_1, KTH_PY_CAPSULE_CORE_U32_LIST, NULL); + PyObject* capsule_2 = PyCapsule_New((void*)out_2, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS_LIST, kth_py_native_wallet_payment_address_list_capsule_dtor); + PyObject* capsule_3 = PyCapsule_New((void*)out_3, KTH_PY_CAPSULE_CORE_U64_LIST, NULL); + if (capsule_0 == NULL) { + kth_chain_transaction_destruct(out_0); + kth_core_u32_list_destruct(out_1); + kth_wallet_payment_address_list_destruct(out_2); + kth_core_u64_list_destruct(out_3); + return NULL; + } + if (capsule_1 == NULL) { + kth_core_u32_list_destruct(out_1); + Py_DECREF(capsule_0); + kth_wallet_payment_address_list_destruct(out_2); + kth_core_u64_list_destruct(out_3); + return NULL; + } + if (capsule_2 == NULL) { + kth_wallet_payment_address_list_destruct(out_2); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + kth_core_u64_list_destruct(out_3); + return NULL; + } + if (capsule_3 == NULL) { + kth_core_u64_list_destruct(out_3); + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + return NULL; + } + PyObject* py_result = Py_BuildValue("(OOOO)", capsule_0, capsule_1, capsule_2, capsule_3); + if (py_result == NULL) { + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + Py_DECREF(capsule_3); + return NULL; + } + Py_DECREF(capsule_0); + Py_DECREF(capsule_1); + Py_DECREF(capsule_2); + Py_DECREF(capsule_3); + return py_result; +} + +PyObject* +kth_py_native_wallet_coin_selection_make_change_ratios(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"change_count", NULL}; + Py_ssize_t change_count = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "n", kwlist, &change_count)) { + return NULL; + } + if (change_count < 0) { + PyErr_Format(PyExc_ValueError, "change_count must be non-negative, got %zd", change_count); + return NULL; + } + auto const result = kth_wallet_coin_selection_make_change_ratios((kth_size_t)change_count); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL list returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CORE_DOUBLE_LIST, NULL); + if (capsule == NULL) { + kth_core_double_list_destruct(result); + return NULL; + } + return capsule; +} + +PyMethodDef kth_py_native_wallet_coin_selection_methods[] = { + {"wallet_coin_selection_select_utxos", (PyCFunction)kth_py_native_wallet_coin_selection_select_utxos, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_coin_selection_select_utxos_send_all", (PyCFunction)kth_py_native_wallet_coin_selection_select_utxos_send_all, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_coin_selection_select_utxos_both", (PyCFunction)kth_py_native_wallet_coin_selection_select_utxos_both, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_coin_selection_create_token_split_tx_template", (PyCFunction)kth_py_native_wallet_coin_selection_create_token_split_tx_template, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_coin_selection_create_tx_template", (PyCFunction)kth_py_native_wallet_coin_selection_create_tx_template, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_coin_selection_create_tx_template_default_ratios", (PyCFunction)kth_py_native_wallet_coin_selection_create_tx_template_default_ratios, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_coin_selection_make_change_ratios", (PyCFunction)kth_py_native_wallet_coin_selection_make_change_ratios, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/coin_selection_result.cpp b/src/wallet/coin_selection_result.cpp new file mode 100644 index 0000000..beb98ad --- /dev/null +++ b/src/wallet/coin_selection_result.cpp @@ -0,0 +1,93 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_coin_selection_result_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT)) return; + kth_coin_selection_result_mut_t handle = (kth_coin_selection_result_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT); + if (handle != NULL) kth_wallet_coin_selection_result_destruct(handle); +} + +PyObject* +kth_py_native_wallet_coin_selection_result_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_coin_selection_result_const_t self_handle = (kth_coin_selection_result_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_coin_selection_result_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT, kth_py_native_wallet_coin_selection_result_capsule_dtor); + if (capsule == NULL) { + kth_wallet_coin_selection_result_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_coin_selection_result_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_coin_selection_result_mut_t self_handle = (kth_coin_selection_result_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT); + if (self_handle == NULL) return NULL; + kth_wallet_coin_selection_result_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_coin_selection_result_total_selected_bch(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_coin_selection_result_const_t self_handle = (kth_coin_selection_result_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_coin_selection_result_total_selected_bch(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_wallet_coin_selection_result_total_selected_token(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_coin_selection_result_const_t self_handle = (kth_coin_selection_result_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_coin_selection_result_total_selected_token(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_wallet_coin_selection_result_estimated_size(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_coin_selection_result_const_t self_handle = (kth_coin_selection_result_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_COIN_SELECTION_RESULT); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_coin_selection_result_estimated_size(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyMethodDef kth_py_native_wallet_coin_selection_result_methods[] = { + {"wallet_coin_selection_result_copy", (PyCFunction)kth_py_native_wallet_coin_selection_result_copy, METH_O, NULL}, + {"wallet_coin_selection_result_destruct", (PyCFunction)kth_py_native_wallet_coin_selection_result_destruct, METH_O, NULL}, + {"wallet_coin_selection_result_total_selected_bch", (PyCFunction)kth_py_native_wallet_coin_selection_result_total_selected_bch, METH_O, NULL}, + {"wallet_coin_selection_result_total_selected_token", (PyCFunction)kth_py_native_wallet_coin_selection_result_total_selected_token, METH_O, NULL}, + {"wallet_coin_selection_result_estimated_size", (PyCFunction)kth_py_native_wallet_coin_selection_result_estimated_size, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/ek_private.cpp b/src/wallet/ek_private.cpp new file mode 100644 index 0000000..f95f1eb --- /dev/null +++ b/src/wallet/ek_private.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_ek_private_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_EK_PRIVATE)) return; + kth_ek_private_mut_t handle = (kth_ek_private_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (handle != NULL) kth_wallet_ek_private_destruct(handle); +} + +PyObject* +kth_py_native_wallet_ek_private_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_ek_private_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PRIVATE, kth_py_native_wallet_ek_private_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_private_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_private_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"encoded", NULL}; + char const* encoded = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &encoded)) { + return NULL; + } + auto const result = kth_wallet_ek_private_construct_from_encoded(encoded); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PRIVATE, kth_py_native_wallet_ek_private_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_private_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_private_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"value", NULL}; + char const* value_buf = NULL; + Py_ssize_t value_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#", kwlist, &value_buf, &value_size)) { + return NULL; + } + if (value_size != (Py_ssize_t)43) { + PyErr_Format(PyExc_ValueError, "expected %d-byte value, got %zd", (int)43, value_size); + return NULL; + } + kth_encrypted_private_t value; + memcpy(value.data, value_buf, (size_t)43); + auto const result = kth_wallet_ek_private_construct_from_value(&value); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PRIVATE, kth_py_native_wallet_ek_private_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_private_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_private_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_private_const_t self_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_private_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PRIVATE, kth_py_native_wallet_ek_private_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_private_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_private_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_private_mut_t self_handle = (kth_ek_private_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + kth_wallet_ek_private_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_ek_private_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_ek_private_const_t self_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + kth_ek_private_const_t other_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (other_handle == NULL) return NULL; + auto const result = kth_wallet_ek_private_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_private_less(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_ek_private_const_t self_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + kth_ek_private_const_t x_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (x_handle == NULL) return NULL; + auto const result = kth_wallet_ek_private_less(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_private_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_private_const_t self_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_private_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_private_encoded(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_private_const_t self_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_private_encoded(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_ek_private_private_key(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_private_const_t self_handle = (kth_ek_private_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PRIVATE); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_private_private_key(self_handle); + return Py_BuildValue("y#", result.data, (Py_ssize_t)43); +} + +PyMethodDef kth_py_native_wallet_ek_private_methods[] = { + {"wallet_ek_private_construct_default", (PyCFunction)kth_py_native_wallet_ek_private_construct_default, METH_NOARGS, NULL}, + {"wallet_ek_private_construct_from_encoded", (PyCFunction)kth_py_native_wallet_ek_private_construct_from_encoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_private_construct_from_value", (PyCFunction)kth_py_native_wallet_ek_private_construct_from_value, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_private_copy", (PyCFunction)kth_py_native_wallet_ek_private_copy, METH_O, NULL}, + {"wallet_ek_private_destruct", (PyCFunction)kth_py_native_wallet_ek_private_destruct, METH_O, NULL}, + {"wallet_ek_private_equals", (PyCFunction)kth_py_native_wallet_ek_private_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_private_less", (PyCFunction)kth_py_native_wallet_ek_private_less, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_private_valid", (PyCFunction)kth_py_native_wallet_ek_private_valid, METH_O, NULL}, + {"wallet_ek_private_encoded", (PyCFunction)kth_py_native_wallet_ek_private_encoded, METH_O, NULL}, + {"wallet_ek_private_private_key", (PyCFunction)kth_py_native_wallet_ek_private_private_key, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/ek_public.cpp b/src/wallet/ek_public.cpp new file mode 100644 index 0000000..46eac53 --- /dev/null +++ b/src/wallet/ek_public.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_ek_public_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_EK_PUBLIC)) return; + kth_ek_public_mut_t handle = (kth_ek_public_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (handle != NULL) kth_wallet_ek_public_destruct(handle); +} + +PyObject* +kth_py_native_wallet_ek_public_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_ek_public_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PUBLIC, kth_py_native_wallet_ek_public_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_public_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_public_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"encoded", NULL}; + char const* encoded = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &encoded)) { + return NULL; + } + auto const result = kth_wallet_ek_public_construct_from_encoded(encoded); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PUBLIC, kth_py_native_wallet_ek_public_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_public_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_public_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"value", NULL}; + char const* value_buf = NULL; + Py_ssize_t value_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#", kwlist, &value_buf, &value_size)) { + return NULL; + } + if (value_size != (Py_ssize_t)55) { + PyErr_Format(PyExc_ValueError, "expected %d-byte value, got %zd", (int)55, value_size); + return NULL; + } + kth_encrypted_public_t value; + memcpy(value.data, value_buf, (size_t)55); + auto const result = kth_wallet_ek_public_construct_from_value(&value); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PUBLIC, kth_py_native_wallet_ek_public_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_public_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_public_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_public_const_t self_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_public_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_PUBLIC, kth_py_native_wallet_ek_public_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_public_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_public_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_public_mut_t self_handle = (kth_ek_public_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + kth_wallet_ek_public_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_ek_public_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_ek_public_const_t self_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + kth_ek_public_const_t other_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (other_handle == NULL) return NULL; + auto const result = kth_wallet_ek_public_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_public_less(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_ek_public_const_t self_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + kth_ek_public_const_t x_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (x_handle == NULL) return NULL; + auto const result = kth_wallet_ek_public_less(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_public_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_public_const_t self_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_public_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_public_encoded(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_public_const_t self_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_public_encoded(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_ek_public_public_key(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_public_const_t self_handle = (kth_ek_public_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_PUBLIC); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_public_public_key(self_handle); + return Py_BuildValue("y#", result.data, (Py_ssize_t)55); +} + +PyMethodDef kth_py_native_wallet_ek_public_methods[] = { + {"wallet_ek_public_construct_default", (PyCFunction)kth_py_native_wallet_ek_public_construct_default, METH_NOARGS, NULL}, + {"wallet_ek_public_construct_from_encoded", (PyCFunction)kth_py_native_wallet_ek_public_construct_from_encoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_public_construct_from_value", (PyCFunction)kth_py_native_wallet_ek_public_construct_from_value, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_public_copy", (PyCFunction)kth_py_native_wallet_ek_public_copy, METH_O, NULL}, + {"wallet_ek_public_destruct", (PyCFunction)kth_py_native_wallet_ek_public_destruct, METH_O, NULL}, + {"wallet_ek_public_equals", (PyCFunction)kth_py_native_wallet_ek_public_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_public_less", (PyCFunction)kth_py_native_wallet_ek_public_less, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_public_valid", (PyCFunction)kth_py_native_wallet_ek_public_valid, METH_O, NULL}, + {"wallet_ek_public_encoded", (PyCFunction)kth_py_native_wallet_ek_public_encoded, METH_O, NULL}, + {"wallet_ek_public_public_key", (PyCFunction)kth_py_native_wallet_ek_public_public_key, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/ek_token.cpp b/src/wallet/ek_token.cpp new file mode 100644 index 0000000..5b755a3 --- /dev/null +++ b/src/wallet/ek_token.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_ek_token_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_EK_TOKEN)) return; + kth_ek_token_mut_t handle = (kth_ek_token_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (handle != NULL) kth_wallet_ek_token_destruct(handle); +} + +PyObject* +kth_py_native_wallet_ek_token_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_ek_token_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_TOKEN, kth_py_native_wallet_ek_token_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_token_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_token_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"encoded", NULL}; + char const* encoded = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &encoded)) { + return NULL; + } + auto const result = kth_wallet_ek_token_construct_from_encoded(encoded); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_TOKEN, kth_py_native_wallet_ek_token_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_token_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_token_construct_from_value(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"value", NULL}; + char const* value_buf = NULL; + Py_ssize_t value_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#", kwlist, &value_buf, &value_size)) { + return NULL; + } + if (value_size != (Py_ssize_t)53) { + PyErr_Format(PyExc_ValueError, "expected %d-byte value, got %zd", (int)53, value_size); + return NULL; + } + kth_encrypted_token_t value; + memcpy(value.data, value_buf, (size_t)53); + auto const result = kth_wallet_ek_token_construct_from_value(&value); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_TOKEN, kth_py_native_wallet_ek_token_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_token_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_token_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_token_const_t self_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_token_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EK_TOKEN, kth_py_native_wallet_ek_token_capsule_dtor); + if (capsule == NULL) { + kth_wallet_ek_token_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_ek_token_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_token_mut_t self_handle = (kth_ek_token_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + kth_wallet_ek_token_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_ek_token_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_ek_token_const_t self_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + kth_ek_token_const_t other_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (other_handle == NULL) return NULL; + auto const result = kth_wallet_ek_token_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_token_less(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_ek_token_const_t self_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + kth_ek_token_const_t x_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (x_handle == NULL) return NULL; + auto const result = kth_wallet_ek_token_less(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_token_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_token_const_t self_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_token_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_ek_token_encoded(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_token_const_t self_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_token_encoded(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_ek_token_token(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_ek_token_const_t self_handle = (kth_ek_token_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_EK_TOKEN); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_ek_token_token(self_handle); + return Py_BuildValue("y#", result.data, (Py_ssize_t)53); +} + +PyMethodDef kth_py_native_wallet_ek_token_methods[] = { + {"wallet_ek_token_construct_default", (PyCFunction)kth_py_native_wallet_ek_token_construct_default, METH_NOARGS, NULL}, + {"wallet_ek_token_construct_from_encoded", (PyCFunction)kth_py_native_wallet_ek_token_construct_from_encoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_token_construct_from_value", (PyCFunction)kth_py_native_wallet_ek_token_construct_from_value, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_token_copy", (PyCFunction)kth_py_native_wallet_ek_token_copy, METH_O, NULL}, + {"wallet_ek_token_destruct", (PyCFunction)kth_py_native_wallet_ek_token_destruct, METH_O, NULL}, + {"wallet_ek_token_equals", (PyCFunction)kth_py_native_wallet_ek_token_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_token_less", (PyCFunction)kth_py_native_wallet_ek_token_less, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_ek_token_valid", (PyCFunction)kth_py_native_wallet_ek_token_valid, METH_O, NULL}, + {"wallet_ek_token_encoded", (PyCFunction)kth_py_native_wallet_ek_token_encoded, METH_O, NULL}, + {"wallet_ek_token_token", (PyCFunction)kth_py_native_wallet_ek_token_token, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/encrypted_keys.cpp b/src/wallet/encrypted_keys.cpp new file mode 100644 index 0000000..5cdee38 --- /dev/null +++ b/src/wallet/encrypted_keys.cpp @@ -0,0 +1,69 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_wallet_encrypted_keys_create_key_pair(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"out_private", (char*)"out_point", (char*)"token", (char*)"seed", (char*)"version", (char*)"compressed", NULL}; + char const* out_private_buf = NULL; + Py_ssize_t out_private_size = 0; + char const* out_point_buf = NULL; + Py_ssize_t out_point_size = 0; + char const* token_buf = NULL; + Py_ssize_t token_size = 0; + char const* seed_buf = NULL; + Py_ssize_t seed_size = 0; + unsigned char version = 0; + int compressed = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#y#y#y#Bp", kwlist, &out_private_buf, &out_private_size, &out_point_buf, &out_point_size, &token_buf, &token_size, &seed_buf, &seed_size, &version, &compressed)) { + return NULL; + } + if (out_private_size != (Py_ssize_t)43) { + PyErr_Format(PyExc_ValueError, "expected %d-byte out_private, got %zd", (int)43, out_private_size); + return NULL; + } + kth_encrypted_private_t out_private; + memcpy(out_private.data, out_private_buf, (size_t)43); + if (out_point_size != (Py_ssize_t)KTH_EC_COMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte out_point, got %zd", (int)KTH_EC_COMPRESSED_SIZE, out_point_size); + return NULL; + } + kth_ec_compressed_t out_point; + memcpy(out_point.data, out_point_buf, (size_t)KTH_EC_COMPRESSED_SIZE); + if (token_size != (Py_ssize_t)53) { + PyErr_Format(PyExc_ValueError, "expected %d-byte token, got %zd", (int)53, token_size); + return NULL; + } + kth_encrypted_token_t token; + memcpy(token.data, token_buf, (size_t)53); + if (seed_size != (Py_ssize_t)24) { + PyErr_Format(PyExc_ValueError, "expected %d-byte seed, got %zd", (int)24, seed_size); + return NULL; + } + kth_ek_seed_t seed; + memcpy(seed.data, seed_buf, (size_t)24); + auto const result = kth_wallet_encrypted_keys_create_key_pair(&out_private, &out_point, &token, &seed, (uint8_t)version, (kth_bool_t)compressed); + kth_core_secure_zero((void*)&out_private, sizeof(kth_encrypted_private_t)); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_wallet_encrypted_keys_methods[] = { + {"wallet_encrypted_keys_create_key_pair", (PyCFunction)kth_py_native_wallet_encrypted_keys_create_key_pair, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/language.cpp b/src/wallet/language.cpp new file mode 100644 index 0000000..9b58d21 --- /dev/null +++ b/src/wallet/language.cpp @@ -0,0 +1,144 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_wallet_language_en(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_en(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_es(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_es(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_ja(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_ja(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_it(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_it(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_fr(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_fr(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_cs(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_cs(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_ru(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_ru(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_uk(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_uk(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_zh_Hans(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_zh_Hans(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_zh_Hant(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_zh_Hant(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY, NULL); +} + +PyObject* +kth_py_native_wallet_language_all(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_language_all(); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + return PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_DICTIONARY_LIST, NULL); +} + +PyMethodDef kth_py_native_wallet_language_methods[] = { + {"wallet_language_en", (PyCFunction)kth_py_native_wallet_language_en, METH_NOARGS, NULL}, + {"wallet_language_es", (PyCFunction)kth_py_native_wallet_language_es, METH_NOARGS, NULL}, + {"wallet_language_ja", (PyCFunction)kth_py_native_wallet_language_ja, METH_NOARGS, NULL}, + {"wallet_language_it", (PyCFunction)kth_py_native_wallet_language_it, METH_NOARGS, NULL}, + {"wallet_language_fr", (PyCFunction)kth_py_native_wallet_language_fr, METH_NOARGS, NULL}, + {"wallet_language_cs", (PyCFunction)kth_py_native_wallet_language_cs, METH_NOARGS, NULL}, + {"wallet_language_ru", (PyCFunction)kth_py_native_wallet_language_ru, METH_NOARGS, NULL}, + {"wallet_language_uk", (PyCFunction)kth_py_native_wallet_language_uk, METH_NOARGS, NULL}, + {"wallet_language_zh_Hans", (PyCFunction)kth_py_native_wallet_language_zh_Hans, METH_NOARGS, NULL}, + {"wallet_language_zh_Hant", (PyCFunction)kth_py_native_wallet_language_zh_Hant, METH_NOARGS, NULL}, + {"wallet_language_all", (PyCFunction)kth_py_native_wallet_language_all, METH_NOARGS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/message.cpp b/src/wallet/message.cpp new file mode 100644 index 0000000..22829b5 --- /dev/null +++ b/src/wallet/message.cpp @@ -0,0 +1,165 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_wallet_message_hash_message(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"message", NULL}; + char const* message_buf = NULL; + Py_ssize_t message_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#", kwlist, &message_buf, &message_size)) { + return NULL; + } + auto const result = kth_wallet_message_hash_message((uint8_t const*)message_buf, (kth_size_t)message_size); + return Py_BuildValue("y#", result.hash, (Py_ssize_t)KTH_BITCOIN_HASH_SIZE); +} + +PyObject* +kth_py_native_wallet_message_sign_message_ec_private(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"out_signature", (char*)"message", (char*)"secret", NULL}; + char const* out_signature_buf = NULL; + Py_ssize_t out_signature_size = 0; + char const* message_buf = NULL; + Py_ssize_t message_size = 0; + PyObject* py_secret = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#y#O", kwlist, &out_signature_buf, &out_signature_size, &message_buf, &message_size, &py_secret)) { + return NULL; + } + if (out_signature_size != (Py_ssize_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte out_signature, got %zd", (int)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE, out_signature_size); + return NULL; + } + kth_message_signature_t out_signature; + memcpy(out_signature.data, out_signature_buf, (size_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE); + kth_ec_private_const_t secret_handle = (kth_ec_private_const_t)PyCapsule_GetPointer(py_secret, KTH_PY_CAPSULE_WALLET_EC_PRIVATE); + if (secret_handle == NULL) return NULL; + auto const result = kth_wallet_message_sign_message_ec_private(&out_signature, (uint8_t const*)message_buf, (kth_size_t)message_size, secret_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_message_sign_message_string(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"out_signature", (char*)"message", (char*)"wif", NULL}; + char const* out_signature_buf = NULL; + Py_ssize_t out_signature_size = 0; + char const* message_buf = NULL; + Py_ssize_t message_size = 0; + char const* wif = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#y#s", kwlist, &out_signature_buf, &out_signature_size, &message_buf, &message_size, &wif)) { + return NULL; + } + if (out_signature_size != (Py_ssize_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte out_signature, got %zd", (int)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE, out_signature_size); + return NULL; + } + kth_message_signature_t out_signature; + memcpy(out_signature.data, out_signature_buf, (size_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE); + auto const result = kth_wallet_message_sign_message_string(&out_signature, (uint8_t const*)message_buf, (kth_size_t)message_size, wif); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_message_sign_message_hash(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"out_signature", (char*)"message", (char*)"secret", (char*)"compressed", NULL}; + char const* out_signature_buf = NULL; + Py_ssize_t out_signature_size = 0; + char const* message_buf = NULL; + Py_ssize_t message_size = 0; + char const* secret_buf = NULL; + Py_ssize_t secret_size = 0; + int compressed = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#y#y#p", kwlist, &out_signature_buf, &out_signature_size, &message_buf, &message_size, &secret_buf, &secret_size, &compressed)) { + return NULL; + } + if (out_signature_size != (Py_ssize_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte out_signature, got %zd", (int)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE, out_signature_size); + return NULL; + } + kth_message_signature_t out_signature; + memcpy(out_signature.data, out_signature_buf, (size_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE); + if (secret_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte secret, got %zd", (int)KTH_BITCOIN_HASH_SIZE, secret_size); + return NULL; + } + kth_hash_t secret; + memcpy(secret.hash, secret_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + auto const result = kth_wallet_message_sign_message_hash(&out_signature, (uint8_t const*)message_buf, (kth_size_t)message_size, &secret, (kth_bool_t)compressed); + kth_core_secure_zero((void*)&secret, sizeof(kth_hash_t)); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_message_verify_message(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"message", (char*)"address", (char*)"signature", NULL}; + char const* message_buf = NULL; + Py_ssize_t message_size = 0; + PyObject* py_address = NULL; + char const* signature_buf = NULL; + Py_ssize_t signature_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#Oy#", kwlist, &message_buf, &message_size, &py_address, &signature_buf, &signature_size)) { + return NULL; + } + kth_payment_address_const_t address_handle = (kth_payment_address_const_t)PyCapsule_GetPointer(py_address, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS); + if (address_handle == NULL) return NULL; + if (signature_size != (Py_ssize_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte signature, got %zd", (int)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE, signature_size); + return NULL; + } + kth_message_signature_t signature; + memcpy(signature.data, signature_buf, (size_t)KTH_BITCOIN_EC_UNCOMPRESSED_SIZE); + auto const result = kth_wallet_message_verify_message((uint8_t const*)message_buf, (kth_size_t)message_size, address_handle, &signature); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_message_recovery_id_to_magic(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"out_magic", (char*)"recovery_id", (char*)"compressed", NULL}; + unsigned char out_magic = 0; + unsigned char recovery_id = 0; + int compressed = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "BBp", kwlist, &out_magic, &recovery_id, &compressed)) { + return NULL; + } + auto const result = kth_wallet_message_recovery_id_to_magic((uint8_t)out_magic, (uint8_t)recovery_id, (kth_bool_t)compressed); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_message_magic_to_recovery_id(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"out_recovery_id", (char*)"out_compressed", (char*)"magic", NULL}; + unsigned char out_recovery_id = 0; + int out_compressed = 0; + unsigned char magic = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "BpB", kwlist, &out_recovery_id, &out_compressed, &magic)) { + return NULL; + } + auto const result = kth_wallet_message_magic_to_recovery_id((uint8_t)out_recovery_id, (kth_bool_t)out_compressed, (uint8_t)magic); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_wallet_message_methods[] = { + {"wallet_message_hash_message", (PyCFunction)kth_py_native_wallet_message_hash_message, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_message_sign_message_ec_private", (PyCFunction)kth_py_native_wallet_message_sign_message_ec_private, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_message_sign_message_string", (PyCFunction)kth_py_native_wallet_message_sign_message_string, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_message_sign_message_hash", (PyCFunction)kth_py_native_wallet_message_sign_message_hash, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_message_verify_message", (PyCFunction)kth_py_native_wallet_message_verify_message, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_message_recovery_id_to_magic", (PyCFunction)kth_py_native_wallet_message_recovery_id_to_magic, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_message_magic_to_recovery_id", (PyCFunction)kth_py_native_wallet_message_magic_to_recovery_id, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/mnemonic.cpp b/src/wallet/mnemonic.cpp new file mode 100644 index 0000000..cd5124a --- /dev/null +++ b/src/wallet/mnemonic.cpp @@ -0,0 +1,82 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +PyObject* +kth_py_native_wallet_mnemonic_create_mnemonic(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"entropy", (char*)"lexicon", NULL}; + char const* entropy_buf = NULL; + Py_ssize_t entropy_size = 0; + PyObject* py_lexicon = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#O", kwlist, &entropy_buf, &entropy_size, &py_lexicon)) { + return NULL; + } + kth_dictionary_const_t lexicon_handle = (kth_dictionary_const_t)PyCapsule_GetPointer(py_lexicon, KTH_PY_CAPSULE_WALLET_DICTIONARY); + if (lexicon_handle == NULL) return NULL; + auto const result = kth_wallet_mnemonic_create_mnemonic((uint8_t const*)entropy_buf, (kth_size_t)entropy_size, lexicon_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL list returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CORE_STRING_LIST, NULL); + if (capsule == NULL) { + kth_core_string_list_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_mnemonic_validate_mnemonic_dictionary(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"words", (char*)"lexicon", NULL}; + PyObject* py_words = NULL; + PyObject* py_lexicon = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_words, &py_lexicon)) { + return NULL; + } + kth_string_list_const_t words_handle = (kth_string_list_const_t)PyCapsule_GetPointer(py_words, KTH_PY_CAPSULE_CORE_STRING_LIST); + if (words_handle == NULL) return NULL; + kth_dictionary_const_t lexicon_handle = (kth_dictionary_const_t)PyCapsule_GetPointer(py_lexicon, KTH_PY_CAPSULE_WALLET_DICTIONARY); + if (lexicon_handle == NULL) return NULL; + auto const result = kth_wallet_mnemonic_validate_mnemonic_dictionary(words_handle, lexicon_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_mnemonic_validate_mnemonic_dictionary_list(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"mnemonic", (char*)"lexicons", NULL}; + PyObject* py_mnemonic = NULL; + PyObject* py_lexicons = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_mnemonic, &py_lexicons)) { + return NULL; + } + kth_string_list_const_t mnemonic_handle = (kth_string_list_const_t)PyCapsule_GetPointer(py_mnemonic, KTH_PY_CAPSULE_CORE_STRING_LIST); + if (mnemonic_handle == NULL) return NULL; + kth_dictionary_list_const_t lexicons_handle = (kth_dictionary_list_const_t)PyCapsule_GetPointer(py_lexicons, KTH_PY_CAPSULE_WALLET_DICTIONARY_LIST); + if (lexicons_handle == NULL) return NULL; + auto const result = kth_wallet_mnemonic_validate_mnemonic_dictionary_list(mnemonic_handle, lexicons_handle); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_wallet_mnemonic_methods[] = { + {"wallet_mnemonic_create_mnemonic", (PyCFunction)kth_py_native_wallet_mnemonic_create_mnemonic, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_mnemonic_validate_mnemonic_dictionary", (PyCFunction)kth_py_native_wallet_mnemonic_validate_mnemonic_dictionary, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_mnemonic_validate_mnemonic_dictionary_list", (PyCFunction)kth_py_native_wallet_mnemonic_validate_mnemonic_dictionary_list, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/stealth_address.cpp b/src/wallet/stealth_address.cpp new file mode 100644 index 0000000..af90d47 --- /dev/null +++ b/src/wallet/stealth_address.cpp @@ -0,0 +1,306 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_stealth_address_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS)) return; + kth_stealth_address_mut_t handle = (kth_stealth_address_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (handle != NULL) kth_wallet_stealth_address_destruct(handle); +} + +PyObject* +kth_py_native_wallet_stealth_address_construct_default(PyObject* self, PyObject* Py_UNUSED(args)) { + auto const result = kth_wallet_stealth_address_construct_default(); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_wallet_stealth_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_construct_from_decoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"decoded", NULL}; + char const* decoded_buf = NULL; + Py_ssize_t decoded_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#", kwlist, &decoded_buf, &decoded_size)) { + return NULL; + } + auto const result = kth_wallet_stealth_address_construct_from_decoded((uint8_t const*)decoded_buf, (kth_size_t)decoded_size); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_wallet_stealth_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_construct_from_encoded(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"encoded", NULL}; + char const* encoded = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &encoded)) { + return NULL; + } + auto const result = kth_wallet_stealth_address_construct_from_encoded(encoded); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_wallet_stealth_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_construct_from_binary_scan_key_spend_keys_signatures_version(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"filter", (char*)"scan_key", (char*)"spend_keys", (char*)"signatures", (char*)"version", NULL}; + PyObject* py_filter = NULL; + char const* scan_key_buf = NULL; + Py_ssize_t scan_key_size = 0; + PyObject* py_spend_keys = NULL; + unsigned char signatures = 0; + unsigned char version = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#OBB", kwlist, &py_filter, &scan_key_buf, &scan_key_size, &py_spend_keys, &signatures, &version)) { + return NULL; + } + kth_binary_const_t filter_handle = (kth_binary_const_t)PyCapsule_GetPointer(py_filter, KTH_PY_CAPSULE_CORE_BINARY); + if (filter_handle == NULL) return NULL; + if (scan_key_size != (Py_ssize_t)KTH_EC_COMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte scan_key, got %zd", (int)KTH_EC_COMPRESSED_SIZE, scan_key_size); + return NULL; + } + kth_ec_compressed_t scan_key; + memcpy(scan_key.data, scan_key_buf, (size_t)KTH_EC_COMPRESSED_SIZE); + kth_ec_compressed_list_const_t spend_keys_handle = (kth_ec_compressed_list_const_t)PyCapsule_GetPointer(py_spend_keys, KTH_PY_CAPSULE_WALLET_EC_COMPRESSED_LIST); + if (spend_keys_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_construct_from_binary_scan_key_spend_keys_signatures_version(filter_handle, &scan_key, spend_keys_handle, (uint8_t)signatures, (uint8_t)version); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_wallet_stealth_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_wallet_stealth_address_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_address_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_mut_t self_handle = (kth_stealth_address_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + kth_wallet_stealth_address_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_stealth_address_equals(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"other", NULL}; + PyObject* py_self = NULL; + PyObject* py_other = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_other)) { + return NULL; + } + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + kth_stealth_address_const_t other_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_other, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (other_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_equals(self_handle, other_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_stealth_address_less(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"x", NULL}; + PyObject* py_self = NULL; + PyObject* py_x = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &py_self, &py_x)) { + return NULL; + } + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + kth_stealth_address_const_t x_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_x, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (x_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_less(self_handle, x_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_stealth_address_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_stealth_address_encoded(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_encoded(self_handle); + if (result == NULL) Py_RETURN_NONE; + PyObject* py_result = Py_BuildValue("s", result); + kth_core_destruct_string(result); + return py_result; +} + +PyObject* +kth_py_native_wallet_stealth_address_version(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_version(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_wallet_stealth_address_scan_key(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_scan_key(self_handle); + return Py_BuildValue("y#", result.data, (Py_ssize_t)KTH_EC_COMPRESSED_SIZE); +} + +PyObject* +kth_py_native_wallet_stealth_address_spend_keys(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_spend_keys(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL list returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_EC_COMPRESSED_LIST, kth_py_native_borrowed_parent_dtor); + if (capsule == NULL) return NULL; + Py_INCREF(py_self); + if (PyCapsule_SetContext(capsule, py_self) != 0) { + Py_DECREF(py_self); + Py_DECREF(capsule); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_signatures(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_signatures(self_handle); + return PyLong_FromUnsignedLongLong((unsigned long long)result); +} + +PyObject* +kth_py_native_wallet_stealth_address_filter(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_address_filter(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CORE_BINARY, kth_py_native_borrowed_parent_dtor); + if (capsule == NULL) return NULL; + Py_INCREF(py_self); + if (PyCapsule_SetContext(capsule, py_self) != 0) { + Py_DECREF(py_self); + Py_DECREF(capsule); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_address_to_chunk(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_address_const_t self_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (self_handle == NULL) return NULL; + kth_size_t out_size = 0; + auto const result = kth_wallet_stealth_address_to_chunk(self_handle, &out_size); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: serialization failed"); + return NULL; + } + PyObject* py_result = Py_BuildValue("y#", result, (Py_ssize_t)out_size); + kth_core_destruct_array(result); + return py_result; +} + +PyMethodDef kth_py_native_wallet_stealth_address_methods[] = { + {"wallet_stealth_address_construct_default", (PyCFunction)kth_py_native_wallet_stealth_address_construct_default, METH_NOARGS, NULL}, + {"wallet_stealth_address_construct_from_decoded", (PyCFunction)kth_py_native_wallet_stealth_address_construct_from_decoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_address_construct_from_encoded", (PyCFunction)kth_py_native_wallet_stealth_address_construct_from_encoded, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_address_construct_from_binary_scan_key_spend_keys_signatures_version", (PyCFunction)kth_py_native_wallet_stealth_address_construct_from_binary_scan_key_spend_keys_signatures_version, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_address_copy", (PyCFunction)kth_py_native_wallet_stealth_address_copy, METH_O, NULL}, + {"wallet_stealth_address_destruct", (PyCFunction)kth_py_native_wallet_stealth_address_destruct, METH_O, NULL}, + {"wallet_stealth_address_equals", (PyCFunction)kth_py_native_wallet_stealth_address_equals, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_address_less", (PyCFunction)kth_py_native_wallet_stealth_address_less, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_address_valid", (PyCFunction)kth_py_native_wallet_stealth_address_valid, METH_O, NULL}, + {"wallet_stealth_address_encoded", (PyCFunction)kth_py_native_wallet_stealth_address_encoded, METH_O, NULL}, + {"wallet_stealth_address_version", (PyCFunction)kth_py_native_wallet_stealth_address_version, METH_O, NULL}, + {"wallet_stealth_address_scan_key", (PyCFunction)kth_py_native_wallet_stealth_address_scan_key, METH_O, NULL}, + {"wallet_stealth_address_spend_keys", (PyCFunction)kth_py_native_wallet_stealth_address_spend_keys, METH_O, NULL}, + {"wallet_stealth_address_signatures", (PyCFunction)kth_py_native_wallet_stealth_address_signatures, METH_O, NULL}, + {"wallet_stealth_address_filter", (PyCFunction)kth_py_native_wallet_stealth_address_filter, METH_O, NULL}, + {"wallet_stealth_address_to_chunk", (PyCFunction)kth_py_native_wallet_stealth_address_to_chunk, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/stealth_receiver.cpp b/src/wallet/stealth_receiver.cpp new file mode 100644 index 0000000..af35c9b --- /dev/null +++ b/src/wallet/stealth_receiver.cpp @@ -0,0 +1,193 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_stealth_receiver_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER)) return; + kth_stealth_receiver_mut_t handle = (kth_stealth_receiver_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (handle != NULL) kth_wallet_stealth_receiver_destruct(handle); +} + +PyObject* +kth_py_native_wallet_stealth_receiver_construct(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"scan_private", (char*)"spend_private", (char*)"filter", (char*)"version", NULL}; + char const* scan_private_buf = NULL; + Py_ssize_t scan_private_size = 0; + char const* spend_private_buf = NULL; + Py_ssize_t spend_private_size = 0; + PyObject* py_filter = NULL; + unsigned char version = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#y#OB", kwlist, &scan_private_buf, &scan_private_size, &spend_private_buf, &spend_private_size, &py_filter, &version)) { + return NULL; + } + if (scan_private_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte scan_private, got %zd", (int)KTH_BITCOIN_HASH_SIZE, scan_private_size); + return NULL; + } + kth_hash_t scan_private; + memcpy(scan_private.hash, scan_private_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + if (spend_private_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte spend_private, got %zd", (int)KTH_BITCOIN_HASH_SIZE, spend_private_size); + return NULL; + } + kth_hash_t spend_private; + memcpy(spend_private.hash, spend_private_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + kth_binary_const_t filter_handle = (kth_binary_const_t)PyCapsule_GetPointer(py_filter, KTH_PY_CAPSULE_CORE_BINARY); + if (filter_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_receiver_construct(&scan_private, &spend_private, filter_handle, (uint8_t)version); + kth_core_secure_zero((void*)&scan_private, sizeof(kth_hash_t)); + kth_core_secure_zero((void*)&spend_private, sizeof(kth_hash_t)); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER, kth_py_native_wallet_stealth_receiver_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_receiver_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_receiver_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_receiver_const_t self_handle = (kth_stealth_receiver_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_receiver_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER, kth_py_native_wallet_stealth_receiver_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_receiver_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_receiver_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_receiver_mut_t self_handle = (kth_stealth_receiver_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (self_handle == NULL) return NULL; + kth_wallet_stealth_receiver_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_stealth_receiver_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_receiver_const_t self_handle = (kth_stealth_receiver_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_receiver_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_stealth_receiver_stealth_address(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_receiver_const_t self_handle = (kth_stealth_receiver_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_receiver_stealth_address(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS, kth_py_native_borrowed_parent_dtor); + if (capsule == NULL) return NULL; + Py_INCREF(py_self); + if (PyCapsule_SetContext(capsule, py_self) != 0) { + Py_DECREF(py_self); + Py_DECREF(capsule); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_receiver_derive_address(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"out_address", (char*)"ephemeral_public", NULL}; + PyObject* py_self = NULL; + PyObject* py_out_address = NULL; + char const* ephemeral_public_buf = NULL; + Py_ssize_t ephemeral_public_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "OOy#", kwlist, &py_self, &py_out_address, &ephemeral_public_buf, &ephemeral_public_size)) { + return NULL; + } + kth_stealth_receiver_const_t self_handle = (kth_stealth_receiver_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (self_handle == NULL) return NULL; + kth_payment_address_mut_t out_address_handle = (kth_payment_address_mut_t)PyCapsule_GetPointer(py_out_address, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS); + if (out_address_handle == NULL) return NULL; + if (ephemeral_public_size != (Py_ssize_t)KTH_EC_COMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte ephemeral_public, got %zd", (int)KTH_EC_COMPRESSED_SIZE, ephemeral_public_size); + return NULL; + } + kth_ec_compressed_t ephemeral_public; + memcpy(ephemeral_public.data, ephemeral_public_buf, (size_t)KTH_EC_COMPRESSED_SIZE); + auto const result = kth_wallet_stealth_receiver_derive_address(self_handle, out_address_handle, &ephemeral_public); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_stealth_receiver_derive_private(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"self", (char*)"out_private", (char*)"ephemeral_public", NULL}; + PyObject* py_self = NULL; + char const* out_private_buf = NULL; + Py_ssize_t out_private_size = 0; + char const* ephemeral_public_buf = NULL; + Py_ssize_t ephemeral_public_size = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#y#", kwlist, &py_self, &out_private_buf, &out_private_size, &ephemeral_public_buf, &ephemeral_public_size)) { + return NULL; + } + kth_stealth_receiver_const_t self_handle = (kth_stealth_receiver_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_RECEIVER); + if (self_handle == NULL) return NULL; + if (out_private_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte out_private, got %zd", (int)KTH_BITCOIN_HASH_SIZE, out_private_size); + return NULL; + } + kth_hash_t out_private; + memcpy(out_private.hash, out_private_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + if (ephemeral_public_size != (Py_ssize_t)KTH_EC_COMPRESSED_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte ephemeral_public, got %zd", (int)KTH_EC_COMPRESSED_SIZE, ephemeral_public_size); + return NULL; + } + kth_ec_compressed_t ephemeral_public; + memcpy(ephemeral_public.data, ephemeral_public_buf, (size_t)KTH_EC_COMPRESSED_SIZE); + auto const result = kth_wallet_stealth_receiver_derive_private(self_handle, &out_private, &ephemeral_public); + kth_core_secure_zero((void*)&out_private, sizeof(kth_hash_t)); + return PyBool_FromLong((long)result); +} + +PyMethodDef kth_py_native_wallet_stealth_receiver_methods[] = { + {"wallet_stealth_receiver_construct", (PyCFunction)kth_py_native_wallet_stealth_receiver_construct, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_receiver_copy", (PyCFunction)kth_py_native_wallet_stealth_receiver_copy, METH_O, NULL}, + {"wallet_stealth_receiver_destruct", (PyCFunction)kth_py_native_wallet_stealth_receiver_destruct, METH_O, NULL}, + {"wallet_stealth_receiver_valid", (PyCFunction)kth_py_native_wallet_stealth_receiver_valid, METH_O, NULL}, + {"wallet_stealth_receiver_stealth_address", (PyCFunction)kth_py_native_wallet_stealth_receiver_stealth_address, METH_O, NULL}, + {"wallet_stealth_receiver_derive_address", (PyCFunction)kth_py_native_wallet_stealth_receiver_derive_address, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_receiver_derive_private", (PyCFunction)kth_py_native_wallet_stealth_receiver_derive_private, METH_VARARGS | METH_KEYWORDS, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/stealth_sender.cpp b/src/wallet/stealth_sender.cpp new file mode 100644 index 0000000..359fa50 --- /dev/null +++ b/src/wallet/stealth_sender.cpp @@ -0,0 +1,184 @@ +// Copyright (c) 2016-present Knuth Project developers. +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// PyCapsule destructor — released by GC when the capsule is +// collected. Explicit `destruct` calls set the capsule name to +// "kth.destroyed", so PyCapsule_IsValid returns false and this +// destructor becomes a no-op (no double-free). +void kth_py_native_wallet_stealth_sender_capsule_dtor(PyObject* capsule) { + if ( ! PyCapsule_IsValid(capsule, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER)) return; + kth_stealth_sender_mut_t handle = (kth_stealth_sender_mut_t)PyCapsule_GetPointer(capsule, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER); + if (handle != NULL) kth_wallet_stealth_sender_destruct(handle); +} + +PyObject* +kth_py_native_wallet_stealth_sender_construct_from_stealth_address_seed_binary_version(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"address", (char*)"seed", (char*)"filter", (char*)"version", NULL}; + PyObject* py_address = NULL; + char const* seed_buf = NULL; + Py_ssize_t seed_size = 0; + PyObject* py_filter = NULL; + unsigned char version = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "Oy#OB", kwlist, &py_address, &seed_buf, &seed_size, &py_filter, &version)) { + return NULL; + } + kth_stealth_address_const_t address_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_address, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (address_handle == NULL) return NULL; + kth_binary_const_t filter_handle = (kth_binary_const_t)PyCapsule_GetPointer(py_filter, KTH_PY_CAPSULE_CORE_BINARY); + if (filter_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_sender_construct_from_stealth_address_seed_binary_version(address_handle, (uint8_t const*)seed_buf, (kth_size_t)seed_size, filter_handle, (uint8_t)version); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER, kth_py_native_wallet_stealth_sender_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_sender_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_sender_construct_from_ephemeral_private_stealth_address_seed_binary_version(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"ephemeral_private", (char*)"address", (char*)"seed", (char*)"filter", (char*)"version", NULL}; + char const* ephemeral_private_buf = NULL; + Py_ssize_t ephemeral_private_size = 0; + PyObject* py_address = NULL; + char const* seed_buf = NULL; + Py_ssize_t seed_size = 0; + PyObject* py_filter = NULL; + unsigned char version = 0; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "y#Oy#OB", kwlist, &ephemeral_private_buf, &ephemeral_private_size, &py_address, &seed_buf, &seed_size, &py_filter, &version)) { + return NULL; + } + if (ephemeral_private_size != (Py_ssize_t)KTH_BITCOIN_HASH_SIZE) { + PyErr_Format(PyExc_ValueError, "expected %d-byte ephemeral_private, got %zd", (int)KTH_BITCOIN_HASH_SIZE, ephemeral_private_size); + return NULL; + } + kth_hash_t ephemeral_private; + memcpy(ephemeral_private.hash, ephemeral_private_buf, (size_t)KTH_BITCOIN_HASH_SIZE); + kth_stealth_address_const_t address_handle = (kth_stealth_address_const_t)PyCapsule_GetPointer(py_address, KTH_PY_CAPSULE_WALLET_STEALTH_ADDRESS); + if (address_handle == NULL) return NULL; + kth_binary_const_t filter_handle = (kth_binary_const_t)PyCapsule_GetPointer(py_filter, KTH_PY_CAPSULE_CORE_BINARY); + if (filter_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_sender_construct_from_ephemeral_private_stealth_address_seed_binary_version(&ephemeral_private, address_handle, (uint8_t const*)seed_buf, (kth_size_t)seed_size, filter_handle, (uint8_t)version); + kth_core_secure_zero((void*)&ephemeral_private, sizeof(kth_hash_t)); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER, kth_py_native_wallet_stealth_sender_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_sender_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_sender_copy(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_sender_const_t self_handle = (kth_stealth_sender_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_sender_copy(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_MemoryError, "kth: allocation failed"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER, kth_py_native_wallet_stealth_sender_capsule_dtor); + if (capsule == NULL) { + kth_wallet_stealth_sender_destruct(result); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_sender_destruct(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_sender_mut_t self_handle = (kth_stealth_sender_mut_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER); + if (self_handle == NULL) return NULL; + kth_wallet_stealth_sender_destruct(self_handle); + PyCapsule_SetName(py_self, "kth.destroyed"); + Py_RETURN_NONE; +} + +PyObject* +kth_py_native_wallet_stealth_sender_valid(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_sender_const_t self_handle = (kth_stealth_sender_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_sender_valid(self_handle); + return PyBool_FromLong((long)result); +} + +PyObject* +kth_py_native_wallet_stealth_sender_stealth_script(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_sender_const_t self_handle = (kth_stealth_sender_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_sender_stealth_script(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_CHAIN_SCRIPT, kth_py_native_borrowed_parent_dtor); + if (capsule == NULL) return NULL; + Py_INCREF(py_self); + if (PyCapsule_SetContext(capsule, py_self) != 0) { + Py_DECREF(py_self); + Py_DECREF(capsule); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_stealth_sender_payment_address(PyObject* self, PyObject* py_arg0) { + PyObject* py_self = py_arg0; + kth_stealth_sender_const_t self_handle = (kth_stealth_sender_const_t)PyCapsule_GetPointer(py_self, KTH_PY_CAPSULE_WALLET_STEALTH_SENDER); + if (self_handle == NULL) return NULL; + auto const result = kth_wallet_stealth_sender_payment_address(self_handle); + if (result == NULL) { + PyErr_SetString(PyExc_RuntimeError, "kth: NULL handle returned"); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)result, KTH_PY_CAPSULE_WALLET_PAYMENT_ADDRESS, kth_py_native_borrowed_parent_dtor); + if (capsule == NULL) return NULL; + Py_INCREF(py_self); + if (PyCapsule_SetContext(capsule, py_self) != 0) { + Py_DECREF(py_self); + Py_DECREF(capsule); + return NULL; + } + return capsule; +} + +PyMethodDef kth_py_native_wallet_stealth_sender_methods[] = { + {"wallet_stealth_sender_construct_from_stealth_address_seed_binary_version", (PyCFunction)kth_py_native_wallet_stealth_sender_construct_from_stealth_address_seed_binary_version, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_sender_construct_from_ephemeral_private_stealth_address_seed_binary_version", (PyCFunction)kth_py_native_wallet_stealth_sender_construct_from_ephemeral_private_stealth_address_seed_binary_version, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_stealth_sender_copy", (PyCFunction)kth_py_native_wallet_stealth_sender_copy, METH_O, NULL}, + {"wallet_stealth_sender_destruct", (PyCFunction)kth_py_native_wallet_stealth_sender_destruct, METH_O, NULL}, + {"wallet_stealth_sender_valid", (PyCFunction)kth_py_native_wallet_stealth_sender_valid, METH_O, NULL}, + {"wallet_stealth_sender_stealth_script", (PyCFunction)kth_py_native_wallet_stealth_sender_stealth_script, METH_O, NULL}, + {"wallet_stealth_sender_payment_address", (PyCFunction)kth_py_native_wallet_stealth_sender_payment_address, METH_O, NULL}, + {NULL, NULL, 0, NULL} // sentinel +}; + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/src/wallet/wallet_data.cpp b/src/wallet/wallet_data.cpp index 41e7080..2d9c505 100644 --- a/src/wallet/wallet_data.cpp +++ b/src/wallet/wallet_data.cpp @@ -161,6 +161,31 @@ kth_py_native_wallet_wallet_data_set_encrypted_seed(PyObject* self, PyObject* ar PyObject* kth_py_native_wallet_wallet_data_create(PyObject* self, PyObject* args, PyObject* kwds) { + static char* kwlist[] = {(char*)"password", (char*)"normalized_passphrase", (char*)"lexicon", NULL}; + char const* password = NULL; + char const* normalized_passphrase = NULL; + PyObject* py_lexicon = NULL; + if ( ! PyArg_ParseTupleAndKeywords(args, kwds, "ssO", kwlist, &password, &normalized_passphrase, &py_lexicon)) { + return NULL; + } + kth_dictionary_const_t lexicon_handle = (kth_dictionary_const_t)PyCapsule_GetPointer(py_lexicon, KTH_PY_CAPSULE_WALLET_DICTIONARY); + if (lexicon_handle == NULL) return NULL; + kth_wallet_data_mut_t out = NULL; + kth_error_code_t result = kth_wallet_create(password, normalized_passphrase, lexicon_handle, &out); + if (result != kth_ec_success) { + PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); + return NULL; + } + PyObject* capsule = PyCapsule_New((void*)out, KTH_PY_CAPSULE_WALLET_WALLET_DATA, kth_py_native_wallet_wallet_data_capsule_dtor); + if (capsule == NULL) { + kth_wallet_wallet_data_destruct(out); + return NULL; + } + return capsule; +} + +PyObject* +kth_py_native_wallet_wallet_data_create_simple(PyObject* self, PyObject* args, PyObject* kwds) { static char* kwlist[] = {(char*)"password", (char*)"normalized_passphrase", NULL}; char const* password = NULL; char const* normalized_passphrase = NULL; @@ -168,7 +193,7 @@ kth_py_native_wallet_wallet_data_create(PyObject* self, PyObject* args, PyObject return NULL; } kth_wallet_data_mut_t out = NULL; - kth_error_code_t result = kth_wallet_create(password, normalized_passphrase, &out); + kth_error_code_t result = kth_wallet_create_simple(password, normalized_passphrase, &out); if (result != kth_ec_success) { PyErr_Format(PyExc_RuntimeError, "kth error code %d", (int)result); return NULL; @@ -191,6 +216,7 @@ PyMethodDef kth_py_native_wallet_wallet_data_methods[] = { {"wallet_wallet_data_encrypted_seed", (PyCFunction)kth_py_native_wallet_wallet_data_encrypted_seed, METH_O, NULL}, {"wallet_wallet_data_set_encrypted_seed", (PyCFunction)kth_py_native_wallet_wallet_data_set_encrypted_seed, METH_VARARGS | METH_KEYWORDS, NULL}, {"wallet_wallet_data_create", (PyCFunction)kth_py_native_wallet_wallet_data_create, METH_VARARGS | METH_KEYWORDS, NULL}, + {"wallet_wallet_data_create_simple", (PyCFunction)kth_py_native_wallet_wallet_data_create_simple, METH_VARARGS | METH_KEYWORDS, NULL}, {NULL, NULL, 0, NULL} // sentinel }; diff --git a/tests/test_chain_input_point.py b/tests/test_chain_input_point.py new file mode 100644 index 0000000..261725a --- /dev/null +++ b/tests/test_chain_input_point.py @@ -0,0 +1,73 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the chain_input_point binding. + +`input_point` is a typedef alias for `point` in the domain layer +(`using input_point = point;`), so the underlying behaviour is fully +covered by test_chain_point.py. These tests pin the alias-prefixed +Python surface so the binding stays wired through correctly. +""" + +import pytest + +import kth_native as nat + + +HASH = bytes(( + 0x6f, 0xe2, 0x8c, 0x0a, 0xb6, 0xf1, 0xb3, 0x72, + 0xc1, 0xa6, 0xa2, 0x46, 0xae, 0x63, 0xf7, 0x4f, + 0x93, 0x1e, 0x83, 0x65, 0xe1, 0x5a, 0x08, 0x9c, + 0x68, 0xd6, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, +)) + +INDEX = 7 + + +def test_default_construct_is_invalid(): + ip = nat.chain_input_point_construct_default() + assert nat.chain_input_point_is_valid(ip) is False + + +def test_field_constructor_preserves_fields(): + ip = nat.chain_input_point_construct(HASH, INDEX) + assert nat.chain_input_point_is_valid(ip) is True + assert nat.chain_input_point_hash(ip) == HASH + assert nat.chain_input_point_index(ip) == INDEX + + +def test_to_data_from_data_roundtrip(): + original = nat.chain_input_point_construct(HASH, INDEX) + raw = nat.chain_input_point_to_data(original, True) + assert isinstance(raw, bytes) + assert len(raw) > 0 + + parsed = nat.chain_input_point_construct_from_data(raw, True) + assert nat.chain_input_point_is_valid(parsed) is True + assert nat.chain_input_point_equals(original, parsed) is True + + +def test_setters_roundtrip(): + ip = nat.chain_input_point_construct_default() + nat.chain_input_point_set_hash(ip, HASH) + nat.chain_input_point_set_index(ip, INDEX) + assert nat.chain_input_point_hash(ip) == HASH + assert nat.chain_input_point_index(ip) == INDEX + + +def test_copy_preserves_fields(): + a = nat.chain_input_point_construct(HASH, INDEX) + b = nat.chain_input_point_copy(a) + assert nat.chain_input_point_equals(a, b) is True + + +def test_satoshi_fixed_size_is_36(): + assert nat.chain_input_point_satoshi_fixed_size() == 36 + + +def test_null_factory_is_null(): + ip = nat.chain_input_point_null() + # `null` returns a sentinel input_point; the C-API contract + # is that `is_null` returns True for it. + assert nat.chain_input_point_is_valid(ip) is False diff --git a/tests/test_vm_big_number.py b/tests/test_vm_big_number.py new file mode 100644 index 0000000..4220ca9 --- /dev/null +++ b/tests/test_vm_big_number.py @@ -0,0 +1,57 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the vm_big_number binding.""" + +import pytest + +import kth_native as nat + + +def test_default_is_zero(): + n = nat.vm_big_number_construct_default() + assert nat.vm_big_number_is_zero(n) is True + assert nat.vm_big_number_sign(n) == 0 + + +def test_from_value_positive(): + n = nat.vm_big_number_construct_from_value(42) + assert nat.vm_big_number_is_zero(n) is False + assert nat.vm_big_number_is_nonzero(n) is True + assert nat.vm_big_number_is_negative(n) is False + assert nat.vm_big_number_sign(n) == 1 + assert nat.vm_big_number_to_string(n) == "42" + + +def test_from_value_negative(): + n = nat.vm_big_number_construct_from_value(-7) + assert nat.vm_big_number_is_negative(n) is True + assert nat.vm_big_number_sign(n) == -1 + assert nat.vm_big_number_to_string(n) == "-7" + + +def test_from_decimal_str_large_value(): + # 2^100 — far beyond int64 range. + big = nat.vm_big_number_construct_from_decimal_str( + "1267650600228229401496703205376") + assert nat.vm_big_number_is_negative(big) is False + assert nat.vm_big_number_to_string(big) == "1267650600228229401496703205376" + + +def test_from_hex_roundtrip(): + n = nat.vm_big_number_from_hex("ff") + assert nat.vm_big_number_to_hex(n) == "ff" + + +def test_to_int32_saturating_clamps(): + big = nat.vm_big_number_construct_from_decimal_str( + "999999999999999999") + # Saturates at INT32_MAX (2147483647). + assert nat.vm_big_number_to_int32_saturating(big) == 2147483647 + + +def test_copy_preserves_value(): + a = nat.vm_big_number_construct_from_value(12345) + b = nat.vm_big_number_copy(a) + assert nat.vm_big_number_to_string(b) == "12345" diff --git a/tests/test_wallet_bitcoin_uri.py b/tests/test_wallet_bitcoin_uri.py new file mode 100644 index 0000000..efb0ede --- /dev/null +++ b/tests/test_wallet_bitcoin_uri.py @@ -0,0 +1,42 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the wallet_bitcoin_uri binding (BIP21 URI parser / builder).""" + +import pytest + +import kth_native as nat + + +URI = "bitcoin:1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L?amount=0.0001&label=Foo" + + +def test_default_construct_is_invalid(): + uri = nat.wallet_bitcoin_uri_construct_default() + assert nat.wallet_bitcoin_uri_valid(uri) is False + + +def test_construct_from_string_parses_amount_and_label(): + uri = nat.wallet_bitcoin_uri_construct(URI, True) + assert nat.wallet_bitcoin_uri_valid(uri) is True + # `amount` returns satoshis as an int — 0.0001 BTC = 10000 sat. + assert nat.wallet_bitcoin_uri_amount(uri) == 10000 + assert nat.wallet_bitcoin_uri_label(uri) == "Foo" + + +def test_set_label_round_trips(): + uri = nat.wallet_bitcoin_uri_construct_default() + nat.wallet_bitcoin_uri_set_label(uri, "Bar") + assert nat.wallet_bitcoin_uri_label(uri) == "Bar" + + +def test_encoded_round_trip(): + a = nat.wallet_bitcoin_uri_construct(URI, True) + b = nat.wallet_bitcoin_uri_construct(nat.wallet_bitcoin_uri_encoded(a), True) + assert nat.wallet_bitcoin_uri_equals(a, b) is True + + +def test_invalid_uri_returns_invalid_handle(): + uri = nat.wallet_bitcoin_uri_construct("not-a-uri", True) + assert nat.wallet_bitcoin_uri_valid(uri) is False diff --git a/tests/test_wallet_cashaddr.py b/tests/test_wallet_cashaddr.py new file mode 100644 index 0000000..54a8b7e --- /dev/null +++ b/tests/test_wallet_cashaddr.py @@ -0,0 +1,52 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the wallet_cashaddr namespace-module binding. + +The namespace exposes two free functions: `encode` and `decode`. +`decode` returns a `(prefix, payload)` tuple via the Python backend's +`pair` shape — added alongside the rest of the +0.83 sync. +""" + +import pytest + +import kth_native as nat + + +# Reference vector lifted from `src/c-api/test/wallet/cashaddr.cpp` +# — a known-good mainnet P2KH cashaddr + its decoded payload. +ADDR = "bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a" +PREFIX = "bitcoincash" + + +def test_encode_round_trip_through_decode(): + decoded = nat.wallet_cashaddr_decode(ADDR, PREFIX) + assert decoded is not None + prefix, payload = decoded + assert prefix == PREFIX + assert isinstance(payload, bytes) + assert len(payload) > 0 + + re_encoded = nat.wallet_cashaddr_encode(prefix, payload) + assert re_encoded == ADDR + + +def test_decode_uppercase_address(): + # CashAddr accepts all-uppercase as the same address. + decoded = nat.wallet_cashaddr_decode(ADDR.upper(), PREFIX) + assert decoded is not None + prefix, payload = decoded + assert prefix == PREFIX + assert len(payload) > 0 + + +def test_decode_invalid_returns_none(): + # A garbage string has no valid cashaddr decoding. + assert nat.wallet_cashaddr_decode("not-an-address", PREFIX) is None + + +def test_decode_wrong_prefix_returns_none(): + # Same address, wrong expected prefix. + assert nat.wallet_cashaddr_decode(ADDR, "bchtest") is None diff --git a/tests/test_wallet_ek_private.py b/tests/test_wallet_ek_private.py new file mode 100644 index 0000000..965eef0 --- /dev/null +++ b/tests/test_wallet_ek_private.py @@ -0,0 +1,38 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the wallet_ek_private binding (BIP38 encrypted private key).""" + +import pytest + +import kth_native as nat + + +# Reference BIP38 encrypted private key from BIP38 spec test vectors — +# corresponds to the passphrase "TestingOneTwoThree" with no EC +# multiplication. 58 ASCII chars, base58 round-trip safe. +EK_ENCODED = "6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg" + + +def test_default_construct_is_invalid(): + ek = nat.wallet_ek_private_construct_default() + assert nat.wallet_ek_private_valid(ek) is False + + +def test_from_encoded_roundtrip(): + ek = nat.wallet_ek_private_construct_from_encoded(EK_ENCODED) + assert nat.wallet_ek_private_valid(ek) is True + assert nat.wallet_ek_private_encoded(ek) == EK_ENCODED + + +def test_copy_preserves_state(): + a = nat.wallet_ek_private_construct_from_encoded(EK_ENCODED) + b = nat.wallet_ek_private_copy(a) + assert nat.wallet_ek_private_equals(a, b) is True + assert nat.wallet_ek_private_encoded(b) == EK_ENCODED + + +def test_invalid_encoded_returns_invalid_handle(): + ek = nat.wallet_ek_private_construct_from_encoded("not-a-bip38-key") + assert nat.wallet_ek_private_valid(ek) is False diff --git a/tests/test_wallet_language.py b/tests/test_wallet_language.py new file mode 100644 index 0000000..3b59fee --- /dev/null +++ b/tests/test_wallet_language.py @@ -0,0 +1,40 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the wallet_language namespace-module binding. + +Each factory (`en`, `es`, `ja`, `it`, `fr`, `cs`, `ru`, `uk`, +`zh_Hans`, `zh_Hant`) returns an opaque-handle capsule wrapping +the static BIP39 wordlist. `all()` returns a list capsule of all +ten wordlists. +""" + +import pytest + +import kth_native as nat + + +LANGUAGE_FACTORIES = [ + nat.wallet_language_en, + nat.wallet_language_es, + nat.wallet_language_ja, + nat.wallet_language_it, + nat.wallet_language_fr, + nat.wallet_language_cs, + nat.wallet_language_ru, + nat.wallet_language_uk, + nat.wallet_language_zh_Hans, + nat.wallet_language_zh_Hant, +] + + +@pytest.mark.parametrize("factory", LANGUAGE_FACTORIES) +def test_language_factory_returns_handle(factory): + handle = factory() + assert handle is not None + + +def test_all_returns_a_list_handle(): + lst = nat.wallet_language_all() + assert lst is not None diff --git a/tests/test_wallet_message.py b/tests/test_wallet_message.py new file mode 100644 index 0000000..989cf6c --- /dev/null +++ b/tests/test_wallet_message.py @@ -0,0 +1,34 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the wallet_message namespace-module binding (BIP137).""" + +import pytest + +import kth_native as nat + + +def test_hash_message_produces_32_bytes(): + h = nat.wallet_message_hash_message(b"hello world") + assert isinstance(h, bytes) + assert len(h) == 32 + + +def test_hash_message_is_deterministic(): + a = nat.wallet_message_hash_message(b"the same input") + b = nat.wallet_message_hash_message(b"the same input") + assert a == b + + +def test_hash_message_distinguishes_inputs(): + a = nat.wallet_message_hash_message(b"x") + b = nat.wallet_message_hash_message(b"y") + assert a != b + + +# `recovery_id_to_magic` / `magic_to_recovery_id` are bindable but +# their out-pointer params are mis-modelled by the Python backend +# today (declared as scalar inputs rather than out-params); revisit +# once the generator gains an out-pointer scalar shape for the +# Python target. diff --git a/tests/test_wallet_mnemonic.py b/tests/test_wallet_mnemonic.py new file mode 100644 index 0000000..35bf698 --- /dev/null +++ b/tests/test_wallet_mnemonic.py @@ -0,0 +1,33 @@ +# Copyright (c) 2016-present Knuth Project developers. +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +"""Tests for the wallet_mnemonic namespace-module binding (BIP39).""" + +import pytest + +import kth_native as nat + + +# BIP39 spec vector: entropy "00000000000000000000000000000000" +# → "abandon abandon ... abandon about" (12 words). +ENTROPY_16 = bytes(16) # all zeros +EXPECTED_12 = ("abandon " * 11 + "about").strip() + + +def test_create_mnemonic_with_english_wordlist(): + lexicon = nat.wallet_language_en() + words = nat.wallet_mnemonic_create_mnemonic(ENTROPY_16, lexicon) + assert words == EXPECTED_12 + + +def test_validate_known_good_mnemonic_against_dictionary(): + lexicon = nat.wallet_language_en() + assert nat.wallet_mnemonic_validate_mnemonic_dictionary( + EXPECTED_12, lexicon) is True + + +def test_validate_garbage_mnemonic_returns_false(): + lexicon = nat.wallet_language_en() + assert nat.wallet_mnemonic_validate_mnemonic_dictionary( + "not really a mnemonic phrase here", lexicon) is False