From 87f4b862599363e0fe206e56310b6b4b7462a333 Mon Sep 17 00:00:00 2001 From: jbride Date: Tue, 3 Feb 2026 15:40:30 -0700 Subject: [PATCH 1/4] Squashed 'src/libbitcoinpqc/' changes from c609824e87..5da0891af9 5da0891af9 user defined entropy refactoring. No longer need: e347d86bd4 re-add cryptoquick's custom randombytes functions 6468cefd75 Merge commit '462760465fde67d16942407f4420ed51a004ed45' as 'dilithium' 462760465f Squashed 'dilithium/' content from commit 6e00625 e1cc3d4780 Merge commit '02965de0d27b1d074d6fb90870c3fba1f9267b90' as 'sphincsplus' 02965de0d2 Squashed 'sphincsplus/' content from commit 7ec789a 1795caf5d3 remove dilitihium/ and sphincsplus/ copies 09cdb3e242 Merge pull request #23 from jbride/nodejs fd11cd95ab removed reference to Falcon in npm packages git-subtree-dir: src/libbitcoinpqc git-subtree-split: 5da0891af9eb7e42942843213a6988e8e83c55c0 --- CMakeLists.txt | 3 +- dilithium/LICENSE | 2 +- dilithium/ref/config.h | 6 +- dilithium/ref/randombytes_custom.c | 12 -- docs/user_provided_entropy.md | 231 +++++++++++++++++++++ examples/entropy_demo.c | 155 ++++++++++++++ nodejs/.gitignore | 2 + nodejs/README.md | 18 +- nodejs/binding.gyp | 85 +++----- nodejs/examples/basic-usage.ts | 52 ++--- nodejs/package-lock.json | 8 +- nodejs/package.json | 28 ++- nodejs/scripts/sync-c-sources.sh | 41 ++++ nodejs/src/__tests__/bitcoinpqc.test.ts | 67 +++--- nodejs/src/library.ts | 1 - nodejs/src/native/mock_bitcoinpqc_addon.cc | 180 ++++++++-------- nodejs/src/types.ts | 6 +- nodejs/tests/bitcoinpqc.test.ts | 67 +++--- nodejs/tsconfig.json | 41 ++-- sphincsplus/ref/api.h | 2 +- sphincsplus/ref/randombytes_custom.c | 12 -- sphincsplus/ref/test/cycles.h | 7 + sphincsplus/shake-a64/test/cycles.h | 1 + src/ml_dsa/utils.c | 69 +----- src/randombytes_custom.c | 81 ++++++++ src/randombytes_custom.h | 18 ++ src/slh_dsa/utils.c | 68 +----- 27 files changed, 817 insertions(+), 446 deletions(-) delete mode 100644 dilithium/ref/randombytes_custom.c create mode 100644 docs/user_provided_entropy.md create mode 100644 examples/entropy_demo.c create mode 100755 nodejs/scripts/sync-c-sources.sh delete mode 100644 sphincsplus/ref/randombytes_custom.c create mode 100644 sphincsplus/ref/test/cycles.h create mode 120000 sphincsplus/shake-a64/test/cycles.h create mode 100644 src/randombytes_custom.c create mode 100644 src/randombytes_custom.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3efcb439988b..07ffa297388e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,8 +24,7 @@ include_directories( # Custom randombytes implementation set(CUSTOM_RANDOMBYTES - dilithium/ref/randombytes_custom.c - sphincsplus/ref/randombytes_custom.c + src/randombytes_custom.c ) # ML-DSA-44 (Dilithium) source files diff --git a/dilithium/LICENSE b/dilithium/LICENSE index cddfe615c635..c08637961ede 100644 --- a/dilithium/LICENSE +++ b/dilithium/LICENSE @@ -1,5 +1,5 @@ Public Domain (https://creativecommons.org/share-your-work/public-domain/cc0/); -or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html). +or Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0.html) or GPL 2.0 License (http://www.gnu.org/licenses/gpl-2.0.html). For Keccak and the random number generator we are using public-domain code from sources diff --git a/dilithium/ref/config.h b/dilithium/ref/config.h index 8469015971bb..98b8ccb11d8d 100644 --- a/dilithium/ref/config.h +++ b/dilithium/ref/config.h @@ -11,15 +11,15 @@ #endif #if DILITHIUM_MODE == 2 -#define CRYPTO_ALGNAME_DILITHIUM "Dilithium2" +#define CRYPTO_ALGNAME "Dilithium2" #define DILITHIUM_NAMESPACETOP pqcrystals_dilithium2_ref #define DILITHIUM_NAMESPACE(s) pqcrystals_dilithium2_ref_##s #elif DILITHIUM_MODE == 3 -#define CRYPTO_ALGNAME_DILITHIUM "Dilithium3" +#define CRYPTO_ALGNAME "Dilithium3" #define DILITHIUM_NAMESPACETOP pqcrystals_dilithium3_ref #define DILITHIUM_NAMESPACE(s) pqcrystals_dilithium3_ref_##s #elif DILITHIUM_MODE == 5 -#define CRYPTO_ALGNAME_DILITHIUM "Dilithium5" +#define CRYPTO_ALGNAME "Dilithium5" #define DILITHIUM_NAMESPACETOP pqcrystals_dilithium5_ref #define DILITHIUM_NAMESPACE(s) pqcrystals_dilithium5_ref_##s #endif diff --git a/dilithium/ref/randombytes_custom.c b/dilithium/ref/randombytes_custom.c deleted file mode 100644 index 2e661fc2536e..000000000000 --- a/dilithium/ref/randombytes_custom.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include -#include -#include "randombytes.h" - -/* Forward declaration of our custom implementation from utils.c */ -extern void custom_randombytes_impl(uint8_t *out, size_t outlen); - -/* This function is the original randombytes implementation but calls our custom implementation */ -void randombytes(uint8_t *out, size_t outlen) { - custom_randombytes_impl(out, outlen); -} diff --git a/docs/user_provided_entropy.md b/docs/user_provided_entropy.md new file mode 100644 index 000000000000..bb76c4c5e122 --- /dev/null +++ b/docs/user_provided_entropy.md @@ -0,0 +1,231 @@ +# User-Provided Entropy + +libbitcoinpqc does not generate its own randomness. Instead, the caller is +responsible for supplying entropy to key generation functions. This document +explains why, what the library does with the entropy you provide, and how to +choose a suitable source. + +## Why "Bring Your Own Randomness"? + +Cryptographic key generation requires high-quality random data. Different +deployment environments have different trust models for where that randomness +should come from: + +- A Bitcoin node may already maintain its own CSPRNG seeded from multiple + hardware and OS sources. +- A regulated environment may require randomness from a FIPS 140-2/3 certified + HSM. +- An air-gapped signing device may use a dedicated hardware TRNG. +- A test harness may need deterministic keys from a fixed seed. + +By accepting entropy as a parameter rather than sourcing it internally, the +library avoids making assumptions about the caller's security requirements. + +## How the Library Consumes Entropy + +### ML-DSA-44 (CRYSTALS-Dilithium) + +`ml_dsa_44_keygen()` passes your entropy buffer to the internal Dilithium +reference implementation, which calls `randombytes(seedbuf, 32)` during key +generation. This means **32 bytes** of your provided data are consumed to +seed the key generation process. The seed is then expanded +deterministically by Dilithium's internal key derivation. + +### SLH-DSA-SHAKE-128s (SPHINCS+) + +`slh_dsa_shake_128s_keygen()` passes your entropy buffer directly to +`crypto_sign_seed_keypair()`, which uses the first `3 * SPX_N` bytes as the +seed. For SHAKE-128s, `SPX_N = 16`, so **48 bytes** are consumed. + +### The 128-Byte Minimum + +Both keygen functions reject buffers smaller than 128 bytes. This minimum +provides a comfortable margin above the actual consumption (32 or 48 bytes) +and ensures callers provide a meaningful amount of entropy rather than a +handful of bytes that might be poorly generated. + +### Determinism + +Providing identical entropy produces identical keys. This is by design: + +- It enables reproducible test vectors. +- It means the security of your keys depends entirely on the quality and + secrecy of the entropy you provide. + +### Entropy Cycling + +If the library's internal `randombytes()` requests exceed the size of your +buffer, the implementation wraps around to the beginning and reuses data. +With the 128-byte minimum and actual consumption of 32-48 bytes, this does +not occur during normal key generation. However, callers should be aware of +this behavior if using the lower-level APIs directly. + +## Choosing an Entropy Source + +### Requirements + +Your entropy source must be: + +1. **Unpredictable** - an attacker must not be able to guess or influence the + output. +2. **Sufficient entropy density** - the bytes you provide should contain close + to 8 bits of entropy per byte (i.e., indistinguishable from uniform random). +3. **Secret** - the entropy must not be logged, transmitted, or otherwise + exposed. + +### Suitable Sources + +**Operating system CSPRNG** - The simplest and most common choice. On Linux, +`/dev/urandom` or the `getrandom(2)` syscall provides kernel-mixed entropy +that is suitable for cryptographic use after the system has initialized. + +**Hardware Security Modules (HSMs)** - Devices such as Thales Luna, Utimaco +CryptoServer, or cloud-managed HSMs (AWS CloudHSM, Azure Dedicated HSM) +provide FIPS-certified hardware random number generation. Use these when +regulatory compliance requires a certified entropy source. + +**CPU hardware RNG** - Modern x86 processors expose the `RDRAND` and `RDSEED` +instructions, which draw from an on-die entropy source. ARM v8.5+ provides +the equivalent `RNDR` instruction. These can be used directly or as an +additional seed input to a CSPRNG. + +**Trusted Platform Modules (TPMs)** - TPM 2.0 chips, present in most +enterprise hardware, expose a hardware RNG accessible via `tpm2-tools` or +OS interfaces. Suitable as a supplementary entropy source. + +**Dedicated TRNGs / QRNGs** - Devices such as Quantis (ID Quantique) or +ComScire provide high-throughput true random number generation. Quantum RNGs +base their entropy on physical quantum processes. + +### Sources to Avoid + +- `rand()`, `random()`, or any userspace PRNG seeded from `time()` or PIDs. +- `/dev/random` when blocking behavior is undesirable (on modern Linux + kernels, `/dev/urandom` is equally suitable after initialization). +- Entropy gathered solely from low-resolution timers or predictable system + state. +- Network-based randomness beacons (e.g., NIST Beacon, drand) for secret key + material - these are public and unsuitable for keying. + +## Trying It Out on Linux + +This walkthrough builds the library from source, acquires entropy from the +command line, and pipes it into the included `examples/entropy_demo.c` +program. The demo reads exactly 128 bytes of entropy from **stdin**, then +generates ML-DSA-44 and SLH-DSA-SHAKE-128s key pairs, signs a message with +each, and verifies the signatures. + +### Prerequisites + +```bash +# Debian/Ubuntu +sudo apt-get install build-essential cmake + +# Fedora +sudo dnf install gcc gcc-c++ cmake make +``` + +### Step 1: Build the Library + +```bash +git clone https://github.com/bitcoin/libbitcoinpqc.git +cd libbitcoinpqc + +mkdir build && cd build +cmake .. +make +``` + +This produces `build/lib/libbitcoinpqc.a`. + +### Step 2: Compile the Demo + +```bash +cd .. +gcc -o /tmp/entropy_demo examples/entropy_demo.c \ + -Iinclude \ + -Lbuild/lib -lbitcoinpqc \ + -lm +``` + +### Step 3: Acquire Entropy and Run + +The demo expects exactly 128 bytes of raw entropy on stdin. There are +several ways to provide it from the command line. + +**Option A: `/dev/urandom` (simplest)** + +Read 128 bytes from the kernel CSPRNG and pipe them in: + +```bash +dd if=/dev/urandom bs=128 count=1 2>/dev/null | /tmp/entropy_demo +``` + +**Option B: OpenSSL** + +Use `openssl rand` to generate 128 cryptographically secure bytes: + +```bash +openssl rand 128 | /tmp/entropy_demo +``` + +**Option C: `getrandom(2)` via Python one-liner** + +Calls the `getrandom` syscall under the hood: + +```bash +python3 -c "import os,sys; sys.stdout.buffer.write(os.urandom(128))" | /tmp/entropy_demo +``` + +**Option D: Hardware RNG (`/dev/hwrng`)** + +If the system has a hardware TRNG exposed by the kernel (e.g., Intel +RDRAND via `rng-tools`, a TPM, or a USB TRNG): + +```bash +sudo dd if=/dev/hwrng bs=128 count=1 2>/dev/null | /tmp/entropy_demo +``` + +> Note: `/dev/hwrng` requires root or membership in the appropriate group. +> Not all systems expose this device by default; you may need to load the +> `rng-core` module or install `rng-tools`. + +Expected output (hex values will differ each run): + +``` +Entropy (first 16 bytes): 7a3f1c... + +ML-DSA-44 key pair generated successfully. + Public key size: 1312 bytes + Secret key size: 2560 bytes + Public key (first 16 bytes): 9b2e4d... + +Signature size: 2420 bytes +Verification: PASS + +SLH-DSA-SHAKE-128s key pair generated successfully. + Public key size: 32 bytes + Secret key size: 64 bytes + Public key (first 16 bytes): c4a81f... + +Signature size: 7856 bytes +Verification: PASS +``` + +### Step 4: Verify Determinism + +Save entropy to a file and feed it to the demo twice. The public key +bytes will be identical both times: + +```bash +dd if=/dev/urandom of=/tmp/saved_entropy.bin bs=128 count=1 2>/dev/null + +/tmp/entropy_demo < /tmp/saved_entropy.bin +/tmp/entropy_demo < /tmp/saved_entropy.bin +``` + +### Cleanup + +```bash +rm -f /tmp/entropy_demo saved_entropy.bin +``` diff --git a/examples/entropy_demo.c b/examples/entropy_demo.c new file mode 100644 index 000000000000..7f2b653565bb --- /dev/null +++ b/examples/entropy_demo.c @@ -0,0 +1,155 @@ +/* + * entropy_demo.c - Demonstrates user-provided entropy with libbitcoinpqc. + * + * Reads exactly 128 bytes of entropy from stdin, then uses it to generate + * ML-DSA-44 and SLH-DSA-SHAKE-128s key pairs, sign a message, and verify + * the signatures. + * + * Usage: + * dd if=/dev/urandom bs=128 count=1 2>/dev/null | ./entropy_demo + * ./entropy_demo < saved_entropy.bin + */ + +#include +#include +#include +#include + +#define ENTROPY_SIZE 128 + +int main(void) { + uint8_t entropy[ENTROPY_SIZE]; + size_t total = 0; + + /* Read exactly ENTROPY_SIZE bytes from stdin */ + while (total < ENTROPY_SIZE) { + size_t n = fread(entropy + total, 1, ENTROPY_SIZE - total, stdin); + if (n == 0) { + fprintf(stderr, + "Error: need %d bytes of entropy on stdin, got %zu\n", + ENTROPY_SIZE, total); + return 1; + } + total += n; + } + + /* Show a hex preview of the entropy received */ + printf("Entropy (first 16 bytes): "); + for (int i = 0; i < 16; i++) { + printf("%02x", entropy[i]); + } + printf("...\n\n"); + + /* Generate an ML-DSA-44 key pair */ + bitcoin_pqc_keypair_t keypair; + bitcoin_pqc_error_t err = bitcoin_pqc_keygen( + BITCOIN_PQC_ML_DSA_44, &keypair, entropy, ENTROPY_SIZE + ); + + if (err != BITCOIN_PQC_OK) { + fprintf(stderr, "Key generation failed: %d\n", err); + return 1; + } + + printf("ML-DSA-44 key pair generated successfully.\n"); + printf(" Public key size: %zu bytes\n", keypair.public_key_size); + printf(" Secret key size: %zu bytes\n", keypair.secret_key_size); + + const uint8_t *pk = (const uint8_t *)keypair.public_key; + printf(" Public key (first 16 bytes): "); + for (int i = 0; i < 16; i++) { + printf("%02x", pk[i]); + } + printf("...\n\n"); + + /* Sign a message */ + const char *msg_text = "Hello, post-quantum world!"; + const uint8_t *message = (const uint8_t *)msg_text; + size_t message_len = strlen(msg_text); + + bitcoin_pqc_signature_t sig; + err = bitcoin_pqc_sign( + BITCOIN_PQC_ML_DSA_44, + keypair.secret_key, keypair.secret_key_size, + message, message_len, + &sig + ); + + if (err != BITCOIN_PQC_OK) { + fprintf(stderr, "Signing failed: %d\n", err); + bitcoin_pqc_keypair_free(&keypair); + return 1; + } + + printf("Signature size: %zu bytes\n", sig.signature_size); + + /* Verify the signature */ + err = bitcoin_pqc_verify( + BITCOIN_PQC_ML_DSA_44, + keypair.public_key, keypair.public_key_size, + message, message_len, + sig.signature, sig.signature_size + ); + + printf("Verification: %s\n\n", err == BITCOIN_PQC_OK ? "PASS" : "FAIL"); + + bitcoin_pqc_signature_free(&sig); + bitcoin_pqc_keypair_free(&keypair); + + if (err != BITCOIN_PQC_OK) + return 1; + + /* Generate an SLH-DSA-SHAKE-128s key pair using the same entropy */ + bitcoin_pqc_keypair_t slh_keypair; + err = bitcoin_pqc_keygen( + BITCOIN_PQC_SLH_DSA_SHAKE_128S, &slh_keypair, entropy, ENTROPY_SIZE + ); + + if (err != BITCOIN_PQC_OK) { + fprintf(stderr, "SLH-DSA key generation failed: %d\n", err); + return 1; + } + + printf("SLH-DSA-SHAKE-128s key pair generated successfully.\n"); + printf(" Public key size: %zu bytes\n", slh_keypair.public_key_size); + printf(" Secret key size: %zu bytes\n", slh_keypair.secret_key_size); + + const uint8_t *slh_pk = (const uint8_t *)slh_keypair.public_key; + printf(" Public key (first 16 bytes): "); + for (int i = 0; i < 16; i++) { + printf("%02x", slh_pk[i]); + } + printf("...\n\n"); + + /* Sign with SLH-DSA */ + bitcoin_pqc_signature_t slh_sig; + err = bitcoin_pqc_sign( + BITCOIN_PQC_SLH_DSA_SHAKE_128S, + slh_keypair.secret_key, slh_keypair.secret_key_size, + message, message_len, + &slh_sig + ); + + if (err != BITCOIN_PQC_OK) { + fprintf(stderr, "SLH-DSA signing failed: %d\n", err); + bitcoin_pqc_keypair_free(&slh_keypair); + return 1; + } + + printf("Signature size: %zu bytes\n", slh_sig.signature_size); + + /* Verify the SLH-DSA signature */ + err = bitcoin_pqc_verify( + BITCOIN_PQC_SLH_DSA_SHAKE_128S, + slh_keypair.public_key, slh_keypair.public_key_size, + message, message_len, + slh_sig.signature, slh_sig.signature_size + ); + + printf("Verification: %s\n", err == BITCOIN_PQC_OK ? "PASS" : "FAIL"); + + bitcoin_pqc_signature_free(&slh_sig); + bitcoin_pqc_keypair_free(&slh_keypair); + + return (err != BITCOIN_PQC_OK); +} diff --git a/nodejs/.gitignore b/nodejs/.gitignore index ada280acd068..73db82f6b9fa 100644 --- a/nodejs/.gitignore +++ b/nodejs/.gitignore @@ -21,3 +21,5 @@ coverage/ .vscode/ *.swp *.swo + +c_sources diff --git a/nodejs/README.md b/nodejs/README.md index ab5d2ea84816..9cec3fc79dab 100644 --- a/nodejs/README.md +++ b/nodejs/README.md @@ -7,10 +7,9 @@ TypeScript bindings for the [libbitcoinpqc](https://github.com/bitcoin/libbitcoi - Full TypeScript support with typings - Clean, ergonomic API - Compatible with NodeJS 16+ -- Works with all three PQC algorithms: +- Works with both PQC algorithms: - ML-DSA-44 (formerly CRYSTALS-Dilithium) - SLH-DSA-Shake-128s (formerly SPHINCS+) - - FN-DSA-512 (formerly FALCON) ## Installation @@ -58,12 +57,10 @@ verify(keypair.publicKey, message, signature.bytes); enum Algorithm { /** BIP-340 Schnorr + X-Only - Elliptic Curve Digital Signature Algorithm */ SECP256K1_SCHNORR = 0, - /** FN-DSA-512 (FALCON) - Fast Fourier lattice-based signature scheme */ - FN_DSA_512 = 1, /** ML-DSA-44 (CRYSTALS-Dilithium) - Lattice-based signature scheme */ - ML_DSA_44 = 2, + ML_DSA_44 = 1, /** SLH-DSA-Shake-128s (SPHINCS+) - Hash-based signature scheme */ - SLH_DSA_SHAKE_128S = 3 + SLH_DSA_SHAKE_128S = 2 } ``` @@ -150,11 +147,10 @@ Verify a signature using the specified public key. Throws a `PqcError` if verifi ## Algorithm Characteristics -| Algorithm | Public Key Size | Secret Key Size | Signature Size | Security Level | -|-----------|----------------|----------------|----------------|----------------| -| ML-DSA-44 | 1,312 bytes | 2,528 bytes | 2,420 bytes | NIST Level 2 | -| SLH-DSA-Shake-128s | 32 bytes | 64 bytes | 7,856 bytes | NIST Level 1 | -| FN-DSA-512 | 897 bytes | 1,281 bytes | ~666 bytes (average) | NIST Level 1 | +| Algorithm | Public Key Size | Secret Key Size | Signature Size | Security Level | +| ------------------ | --------------- | --------------- | -------------- | -------------- | +| ML-DSA-44 | 1,312 bytes | 2,528 bytes | 2,420 bytes | NIST Level 2 | +| SLH-DSA-Shake-128s | 32 bytes | 64 bytes | 7,856 bytes | NIST Level 1 | ## Security Notes diff --git a/nodejs/binding.gyp b/nodejs/binding.gyp index 0a9a462b0b82..e9d385e63603 100644 --- a/nodejs/binding.gyp +++ b/nodejs/binding.gyp @@ -4,57 +4,42 @@ "target_name": "bitcoinpqc", "sources": [ "src/native/bitcoinpqc_addon.cc", - "../src/bitcoinpqc.c", - "../src/ml_dsa/keygen.c", - "../src/ml_dsa/sign.c", - "../src/ml_dsa/verify.c", - "../src/ml_dsa/utils.c", - "../src/slh_dsa/keygen.c", - "../src/slh_dsa/sign.c", - "../src/slh_dsa/verify.c", - "../src/slh_dsa/utils.c", - "../src/fn_dsa/keygen.c", - "../src/fn_dsa/sign.c", - "../src/fn_dsa/verify.c", - "../src/fn_dsa/utils.c", - "../dilithium/ref/sign.c", - "../dilithium/ref/packing.c", - "../dilithium/ref/polyvec.c", - "../dilithium/ref/poly.c", - "../dilithium/ref/ntt.c", - "../dilithium/ref/reduce.c", - "../dilithium/ref/rounding.c", - "../dilithium/ref/fips202.c", - "../dilithium/ref/symmetric-shake.c", - "../dilithium/ref/randombytes_custom.c", - "../sphincsplus/ref/address.c", - "../sphincsplus/ref/fors.c", - "../sphincsplus/ref/hash_shake.c", - "../sphincsplus/ref/merkle.c", - "../sphincsplus/ref/sign.c", - "../sphincsplus/ref/thash_shake_simple.c", - "../sphincsplus/ref/utils.c", - "../sphincsplus/ref/utilsx1.c", - "../sphincsplus/ref/wots.c", - "../sphincsplus/ref/wotsx1.c", - "../sphincsplus/ref/fips202.c", - "../falcon/codec.c", - "../falcon/common.c", - "../falcon/falcon.c", - "../falcon/fft.c", - "../falcon/fpr.c", - "../falcon/keygen.c", - "../falcon/shake.c", - "../falcon/sign.c", - "../falcon/vrfy.c", - "../falcon/rng.c" + "src/c_sources/bitcoinpqc.c", + "src/c_sources/ml_dsa/keygen.c", + "src/c_sources/ml_dsa/sign.c", + "src/c_sources/ml_dsa/verify.c", + "src/c_sources/ml_dsa/utils.c", + "src/c_sources/slh_dsa/keygen.c", + "src/c_sources/slh_dsa/sign.c", + "src/c_sources/slh_dsa/verify.c", + "src/c_sources/slh_dsa/utils.c", + "src/c_sources/dilithium_ref/sign.c", + "src/c_sources/dilithium_ref/packing.c", + "src/c_sources/dilithium_ref/polyvec.c", + "src/c_sources/dilithium_ref/poly.c", + "src/c_sources/dilithium_ref/ntt.c", + "src/c_sources/dilithium_ref/reduce.c", + "src/c_sources/dilithium_ref/rounding.c", + "src/c_sources/dilithium_ref/fips202.c", + "src/c_sources/dilithium_ref/symmetric-shake.c", + "src/c_sources/randombytes_custom.c", + "src/c_sources/sphincsplus_ref/address.c", + "src/c_sources/sphincsplus_ref/fors.c", + "src/c_sources/sphincsplus_ref/hash_shake.c", + "src/c_sources/sphincsplus_ref/merkle.c", + "src/c_sources/sphincsplus_ref/sign.c", + "src/c_sources/sphincsplus_ref/thash_shake_simple.c", + "src/c_sources/sphincsplus_ref/utils.c", + "src/c_sources/sphincsplus_ref/utilsx1.c", + "src/c_sources/sphincsplus_ref/wots.c", + "src/c_sources/sphincsplus_ref/wotsx1.c", + "src/c_sources/sphincsplus_ref/fips202.c" ], "include_dirs": [ "", "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/bitcoin/libbitcoinpqc.git", + "directory": "nodejs" + }, + "bugs": { + "url": "https://github.com/bitcoin/libbitcoinpqc/issues" + }, + "homepage": "https://github.com/bitcoin/libbitcoinpqc#readme", "type": "commonjs", "devDependencies": { "@types/jest": "^29.5.12", @@ -40,7 +49,12 @@ "dist", "README.md", "binding.gyp", - "src/native" + "tsconfig.json", + "src/native", + "src/c_sources" ], - "gypfile": true + "gypfile": true, + "publishConfig": { + "access": "public" + } } diff --git a/nodejs/scripts/sync-c-sources.sh b/nodejs/scripts/sync-c-sources.sh new file mode 100755 index 000000000000..c1b673dbe6df --- /dev/null +++ b/nodejs/scripts/sync-c-sources.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Script to sync C source files from parent directory to src/c_sources +# This should be run before building or publishing the package + +set -e + +echo "Syncing C source files..." + +# Remove existing c_sources directory +rm -rf src/c_sources + +# Create new c_sources directory +mkdir -p src/c_sources + +# Copy C source files +echo "Copying main C source file..." +cp ../src/bitcoinpqc.c src/c_sources/ + +echo "Copying ML-DSA source files..." +cp -r ../src/ml_dsa src/c_sources/ + +echo "Copying SLH-DSA source files..." +cp -r ../src/slh_dsa src/c_sources/ + +echo "Copying Dilithium reference implementation..." +cp -r ../dilithium/ref src/c_sources/dilithium_ref + +echo "Copying SPHINCS+ reference implementation..." +cp -r ../sphincsplus/ref src/c_sources/sphincsplus_ref + +echo "Copying include files..." +cp -r ../include src/c_sources/ + +# Update include paths in C source files +echo "Updating include paths..." +find src/c_sources -name "*.c" -exec sed -i 's|../../dilithium/ref/|../dilithium_ref/|g' {} \; +find src/c_sources -name "*.c" -exec sed -i 's|../../sphincsplus/ref/|../sphincsplus_ref/|g' {} \; +find src/c_sources -name "*.c" -exec sed -i 's|../../include/|../include/|g' {} \; + +echo "C source files synced successfully!" \ No newline at end of file diff --git a/nodejs/src/__tests__/bitcoinpqc.test.ts b/nodejs/src/__tests__/bitcoinpqc.test.ts index ed7209125314..54f7c7c3f5f0 100644 --- a/nodejs/src/__tests__/bitcoinpqc.test.ts +++ b/nodejs/src/__tests__/bitcoinpqc.test.ts @@ -27,7 +27,6 @@ describe("Bitcoin PQC", () => { // Test key size reporting functions for (const algo of [ Algorithm.SECP256K1_SCHNORR, - Algorithm.FN_DSA_512, Algorithm.ML_DSA_44, Algorithm.SLH_DSA_SHAKE_128S, ]) { @@ -106,47 +105,45 @@ describe("Bitcoin PQC", () => { }); }); - describe("FN-DSA-512 (FALCON)", () => { - const algorithm = Algorithm.FN_DSA_512; - test("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); + test("should generate keypair, sign and verify", () => { + // Generate random data for key generation + const randomData = getRandomBytes(128); - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); + // Generate a keypair + const keypair = generateKeyPair(algorithm, randomData); - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); + // Verify key sizes match reported sizes + expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); + expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); + // Test message signing + const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); + const signature = sign(keypair.secretKey, message); - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); + // Verify signature size matches reported size + expect(signature.bytes.length).toBe(signatureSize(algorithm)); - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - }); + // Verify the signature - should not throw + expect(() => { + verify(keypair.publicKey, message, signature); + }).not.toThrow(); }); +}); - describe("error conditions", () => { - test("should throw on invalid input", () => { - // Invalid algorithm - expect(() => { - const randomData = getRandomBytes(128); - generateKeyPair(99 as Algorithm, randomData); - }).toThrow(PqcError); - - // Invalid random data size - expect(() => { - const randomData = getRandomBytes(16); // Less than 128 bytes - generateKeyPair(Algorithm.ML_DSA_44, randomData); - }).toThrow(PqcError); - }); +describe("error conditions", () => { + test("should throw on invalid input", () => { + // Invalid algorithm + expect(() => { + const randomData = getRandomBytes(128); + generateKeyPair(99 as Algorithm, randomData); + }).toThrow(PqcError); + + // Invalid random data size + expect(() => { + const randomData = getRandomBytes(16); // Less than 128 bytes + generateKeyPair(Algorithm.ML_DSA_44, randomData); + }).toThrow(PqcError); }); }); +}); diff --git a/nodejs/src/library.ts b/nodejs/src/library.ts index eaffabe4cc24..4b755174599e 100644 --- a/nodejs/src/library.ts +++ b/nodejs/src/library.ts @@ -53,7 +53,6 @@ class MockBitcoinPqcNative implements BitcoinPqcNative { secretKey: 32, signature: 64, }, - [Algorithm.FN_DSA_512]: { publicKey: 897, secretKey: 1281, signature: 666 }, // Average size [Algorithm.ML_DSA_44]: { publicKey: 1312, secretKey: 2528, diff --git a/nodejs/src/native/mock_bitcoinpqc_addon.cc b/nodejs/src/native/mock_bitcoinpqc_addon.cc index 299ca44aec70..9332cc8b517b 100644 --- a/nodejs/src/native/mock_bitcoinpqc_addon.cc +++ b/nodejs/src/native/mock_bitcoinpqc_addon.cc @@ -1,15 +1,11 @@ -#include #include +#include // Mock key sizes const int SECP256K1_PK_SIZE = 32; const int SECP256K1_SK_SIZE = 32; const int SECP256K1_SIG_SIZE = 64; -const int FN_DSA_512_PK_SIZE = 897; -const int FN_DSA_512_SK_SIZE = 1281; -const int FN_DSA_512_SIG_SIZE = 666; - const int ML_DSA_44_PK_SIZE = 1312; const int ML_DSA_44_SK_SIZE = 2528; const int ML_DSA_44_SIG_SIZE = 2420; @@ -25,7 +21,7 @@ const int BAD_KEY = -2; const int BAD_SIGNATURE = -3; const int NOT_IMPLEMENTED = -4; -Napi::Value GetPublicKeySize(const Napi::CallbackInfo& info) { +Napi::Value GetPublicKeySize(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); if (info.Length() < 1 || !info[0].IsNumber()) { @@ -37,17 +33,23 @@ Napi::Value GetPublicKeySize(const Napi::CallbackInfo& info) { int size = 0; switch (algorithm) { - case 0: size = SECP256K1_PK_SIZE; break; - case 1: size = FN_DSA_512_PK_SIZE; break; - case 2: size = ML_DSA_44_PK_SIZE; break; - case 3: size = SLH_DSA_SHAKE_128S_PK_SIZE; break; - default: size = 0; + case 0: + size = SECP256K1_PK_SIZE; + break; + case 1: + size = ML_DSA_44_PK_SIZE; + break; + case 2: + size = SLH_DSA_SHAKE_128S_PK_SIZE; + break; + default: + size = 0; } return Napi::Number::New(env, size); } -Napi::Value GetSecretKeySize(const Napi::CallbackInfo& info) { +Napi::Value GetSecretKeySize(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); if (info.Length() < 1 || !info[0].IsNumber()) { @@ -59,17 +61,23 @@ Napi::Value GetSecretKeySize(const Napi::CallbackInfo& info) { int size = 0; switch (algorithm) { - case 0: size = SECP256K1_SK_SIZE; break; - case 1: size = FN_DSA_512_SK_SIZE; break; - case 2: size = ML_DSA_44_SK_SIZE; break; - case 3: size = SLH_DSA_SHAKE_128S_SK_SIZE; break; - default: size = 0; + case 0: + size = SECP256K1_SK_SIZE; + break; + case 1: + size = ML_DSA_44_SK_SIZE; + break; + case 2: + size = SLH_DSA_SHAKE_128S_SK_SIZE; + break; + default: + size = 0; } return Napi::Number::New(env, size); } -Napi::Value GetSignatureSize(const Napi::CallbackInfo& info) { +Napi::Value GetSignatureSize(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); if (info.Length() < 1 || !info[0].IsNumber()) { @@ -81,17 +89,23 @@ Napi::Value GetSignatureSize(const Napi::CallbackInfo& info) { int size = 0; switch (algorithm) { - case 0: size = SECP256K1_SIG_SIZE; break; - case 1: size = FN_DSA_512_SIG_SIZE; break; - case 2: size = ML_DSA_44_SIG_SIZE; break; - case 3: size = SLH_DSA_SHAKE_128S_SIG_SIZE; break; - default: size = 0; + case 0: + size = SECP256K1_SIG_SIZE; + break; + case 1: + size = ML_DSA_44_SIG_SIZE; + break; + case 2: + size = SLH_DSA_SHAKE_128S_SIG_SIZE; + break; + default: + size = 0; } return Napi::Number::New(env, size); } -Napi::Value GenerateKeypair(const Napi::CallbackInfo& info) { +Napi::Value GenerateKeypair(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsTypedArray()) { @@ -103,7 +117,8 @@ Napi::Value GenerateKeypair(const Napi::CallbackInfo& info) { Napi::Uint8Array randomData = info[1].As(); if (randomData.ByteLength() < 128) { - Napi::Error::New(env, "Random data must be at least 128 bytes").ThrowAsJavaScriptException(); + Napi::Error::New(env, "Random data must be at least 128 bytes") + .ThrowAsJavaScriptException(); return env.Null(); } @@ -117,24 +132,20 @@ Napi::Value GenerateKeypair(const Napi::CallbackInfo& info) { int skSize = 0; switch (algorithm) { - case 0: - pkSize = SECP256K1_PK_SIZE; - skSize = SECP256K1_SK_SIZE; - break; - case 1: - pkSize = FN_DSA_512_PK_SIZE; - skSize = FN_DSA_512_SK_SIZE; - break; - case 2: - pkSize = ML_DSA_44_PK_SIZE; - skSize = ML_DSA_44_SK_SIZE; - break; - case 3: - pkSize = SLH_DSA_SHAKE_128S_PK_SIZE; - skSize = SLH_DSA_SHAKE_128S_SK_SIZE; - break; - default: - return Napi::Number::New(env, BAD_ARGUMENT); + case 0: + pkSize = SECP256K1_PK_SIZE; + skSize = SECP256K1_SK_SIZE; + break; + case 1: + pkSize = ML_DSA_44_PK_SIZE; + skSize = ML_DSA_44_SK_SIZE; + break; + case 2: + pkSize = SLH_DSA_SHAKE_128S_PK_SIZE; + skSize = SLH_DSA_SHAKE_128S_SK_SIZE; + break; + default: + return Napi::Number::New(env, BAD_ARGUMENT); } // Create result object @@ -160,10 +171,11 @@ Napi::Value GenerateKeypair(const Napi::CallbackInfo& info) { return result; } -Napi::Value SignMessage(const Napi::CallbackInfo& info) { +Napi::Value SignMessage(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); - if (info.Length() < 3 || !info[0].IsNumber() || !info[1].IsTypedArray() || !info[2].IsTypedArray()) { + if (info.Length() < 3 || !info[0].IsNumber() || !info[1].IsTypedArray() || + !info[2].IsTypedArray()) { Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); return env.Null(); } @@ -182,24 +194,20 @@ Napi::Value SignMessage(const Napi::CallbackInfo& info) { int expectedSkSize = 0; switch (algorithm) { - case 0: - sigSize = SECP256K1_SIG_SIZE; - expectedSkSize = SECP256K1_SK_SIZE; - break; - case 1: - sigSize = FN_DSA_512_SIG_SIZE; - expectedSkSize = FN_DSA_512_SK_SIZE; - break; - case 2: - sigSize = ML_DSA_44_SIG_SIZE; - expectedSkSize = ML_DSA_44_SK_SIZE; - break; - case 3: - sigSize = SLH_DSA_SHAKE_128S_SIG_SIZE; - expectedSkSize = SLH_DSA_SHAKE_128S_SK_SIZE; - break; - default: - return Napi::Number::New(env, BAD_ARGUMENT); + case 0: + sigSize = SECP256K1_SIG_SIZE; + expectedSkSize = SECP256K1_SK_SIZE; + break; + case 1: + sigSize = ML_DSA_44_SIG_SIZE; + expectedSkSize = ML_DSA_44_SK_SIZE; + break; + case 2: + sigSize = SLH_DSA_SHAKE_128S_SIG_SIZE; + expectedSkSize = SLH_DSA_SHAKE_128S_SK_SIZE; + break; + default: + return Napi::Number::New(env, BAD_ARGUMENT); } // Check key size @@ -216,7 +224,8 @@ Napi::Value SignMessage(const Napi::CallbackInfo& info) { // Create dummy signature Napi::Uint8Array signature = Napi::Uint8Array::New(env, sigSize); - // Use message to fill the signature (in a real implementation this would be a proper signature) + // Use message to fill the signature (in a real implementation this would be a + // proper signature) for (size_t i = 0; i < sigSize; i++) { signature[i] = i < message.ByteLength() ? message[i] : 0; } @@ -227,7 +236,7 @@ Napi::Value SignMessage(const Napi::CallbackInfo& info) { return result; } -Napi::Value VerifySignature(const Napi::CallbackInfo& info) { +Napi::Value VerifySignature(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); if (info.Length() < 4 || !info[0].IsNumber() || !info[1].IsTypedArray() || @@ -250,24 +259,20 @@ Napi::Value VerifySignature(const Napi::CallbackInfo& info) { int expectedSigSize = 0; switch (algorithm) { - case 0: - expectedPkSize = SECP256K1_PK_SIZE; - expectedSigSize = SECP256K1_SIG_SIZE; - break; - case 1: - expectedPkSize = FN_DSA_512_PK_SIZE; - expectedSigSize = FN_DSA_512_SIG_SIZE; - break; - case 2: - expectedPkSize = ML_DSA_44_PK_SIZE; - expectedSigSize = ML_DSA_44_SIG_SIZE; - break; - case 3: - expectedPkSize = SLH_DSA_SHAKE_128S_PK_SIZE; - expectedSigSize = SLH_DSA_SHAKE_128S_SIG_SIZE; - break; - default: - return Napi::Number::New(env, BAD_ARGUMENT); + case 0: + expectedPkSize = SECP256K1_PK_SIZE; + expectedSigSize = SECP256K1_SIG_SIZE; + break; + case 1: + expectedPkSize = ML_DSA_44_PK_SIZE; + expectedSigSize = ML_DSA_44_SIG_SIZE; + break; + case 2: + expectedPkSize = SLH_DSA_SHAKE_128S_PK_SIZE; + expectedSigSize = SLH_DSA_SHAKE_128S_SIG_SIZE; + break; + default: + return Napi::Number::New(env, BAD_ARGUMENT); } // Check key and signature sizes @@ -285,9 +290,12 @@ Napi::Value VerifySignature(const Napi::CallbackInfo& info) { } Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports.Set("bitcoin_pqc_public_key_size", Napi::Function::New(env, GetPublicKeySize)); - exports.Set("bitcoin_pqc_secret_key_size", Napi::Function::New(env, GetSecretKeySize)); - exports.Set("bitcoin_pqc_signature_size", Napi::Function::New(env, GetSignatureSize)); + exports.Set("bitcoin_pqc_public_key_size", + Napi::Function::New(env, GetPublicKeySize)); + exports.Set("bitcoin_pqc_secret_key_size", + Napi::Function::New(env, GetSecretKeySize)); + exports.Set("bitcoin_pqc_signature_size", + Napi::Function::New(env, GetSignatureSize)); exports.Set("bitcoin_pqc_keygen", Napi::Function::New(env, GenerateKeypair)); exports.Set("bitcoin_pqc_sign", Napi::Function::New(env, SignMessage)); exports.Set("bitcoin_pqc_verify", Napi::Function::New(env, VerifySignature)); diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts index 28ea18827ec8..282c4085f7ba 100644 --- a/nodejs/src/types.ts +++ b/nodejs/src/types.ts @@ -4,12 +4,10 @@ export enum Algorithm { /** BIP-340 Schnorr + X-Only - Elliptic Curve Digital Signature Algorithm */ SECP256K1_SCHNORR = 0, - /** FN-DSA-512 (FALCON) - Fast Fourier lattice-based signature scheme */ - FN_DSA_512 = 1, /** ML-DSA-44 (CRYSTALS-Dilithium) - Lattice-based signature scheme */ - ML_DSA_44 = 2, + ML_DSA_44 = 1, /** SLH-DSA-Shake-128s (SPHINCS+) - Hash-based signature scheme */ - SLH_DSA_SHAKE_128S = 3, + SLH_DSA_SHAKE_128S = 2, } /** diff --git a/nodejs/tests/bitcoinpqc.test.ts b/nodejs/tests/bitcoinpqc.test.ts index 5a18799a2751..9930055eb2f2 100644 --- a/nodejs/tests/bitcoinpqc.test.ts +++ b/nodejs/tests/bitcoinpqc.test.ts @@ -31,7 +31,6 @@ describe("Bitcoin PQC", () => { // Test key size reporting functions for (const algo of [ Algorithm.SECP256K1_SCHNORR, - Algorithm.FN_DSA_512, Algorithm.ML_DSA_44, Algorithm.SLH_DSA_SHAKE_128S, ]) { @@ -110,47 +109,45 @@ describe("Bitcoin PQC", () => { }); }); - describe("FN-DSA-512 (FALCON)", () => { - const algorithm = Algorithm.FN_DSA_512; - test("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); + test("should generate keypair, sign and verify", () => { + // Generate random data for key generation + const randomData = getRandomBytes(128); - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); + // Generate a keypair + const keypair = generateKeyPair(algorithm, randomData); - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); + // Verify key sizes match reported sizes + expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); + expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); + // Test message signing + const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); + const signature = sign(keypair.secretKey, message); - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); + // Verify signature size matches reported size + expect(signature.bytes.length).toBe(signatureSize(algorithm)); - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - }); + // Verify the signature - should not throw + expect(() => { + verify(keypair.publicKey, message, signature); + }).not.toThrow(); }); +}); - describe("error conditions", () => { - test("should throw on invalid input", () => { - // Invalid algorithm - expect(() => { - const randomData = getRandomBytes(128); - generateKeyPair(99 as Algorithm, randomData); - }).toThrow(PqcError); - - // Invalid random data size - expect(() => { - const randomData = getRandomBytes(16); // Less than 128 bytes - generateKeyPair(Algorithm.ML_DSA_44, randomData); - }).toThrow(PqcError); - }); +describe("error conditions", () => { + test("should throw on invalid input", () => { + // Invalid algorithm + expect(() => { + const randomData = getRandomBytes(128); + generateKeyPair(99 as Algorithm, randomData); + }).toThrow(PqcError); + + // Invalid random data size + expect(() => { + const randomData = getRandomBytes(16); // Less than 128 bytes + generateKeyPair(Algorithm.ML_DSA_44, randomData); + }).toThrow(PqcError); }); }); +}); diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json index 005fce82ce4a..7c2a08735de7 100644 --- a/nodejs/tsconfig.json +++ b/nodejs/tsconfig.json @@ -1,7 +1,6 @@ { "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ @@ -9,9 +8,8 @@ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ // "jsx": "preserve", /* Specify what JSX code is generated. */ // "libReplacement": true, /* Enable lib replacement. */ @@ -24,10 +22,10 @@ // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ + "module": "commonjs", /* Specify what module code is generated. */ + "rootDir": "./src", /* Specify the root folder within your source files. */ + "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ @@ -45,21 +43,19 @@ // "resolveJsonModule": true, /* Enable importing .json files. */ // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ // "declarationMap": true, /* Create sourcemaps for d.ts files. */ // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist", /* Specify an output folder for all emitted files. */ + "outDir": "./dist", /* Specify an output folder for all emitted files. */ // "removeComments": true, /* Disable emitting comments. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ @@ -73,19 +69,17 @@ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - /* Interop Constraints */ // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ + "strict": true, /* Enable all strict type-checking options. */ // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ @@ -105,11 +99,18 @@ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["src/**/*"], - "exclude": ["node_modules", "**/*.test.ts", "dist"] -} + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "node_modules", + "**/*.test.ts", + "dist", + "src/__tests__/**/*", + "src/c_sources/**/*" + ] +} \ No newline at end of file diff --git a/sphincsplus/ref/api.h b/sphincsplus/ref/api.h index b89bd52b083b..d57a148f7f86 100644 --- a/sphincsplus/ref/api.h +++ b/sphincsplus/ref/api.h @@ -6,7 +6,7 @@ #include "params.h" -#define CRYPTO_ALGNAME_SPHINCS "SPHINCS+" +#define CRYPTO_ALGNAME "SPHINCS+" #define CRYPTO_SECRETKEYBYTES SPX_SK_BYTES #define CRYPTO_PUBLICKEYBYTES SPX_PK_BYTES diff --git a/sphincsplus/ref/randombytes_custom.c b/sphincsplus/ref/randombytes_custom.c deleted file mode 100644 index 9c05aa355f71..000000000000 --- a/sphincsplus/ref/randombytes_custom.c +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include -#include -#include "randombytes.h" - -/* Forward declaration of our custom implementation from utils.c */ -extern void custom_slh_randombytes_impl(uint8_t *out, size_t outlen); - -/* This function is the original randombytes implementation but calls our custom implementation */ -void randombytes(unsigned char *x, unsigned long long xlen) { - custom_slh_randombytes_impl(x, (size_t)xlen); -} diff --git a/sphincsplus/ref/test/cycles.h b/sphincsplus/ref/test/cycles.h new file mode 100644 index 000000000000..913a9a55fe6a --- /dev/null +++ b/sphincsplus/ref/test/cycles.h @@ -0,0 +1,7 @@ +#ifndef SPX_CYCLES_H +#define SPX_CYCLES_H + +void init_cpucycles(void); +unsigned long long cpucycles(void); + +#endif diff --git a/sphincsplus/shake-a64/test/cycles.h b/sphincsplus/shake-a64/test/cycles.h new file mode 120000 index 000000000000..c386581937e5 --- /dev/null +++ b/sphincsplus/shake-a64/test/cycles.h @@ -0,0 +1 @@ +../../ref/test/cycles.h \ No newline at end of file diff --git a/src/ml_dsa/utils.c b/src/ml_dsa/utils.c index a74d49342a09..32caef3df002 100644 --- a/src/ml_dsa/utils.c +++ b/src/ml_dsa/utils.c @@ -1,27 +1,20 @@ #include #include #include -#include "../../dilithium/ref/randombytes.h" #include "../../dilithium/ref/api.h" #include "../../dilithium/ref/fips202.h" #include "../../dilithium/ref/params.h" #include "libbitcoinpqc/ml_dsa.h" +#include "../randombytes_custom.h" /* * This file implements utility functions for ML-DSA-44 (CRYSTALS-Dilithium) * particularly related to random data handling */ -/* Provide a custom random bytes function that uses user-provided entropy */ -static const uint8_t *g_random_data = NULL; -static size_t g_random_data_size = 0; -static size_t g_random_data_offset = 0; - /* Initialize the random data source */ void ml_dsa_init_random_source(const uint8_t *random_data, size_t random_data_size) { - g_random_data = random_data; - g_random_data_size = random_data_size; - g_random_data_offset = 0; + pqc_randombytes_init(random_data, random_data_size); } /* Setup custom random function - this is called before keygen/sign */ @@ -31,63 +24,7 @@ void ml_dsa_setup_custom_random() { /* Restore original random function - this is called after keygen/sign */ void ml_dsa_restore_original_random() { - /* Clear the global state */ - g_random_data = NULL; - g_random_data_size = 0; - g_random_data_offset = 0; -} - -/* This function is called from our custom randombytes implementation */ -void custom_randombytes_impl(uint8_t *out, size_t outlen) { - /* If out is NULL or outlen is 0, nothing to do */ - if (!out || outlen == 0) { - return; - } - - /* If we don't have custom random data, use system randomness */ - if (g_random_data == NULL || g_random_data_size == 0) { - /* Fall back to system randomness */ - FILE *f = fopen("/dev/urandom", "r"); - if (!f) { - /* If we can't open /dev/urandom, just fill with zeros */ - memset(out, 0, outlen); - return; - } - - size_t bytes_read = fread(out, 1, outlen, f); - fclose(f); - - /* If we can't read enough data, fill remaining with zeros */ - if (bytes_read < outlen) { - memset(out + bytes_read, 0, outlen - bytes_read); - } - - return; - } - - /* Otherwise use our provided random data */ - size_t total_copied = 0; - - /* Copy data until we've filled the output buffer */ - while (total_copied < outlen) { - /* Calculate amount to copy */ - size_t amount = outlen - total_copied; - if (amount > g_random_data_size - g_random_data_offset) { - amount = g_random_data_size - g_random_data_offset; - } - - /* Copy the data */ - memcpy(out + total_copied, g_random_data + g_random_data_offset, amount); - - /* Update positions */ - total_copied += amount; - g_random_data_offset += amount; - - /* Wrap around if needed */ - if (g_random_data_offset >= g_random_data_size) { - g_random_data_offset = 0; - } - } + pqc_randombytes_cleanup(); } /* Function to derive deterministic randomness from message and key */ diff --git a/src/randombytes_custom.c b/src/randombytes_custom.c new file mode 100644 index 000000000000..97b5a89fe8fd --- /dev/null +++ b/src/randombytes_custom.c @@ -0,0 +1,81 @@ +/* + * Consolidated custom randombytes implementation. + * + * Provides the single randombytes() definition used by both the Dilithium + * and SPHINCS+ reference implementations. User-provided entropy is + * injected via pqc_randombytes_init(); when no custom data is set the + * function falls back to /dev/urandom. + * + * The Dilithium-style signature (uint8_t*, size_t) is used here. It is + * ABI-compatible with the SPHINCS+ signature (unsigned char*, + * unsigned long long) on LP64 platforms. + */ + +#include +#include +#include +#include +#include "randombytes_custom.h" + +/* Global entropy state */ +static const uint8_t *g_random_data = NULL; +static size_t g_random_data_size = 0; +static size_t g_random_data_offset = 0; + +void pqc_randombytes_init(const uint8_t *data, size_t size) { + g_random_data = data; + g_random_data_size = size; + g_random_data_offset = 0; +} + +void pqc_randombytes_cleanup(void) { + g_random_data = NULL; + g_random_data_size = 0; + g_random_data_offset = 0; +} + +/* + * randombytes() — called by the upstream Dilithium and SPHINCS+ reference + * implementations during keygen and signing. + */ +void randombytes(uint8_t *out, size_t outlen) { + if (!out || outlen == 0) { + return; + } + + /* No custom data: fall back to system randomness */ + if (g_random_data == NULL || g_random_data_size == 0) { + FILE *f = fopen("/dev/urandom", "r"); + if (!f) { + memset(out, 0, outlen); + return; + } + + size_t bytes_read = fread(out, 1, outlen, f); + fclose(f); + + if (bytes_read < outlen) { + memset(out + bytes_read, 0, outlen - bytes_read); + } + return; + } + + /* Serve from user-provided buffer, cycling if necessary */ + size_t total_copied = 0; + + while (total_copied < outlen) { + size_t amount = outlen - total_copied; + if (amount > g_random_data_size - g_random_data_offset) { + amount = g_random_data_size - g_random_data_offset; + } + + memcpy(out + total_copied, g_random_data + g_random_data_offset, amount); + + total_copied += amount; + g_random_data_offset += amount; + + if (g_random_data_offset >= g_random_data_size) { + g_random_data_offset = 0; + } + } +} diff --git a/src/randombytes_custom.h b/src/randombytes_custom.h new file mode 100644 index 000000000000..37e42f262216 --- /dev/null +++ b/src/randombytes_custom.h @@ -0,0 +1,18 @@ +#ifndef PQC_RANDOMBYTES_CUSTOM_H +#define PQC_RANDOMBYTES_CUSTOM_H + +#include +#include + +/* + * Shared entropy state for user-provided randomness. + * + * Call pqc_randombytes_init() before invoking any upstream keygen/sign + * function that calls randombytes(), and pqc_randombytes_cleanup() + * afterwards to clear the global state. + */ + +void pqc_randombytes_init(const uint8_t *data, size_t size); +void pqc_randombytes_cleanup(void); + +#endif /* PQC_RANDOMBYTES_CUSTOM_H */ diff --git a/src/slh_dsa/utils.c b/src/slh_dsa/utils.c index 9bf63038044a..7d37f07cfb6e 100644 --- a/src/slh_dsa/utils.c +++ b/src/slh_dsa/utils.c @@ -2,7 +2,6 @@ #include #include #include -#include "../../sphincsplus/ref/randombytes.h" #include "../../sphincsplus/ref/api.h" #include "../../sphincsplus/ref/fors.h" #include "../../sphincsplus/ref/hash.h" @@ -10,85 +9,26 @@ #include "../../sphincsplus/ref/utils.h" #include "../../sphincsplus/ref/address.h" #include "libbitcoinpqc/slh_dsa.h" +#include "../randombytes_custom.h" /* * This file implements utility functions for SLH-DSA-Shake-128s (SPHINCS+) * particularly related to random data handling */ -/* Provide a custom random bytes function that uses user-provided entropy */ -static const uint8_t *g_random_data = NULL; -static size_t g_random_data_size = 0; -static size_t g_random_data_offset = 0; - /* Initialize the random data source */ void slh_dsa_init_random_source(const uint8_t *random_data, size_t random_data_size) { - g_random_data = random_data; - g_random_data_size = random_data_size; - - /* Always reset offset to ensure deterministic behavior */ - g_random_data_offset = 0; - - /* Note: For truly deterministic behavior across multiple calls, - * we should hash the random data with some constant seed, but - * for this implementation we'll just use the raw data. - */ + pqc_randombytes_init(random_data, random_data_size); } /* Setup custom random function - this is called before keygen/sign */ void slh_dsa_setup_custom_random() { - /* Nothing to do here, as we can't replace the function */ + /* Nothing to do here, as our randombytes function is already set up */ } /* Restore original random function - this is called after keygen/sign */ void slh_dsa_restore_original_random() { - /* Clear the global state */ - g_random_data = NULL; - g_random_data_size = 0; - g_random_data_offset = 0; -} - -/* This function is called from our custom randombytes implementation */ -void custom_slh_randombytes_impl(uint8_t *out, size_t outlen) { - /* If we don't have custom random data, use system randomness */ - if (g_random_data == NULL || g_random_data_size == 0) { - /* Fall back to system randomness */ - FILE *f = fopen("/dev/urandom", "r"); - if (!f) { - /* If we can't open /dev/urandom, just fill with zeros */ - memset(out, 0, outlen); - return; - } - - if (fread(out, 1, outlen, f) != outlen) { - /* If we can't read enough data, fill remaining with zeros */ - memset(out, 0, outlen); - } - - fclose(f); - return; - } - - /* Otherwise use our provided random data */ - size_t remaining = g_random_data_size - g_random_data_offset; - - if (outlen > remaining) { - /* If we need more random bytes than available, we cycle through the provided data */ - size_t position = 0; - - while (position < outlen) { - size_t to_copy = (outlen - position < remaining) ? outlen - position : remaining; - memcpy(out + position, g_random_data + g_random_data_offset, to_copy); - - position += to_copy; - g_random_data_offset = (g_random_data_offset + to_copy) % g_random_data_size; - remaining = g_random_data_size - g_random_data_offset; - } - } else { - /* We have enough random data */ - memcpy(out, g_random_data + g_random_data_offset, outlen); - g_random_data_offset = (g_random_data_offset + outlen) % g_random_data_size; - } + pqc_randombytes_cleanup(); } /* Simple implementation of deterministic randomness from message and key */ From 8071394d7cead8e35a8ef413e7be3401c90ce6c9 Mon Sep 17 00:00:00 2001 From: jbride Date: Tue, 3 Feb 2026 17:12:31 -0700 Subject: [PATCH 2/4] Squashed 'src/libbitcoinpqc/' changes from 5da0891af9..802e1c2a6b 802e1c2a6b segregating core C functionality from language bindings (which will all go in a different git repository git-subtree-dir: src/libbitcoinpqc git-subtree-split: 802e1c2a6b1bbd0bdbbd66f343784c1b9b1ba594 --- .github/workflows/ci.yml | 77 +- .gitignore | 8 - .vscode/settings.json | 5 +- Cargo.lock | 1040 ---- Cargo.toml | 46 - Makefile | 169 +- README.md | 210 +- benches/README.md | 89 - benches/REPORT.md | 31 - benches/sig_benchmarks.rs | 479 -- build.rs | 40 - examples/basic.rs | 77 - fuzz/.gitignore | 3 - fuzz/Cargo.lock | 505 -- fuzz/Cargo.toml | 54 - fuzz/README.md | 83 - ...h-256ac14220a2ca53e6006f2ed7f036b98864e08a | Bin 155 -> 0 bytes fuzz/fuzz_targets/cross_algorithm_fuzz.rs | 66 - fuzz/fuzz_targets/key_parsing_fuzz.rs | 40 - fuzz/fuzz_targets/keypair_generation_fuzz.rs | 28 - fuzz/fuzz_targets/sign_verify_fuzz.rs | 77 - fuzz/fuzz_targets/signature_parsing_fuzz.rs | 22 - fuzz/output.txt | 176 - fuzz/run_all_fuzzers.sh | 29 - nodejs/.gitignore | 25 - nodejs/README.md | 167 - nodejs/binding.gyp | 79 - nodejs/examples/basic-usage.ts | 92 - nodejs/jest.config.js | 8 - nodejs/package-lock.json | 4968 ----------------- nodejs/package.json | 60 - nodejs/scripts/sync-c-sources.sh | 41 - nodejs/src/__tests__/bitcoinpqc.test.ts | 149 - nodejs/src/index.ts | 171 - nodejs/src/library.ts | 187 - nodejs/src/native/bitcoinpqc_addon.cc | 208 - nodejs/src/native/bitcoinpqc_wrapper.cc | 171 - nodejs/src/native/bitcoinpqc_wrapper.h | 17 - nodejs/src/native/mock_bitcoinpqc_addon.cc | 305 - nodejs/src/types.ts | 125 - nodejs/tests/bitcoinpqc.test.ts | 153 - nodejs/tsconfig.json | 116 - python/MANIFEST.in | 4 - python/README.md | 77 - python/bitcoinpqc/__init__.py | 21 - python/bitcoinpqc/bitcoinpqc.py | 533 -- python/check_library.py | 102 - python/examples/__init__.py | 1 - python/examples/basic_usage.py | 65 - python/run_tests.sh | 45 - python/setup.py | 38 - python/tests/__init__.py | 1 - python/tests/test_bitcoinpqc.py | 77 - src/bindings_include.rs | 207 - src/lib.rs | 698 --- tests/algorithm_tests.rs | 316 -- tests/serialization_tests.rs | 447 -- 57 files changed, 38 insertions(+), 12990 deletions(-) delete mode 100644 Cargo.lock delete mode 100644 Cargo.toml delete mode 100644 benches/README.md delete mode 100644 benches/REPORT.md delete mode 100644 benches/sig_benchmarks.rs delete mode 100644 build.rs delete mode 100644 examples/basic.rs delete mode 100644 fuzz/.gitignore delete mode 100644 fuzz/Cargo.lock delete mode 100644 fuzz/Cargo.toml delete mode 100644 fuzz/README.md delete mode 100644 fuzz/artifacts/sign_verify/crash-256ac14220a2ca53e6006f2ed7f036b98864e08a delete mode 100644 fuzz/fuzz_targets/cross_algorithm_fuzz.rs delete mode 100644 fuzz/fuzz_targets/key_parsing_fuzz.rs delete mode 100644 fuzz/fuzz_targets/keypair_generation_fuzz.rs delete mode 100644 fuzz/fuzz_targets/sign_verify_fuzz.rs delete mode 100644 fuzz/fuzz_targets/signature_parsing_fuzz.rs delete mode 100644 fuzz/output.txt delete mode 100755 fuzz/run_all_fuzzers.sh delete mode 100644 nodejs/.gitignore delete mode 100644 nodejs/README.md delete mode 100644 nodejs/binding.gyp delete mode 100644 nodejs/examples/basic-usage.ts delete mode 100644 nodejs/jest.config.js delete mode 100644 nodejs/package-lock.json delete mode 100644 nodejs/package.json delete mode 100755 nodejs/scripts/sync-c-sources.sh delete mode 100644 nodejs/src/__tests__/bitcoinpqc.test.ts delete mode 100644 nodejs/src/index.ts delete mode 100644 nodejs/src/library.ts delete mode 100644 nodejs/src/native/bitcoinpqc_addon.cc delete mode 100644 nodejs/src/native/bitcoinpqc_wrapper.cc delete mode 100644 nodejs/src/native/bitcoinpqc_wrapper.h delete mode 100644 nodejs/src/native/mock_bitcoinpqc_addon.cc delete mode 100644 nodejs/src/types.ts delete mode 100644 nodejs/tests/bitcoinpqc.test.ts delete mode 100644 nodejs/tsconfig.json delete mode 100644 python/MANIFEST.in delete mode 100644 python/README.md delete mode 100644 python/bitcoinpqc/__init__.py delete mode 100644 python/bitcoinpqc/bitcoinpqc.py delete mode 100755 python/check_library.py delete mode 100644 python/examples/__init__.py delete mode 100644 python/examples/basic_usage.py delete mode 100755 python/run_tests.sh delete mode 100644 python/setup.py delete mode 100644 python/tests/__init__.py delete mode 100644 python/tests/test_bitcoinpqc.py delete mode 100644 src/bindings_include.rs delete mode 100644 src/lib.rs delete mode 100644 tests/algorithm_tests.rs delete mode 100644 tests/serialization_tests.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3d9bfa57a8c..52d4d53e11fe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Rust CI +name: C CI on: push: @@ -6,12 +6,9 @@ on: pull_request: branches: [ main ] -env: - CARGO_TERM_COLOR: always - jobs: - test: - name: Test + build: + name: Build and Test runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -21,25 +18,17 @@ jobs: sudo apt-get update sudo apt-get install -y build-essential cmake libssl-dev - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - components: clippy, rustfmt - - - name: Cache dependencies - uses: Swatinem/rust-cache@v2 - - - name: Check code format - run: cargo fmt -- --check - - - name: Clippy - run: cargo clippy -- -D warnings + - name: Configure + run: | + mkdir build + cd build + cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON - name: Build - run: cargo build --verbose + run: cmake --build build --verbose - name: Run tests - run: cargo test --verbose + run: cd build && ctest -V build-matrix: name: Build on ${{ matrix.os }} @@ -48,7 +37,6 @@ jobs: matrix: os: [ubuntu-latest] # os: [ubuntu-latest, macos-latest] - rust: [stable] fail-fast: false steps: - uses: actions/checkout@v3 @@ -64,45 +52,14 @@ jobs: run: | brew install cmake - - name: Install Rust - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ matrix.rust }} - components: clippy, rustfmt - - - name: Cache dependencies - uses: Swatinem/rust-cache@v2 - - - name: Check code format - run: cargo fmt -- --check - - - name: Clippy - run: cargo clippy -- -D warnings + - name: Configure + run: | + mkdir build + cd build + cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_EXAMPLES=ON - name: Build - run: cargo build --verbose + run: cmake --build build --verbose - name: Run tests - run: cargo test --verbose - - # benchmark: - # name: Benchmark - # runs-on: ubuntu-latest - # needs: test - # if: github.event_name == 'push' && github.ref == 'refs/heads/main' - # steps: - # - uses: actions/checkout@v3 - - # - name: Install dependencies - # run: | - # sudo apt-get update - # sudo apt-get install -y build-essential cmake libssl-dev - - # - name: Install Rust - # uses: dtolnay/rust-toolchain@stable - - # - name: Cache dependencies - # uses: Swatinem/rust-cache@v2 - - # - name: Run benchmarks - # run: cargo bench + run: cd build && ctest -V diff --git a/.gitignore b/.gitignore index 37d93e86d5da..f32781186d75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,15 +1,7 @@ build/ -dist/ *.o benchmark_results.txt -__pycache__ -python/build/ -*.egg-info/ -node_modules/ **.gcno **.lcov -**/target/ tags TAGS -rust-toolchain.toml -Cargo.lock \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 206a1070863f..ad92582bd091 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,3 @@ { - "rust-analyzer.cargo.features": ["ide"], - "editor.formatOnSave": true, - "rust-analyzer.check.command": "clippy", - "rust-analyzer.check.extraArgs": ["--all-targets"] + "editor.formatOnSave": true } diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 7a41a757df32..000000000000 --- a/Cargo.lock +++ /dev/null @@ -1,1040 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "anstyle" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "bindgen" -version = "0.71.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitcoin-io" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" -dependencies = [ - "bitcoin-io", - "hex-conservative", -] - -[[package]] -name = "bitcoinpqc" -version = "0.2.0" -dependencies = [ - "bindgen", - "bitmask-enum", - "cmake", - "criterion", - "hex", - "libc", - "rand", - "secp256k1", - "serde", - "serde_json", - "sha2", -] - -[[package]] -name = "bitflags" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" - -[[package]] -name = "bitmask-enum" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6cbbb8f56245b5a479b30a62cdc86d26e2f35c2b9f594bc4671654b03851380" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.2.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc" -dependencies = [ - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" - -[[package]] -name = "ciborium" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" - -[[package]] -name = "ciborium-ll" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f" -dependencies = [ - "clap_builder", -] - -[[package]] -name = "clap_builder" -version = "4.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e" -dependencies = [ - "anstyle", - "clap_lex", -] - -[[package]] -name = "clap_lex" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" -dependencies = [ - "anes", - "cast", - "ciborium", - "clap", - "criterion-plot", - "is-terminal", - "itertools 0.10.5", - "num-traits", - "once_cell", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools 0.10.5", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi", -] - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "half" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-conservative" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi", - "libc", - "windows-sys", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.174" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" - -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets 0.53.2", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "memchr" -version = "2.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "oorandom" -version = "11.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" - -[[package]] -name = "plotters" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aeb6f403d7a4911efb1e33402027fc44f29b5bf6def3effcc22d7bb75f2b747" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df42e13c12958a16b3f7f4386b9ab1f3e7933914ecea48da7139435263a4172a" - -[[package]] -name = "plotters-svg" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51bae2ac328883f7acdfea3d66a7c35751187f870bc81f94563733a154d7a670" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6837b9e10d61f45f987d50808f83d1ee3d206c66acf650c3e4ae2e1f6ddedf55" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustversion" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "secp256k1" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3dff2d01c9aa65c3186a45ff846bfea52cbe6de3b6320ed2a358d90dad0d76" -dependencies = [ - "bitcoin_hashes", - "rand", - "secp256k1-sys", - "serde", -] - -[[package]] -name = "secp256k1-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" -dependencies = [ - "cc", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "2.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "zerocopy" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 338a9b58be26..000000000000 --- a/Cargo.toml +++ /dev/null @@ -1,46 +0,0 @@ -[package] -name = "bitcoinpqc" -version = "0.2.0" -edition = "2021" -authors = ["Hunter Beast "] -description = "Post-Quantum Cryptographic signature algorithms for Bitcoin (BIP-360)" -repository = "https://github.com/bitcoin/libbitcoinpqc" -license = "MIT" -keywords = ["bitcoin", "pqc", "cryptography", "bip-360", "qubit"] - -[dependencies] -hex = "0.4" -libc = "0.2" -bitmask-enum = "2.2.5" -serde = { version = "1.0", features = ["derive"], optional = true } -secp256k1 = { version = "0.31.0", default-features = false, features = [ - "global-context", - "rand", -] } - -[build-dependencies] -bindgen = "0.71.1" -cmake = "0.1" - -[dev-dependencies] -hex = "0.4" -rand = "0.9" -criterion = "0.5" -sha2 = "0.10" -serde_json = "1.0" - -[features] -default = [] -# Enable this feature in your IDE for better code completion -# but never use it for actual builds -ide = [] -# Define the serde feature -serde = ["dep:serde", "secp256k1/serde"] - -[lib] -name = "bitcoinpqc" -crate-type = ["rlib", "staticlib", "cdylib"] - -[[bench]] -name = "sig_benchmarks" -harness = false diff --git a/Makefile b/Makefile index 14ab0d5870df..9fd8e8a3f34e 100644 --- a/Makefile +++ b/Makefile @@ -1,25 +1,17 @@ # libbitcoinpqc - Post-Quantum Cryptography for Bitcoin -# Main Makefile for building, testing, and installing all components +# Main Makefile for building, testing, and installing the C library # User-configurable variables PREFIX ?= /usr/local DEBUG ?= 0 VERBOSE ?= 0 -INSTALL_DEPS ?= 0 -BUILD_DOCS ?= 0 NO_COLOR ?= 0 -BUILD_BINDINGS ?= 0 # Tool detection CMAKE := $(shell command -v cmake 2> /dev/null) -CARGO := $(shell command -v cargo 2> /dev/null) -PYTHON := $(shell command -v python3 2> /dev/null) -NPM := $(shell command -v npm 2> /dev/null) # Build directories BUILD_DIR := build -RELEASE_DIR := target/release -DEBUG_DIR := target/debug # Colors for terminal output ifeq ($(NO_COLOR), 0) @@ -38,14 +30,10 @@ endif # Default target .PHONY: all -all: info c-lib rust-lib bindings +all: info c-lib .PHONY: everything -everything: all examples tests docs - -# Bindings target -.PHONY: bindings -bindings: python nodejs +everything: all examples tests # Print build information .PHONY: info @@ -53,17 +41,11 @@ info: @echo -e "${BLUE}Building libbitcoinpqc - Post-Quantum Cryptography for Bitcoin${NC}" @echo -e "${BLUE}------------------------------------------------------------${NC}" @if [ -n "$(CMAKE)" ]; then echo -e " [${GREEN}✓${NC}] CMake: $(CMAKE)"; else echo -e " [${RED}✗${NC}] CMake (required for C library)"; fi - @if [ -n "$(CARGO)" ]; then echo -e " [${GREEN}✓${NC}] Cargo: $(CARGO)"; else echo -e " [${RED}✗${NC}] Cargo (required for Rust library)"; fi - @if [ -n "$(PYTHON)" ]; then echo -e " [${GREEN}✓${NC}] Python: $(PYTHON)"; else echo -e " [${YELLOW}!${NC}] Python (optional for Python bindings)"; fi - @if [ -n "$(NPM)" ]; then echo -e " [${GREEN}✓${NC}] NPM: $(NPM)"; else echo -e " [${YELLOW}!${NC}] NPM (optional for NodeJS bindings)"; fi @echo -e "${BLUE}------------------------------------------------------------${NC}" - @echo -e "${YELLOW}This will build the core libraries (C and Rust) and language bindings.${NC}" @echo -e "${YELLOW}Available make targets:${NC}" - @echo -e " ${GREEN}make c-lib${NC} - Build only the C library" - @echo -e " ${GREEN}make rust-lib${NC} - Build only the Rust library" - @echo -e " ${GREEN}make bindings${NC} - Build only Python and NodeJS bindings" + @echo -e " ${GREEN}make c-lib${NC} - Build the C library" @echo -e " ${GREEN}make examples${NC} - Build example programs" - @echo -e " ${GREEN}make everything${NC} - Build all components (libraries, bindings, examples, tests)" + @echo -e " ${GREEN}make everything${NC} - Build all components (library, examples, tests)" @echo -e " ${GREEN}make help${NC} - Show all available targets" @echo -e "${BLUE}------------------------------------------------------------${NC}" @@ -82,135 +64,45 @@ cmake-build: @echo -e "${BLUE}Building C library...${NC}" @cmake --build $(BUILD_DIR) $(if $(filter 1,$(VERBOSE)),--verbose,) -# Rust library targets -.PHONY: rust-lib -rust-lib: - @echo -e "${BLUE}Building Rust library...${NC}" - @$(CARGO) build $(if $(filter 0,$(DEBUG)),--release,) - # Example targets .PHONY: examples -examples: c-examples rust-examples - -.PHONY: c-examples -c-examples: c-lib +examples: c-lib @echo -e "${BLUE}Building C examples...${NC}" @cmake --build $(BUILD_DIR) --target examples -.PHONY: rust-examples -rust-examples: - @echo -e "${BLUE}Building and running Rust examples...${NC}" - @$(CARGO) run --example basic $(if $(filter 0,$(DEBUG)),--release,) - # Testing targets .PHONY: tests -tests: test-c test-rust +tests: test-c .PHONY: test-c test-c: c-lib @echo -e "${BLUE}Running C tests...${NC}" @cd $(BUILD_DIR) && ctest $(if $(filter 1,$(VERBOSE)),-V,) -.PHONY: test-rust -test-rust: - @echo -e "${BLUE}Running Rust tests...${NC}" - @$(CARGO) test $(if $(filter 0,$(DEBUG)),--release,) - -# Benchmark targets -.PHONY: bench -bench: - @echo -e "${BLUE}Running benchmarks...${NC}" - @$(CARGO) bench - -# Documentation targets -.PHONY: docs -docs: -ifeq ($(BUILD_DOCS), 1) - @echo -e "${BLUE}Building documentation...${NC}" - @$(CARGO) doc --no-deps - @echo -e "${GREEN}Documentation built in target/doc/bitcoinpqc/index.html${NC}" -else - @echo -e "${YELLOW}Skipping documentation build (use BUILD_DOCS=1 to enable)${NC}" -endif - -# Language bindings -.PHONY: python -python: rust-lib - @echo -e "${BLUE}Building Python bindings...${NC}" - @if [ -n "$(PYTHON)" ]; then \ - echo -e "${YELLOW}Creating a Python virtual environment...${NC}"; \ - $(PYTHON) -m venv python/.venv || { echo -e "${RED}Failed to create virtual environment${NC}"; exit 1; }; \ - echo -e "${GREEN}Virtual environment created at python/.venv${NC}"; \ - echo -e "${YELLOW}Installing Python bindings in virtual environment...${NC}"; \ - . python/.venv/bin/activate && cd python && $(PYTHON) -m pip install -e . && \ - echo -e "${GREEN}Python bindings installed successfully in virtual environment${NC}"; \ - echo -e "${YELLOW}To use the bindings, activate the virtual environment:${NC}"; \ - echo -e " source python/.venv/bin/activate"; \ - else \ - echo -e "${RED}Python not found, skipping Python bindings${NC}"; \ - fi - -.PHONY: nodejs -nodejs: rust-lib - @echo -e "${BLUE}Building NodeJS bindings...${NC}" - @if [ -n "$(NPM)" ]; then \ - cd nodejs && $(NPM) install && $(NPM) run build; \ - else \ - echo -e "${RED}NPM not found, skipping NodeJS bindings${NC}"; \ - fi - # Installation targets .PHONY: install -install: install-c install-rust - -.PHONY: install-c -install-c: c-lib +install: c-lib @echo -e "${BLUE}Installing C library to $(PREFIX)...${NC}" @cd $(BUILD_DIR) && cmake --install . -.PHONY: install-rust -install-rust: rust-lib - @echo -e "${BLUE}Installing Rust library...${NC}" - @$(CARGO) install --path . - # Clean targets .PHONY: clean -clean: clean-c clean-rust clean-bindings - -.PHONY: clean-c -clean-c: - @echo -e "${BLUE}Cleaning C library build files...${NC}" +clean: + @echo -e "${BLUE}Cleaning build files...${NC}" @rm -rf $(BUILD_DIR) -.PHONY: clean-rust -clean-rust: - @echo -e "${BLUE}Cleaning Rust library build files...${NC}" - @$(CARGO) clean - -.PHONY: clean-bindings -clean-bindings: - @echo -e "${BLUE}Cleaning language bindings...${NC}" - @if [ -d "python/build" ]; then rm -rf python/build; fi - @if [ -d "nodejs/dist" ]; then rm -rf nodejs/dist; fi - # Help target .PHONY: help help: @echo -e "${BLUE}libbitcoinpqc Makefile Help${NC}" @echo -e "${BLUE}-------------------------${NC}" @echo -e "Main targets:" - @echo -e " ${GREEN}all${NC} - Build C and Rust libraries and language bindings (default)" - @echo -e " ${GREEN}bindings${NC} - Build Python and NodeJS bindings" + @echo -e " ${GREEN}all${NC} - Build the C library (default)" @echo -e " ${GREEN}everything${NC} - Build all components including examples and tests" - @echo -e " ${GREEN}c-lib${NC} - Build only the C library" - @echo -e " ${GREEN}rust-lib${NC} - Build only the Rust library" - @echo -e " ${GREEN}python${NC} - Build Python bindings" - @echo -e " ${GREEN}nodejs${NC} - Build NodeJS bindings" + @echo -e " ${GREEN}c-lib${NC} - Build the C library" @echo -e " ${GREEN}examples${NC} - Build example programs" @echo -e " ${GREEN}tests${NC} - Run all tests" - @echo -e " ${GREEN}bench${NC} - Run benchmarks" - @echo -e " ${GREEN}docs${NC} - Build documentation" - @echo -e " ${GREEN}install${NC} - Install libraries" + @echo -e " ${GREEN}install${NC} - Install the library" @echo -e " ${GREEN}clean${NC} - Clean all build files" @echo -e " ${GREEN}help${NC} - Display this help message" @echo -e " ${GREEN}fix-warnings${NC} - Fix common build warnings" @@ -218,8 +110,8 @@ help: @echo -e "" @echo -e "Developer targets:" @echo -e " ${GREEN}dev${NC} - Run format, lint, and analyze" - @echo -e " ${GREEN}format${NC} - Format C and Rust code" - @echo -e " ${GREEN}lint${NC} - Lint C and Rust code" + @echo -e " ${GREEN}format${NC} - Format C code" + @echo -e " ${GREEN}lint${NC} - Lint C code" @echo -e " ${GREEN}analyze${NC} - Run static analysis on C code" @echo -e " ${GREEN}dev-deps${NC} - Install development dependencies" @echo -e "" @@ -227,7 +119,6 @@ help: @echo -e " ${YELLOW}DEBUG=1${NC} - Build in debug mode (default: 0)" @echo -e " ${YELLOW}VERBOSE=1${NC} - Show verbose build output (default: 0)" @echo -e " ${YELLOW}PREFIX=/path${NC} - Installation prefix (default: /usr/local)" - @echo -e " ${YELLOW}BUILD_DOCS=1${NC} - Build documentation (default: 0)" @echo -e " ${YELLOW}NO_COLOR=1${NC} - Disable colored output (default: 0)" # Fix warnings targets @@ -255,12 +146,6 @@ troubleshoot: @echo -e " ${YELLOW}Missing tools:${NC}" @echo -e " Make sure you have all required development tools installed." @echo -e "" - @echo -e " ${YELLOW}Python or NodeJS bindings issues:${NC}" - @echo -e " If you experience Python or NodeJS binding problems:" - @echo -e " - For Python: Check the virtual environment at python/.venv" - @echo -e " - For NodeJS: Check the build logs in nodejs/build" - @echo -e " You can build bindings separately with 'make python' or 'make nodejs'" - @echo -e "" @echo -e " ${YELLOW}Terminal color issues:${NC}" @echo -e " If you see raw escape sequences (like \\033[0;32m), run with NO_COLOR=1" @echo -e "" @@ -276,15 +161,9 @@ format: @echo -e "${BLUE}Formatting code...${NC}" @if command -v clang-format > /dev/null; then \ find src include examples -name "*.c" -o -name "*.h" | xargs clang-format -i -style=file; \ - echo -e "${GREEN}C/C++ code formatted${NC}"; \ - else \ - echo -e "${YELLOW}clang-format not found, skipping C/C++ formatting${NC}"; \ - fi - @if [ -n "$(CARGO)" ]; then \ - $(CARGO) fmt; \ - echo -e "${GREEN}Rust code formatted${NC}"; \ + echo -e "${GREEN}C code formatted${NC}"; \ else \ - echo -e "${YELLOW}Cargo not found, skipping Rust formatting${NC}"; \ + echo -e "${YELLOW}clang-format not found, skipping C formatting${NC}"; \ fi .PHONY: lint @@ -292,15 +171,9 @@ lint: @echo -e "${BLUE}Linting code...${NC}" @if command -v cppcheck > /dev/null; then \ cppcheck --enable=all --suppressions-list=.cppcheck-suppressions --error-exitcode=0 src include examples; \ - echo -e "${GREEN}C/C++ code linted${NC}"; \ + echo -e "${GREEN}C code linted${NC}"; \ else \ - echo -e "${YELLOW}cppcheck not found, skipping C/C++ linting${NC}"; \ - fi - @if [ -n "$(CARGO)" ]; then \ - $(CARGO) clippy; \ - echo -e "${GREEN}Rust code linted${NC}"; \ - else \ - echo -e "${YELLOW}Cargo not found, skipping Rust linting${NC}"; \ + echo -e "${YELLOW}cppcheck not found, skipping C linting${NC}"; \ fi .PHONY: analyze @@ -330,7 +203,3 @@ dev-deps: echo "- cppcheck (for static analysis)"; \ echo "- clang tools (for static analysis)"; \ fi - @if [ -n "$(CARGO)" ]; then \ - rustup component add clippy rustfmt; \ - echo -e "${GREEN}Rust development tools installed${NC}"; \ - fi diff --git a/README.md b/README.md index d49d7f61e6a1..47a8835c4eb9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # libbitcoinpqc -A C library, with Rust bindings, for Post-Quantum Cryptographic (PQC) signature algorithms. This library implements two NIST PQC standard signature algorithms for use with [BIP-360](https://github.com/cryptoquick/bips/blob/p2qrh/bip-0360.mediawiki) and the Bitcoin QuBit soft fork: +A C library for Post-Quantum Cryptographic (PQC) signature algorithms. This library implements two NIST PQC standard signature algorithms for use with [BIP-360](https://github.com/cryptoquick/bips/blob/p2qrh/bip-0360.mediawiki) and the Bitcoin QuBit soft fork: 1. **ML-DSA-44** (formerly CRYSTALS-Dilithium): A structured lattice-based digital signature scheme that is part of the NIST PQC standardization. 2. **SLH-DSA-Shake-128s** (formerly SPHINCS+): A stateless hash-based signature scheme with minimal security assumptions. @@ -14,9 +14,6 @@ This library serves as the cryptographic foundation for the Bitcoin QuBit soft f ## Features - Clean, unified C API for all three signature algorithms -- Safe Rust bindings with memory safety and zero-copy operations -- NodeJS TypeScript bindings with full type safety -- Python bindings for easy integration - User-provided entropy (bring your own randomness) - Key generation, signing, and verification functions - Minimal dependencies @@ -29,8 +26,6 @@ This library serves as the cryptographic foundation for the Bitcoin QuBit soft f | ML-DSA-44 | 1,312 bytes | 2,528 bytes | 2,420 bytes | NIST Level 2 | | SLH-DSA-SHAKE-128s | 32 bytes | 64 bytes | 7,856 bytes | NIST Level 1 | -See [REPORT.md](benches/REPORT.md) for performance and size comparison to secp256k1. - ## Security Notes - This library does not provide its own random number generation. It is essential that the user provide entropy from a cryptographically secure source. @@ -59,7 +54,6 @@ Cryptographic dependencies included in this project: - CMake 3.10 or higher - C99 compiler -- Rust 1.50 or higher (for Rust bindings) ### Building @@ -73,46 +67,8 @@ mkdir build cd build cmake .. make - -# Build the Rust library and bindings -cd .. -cargo build --release -``` - -## Fuzz Testing - -This library includes fuzz testing targets using [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). - -### Prerequisites - -```bash -# Install cargo-fuzz -cargo install cargo-fuzz -``` - -### Available Fuzz Targets - -1. **keypair_generation** - Tests key pair generation with different algorithms -2. **sign_verify** - Tests signature creation and verification -3. **cross_algorithm** - Tests verification with mismatched keys and signatures from different algorithms - -### Running Fuzz Tests - -```bash -# Run a specific fuzz target -cargo fuzz run keypair_generation -cargo fuzz run sign_verify -cargo fuzz run cross_algorithm - -# Run a fuzz target for a specific amount of time (in seconds) -cargo fuzz run keypair_generation -- -max_total_time=60 - -# Run a fuzz target with a specific number of iterations -cargo fuzz run sign_verify -- -runs=1000000 ``` -See `fuzz/README.md` for more details on fuzz testing. - ## C API Usage ```c @@ -143,170 +99,6 @@ bitcoin_pqc_signature_free(&signature); bitcoin_pqc_keypair_free(&keypair); ``` -## Rust API Usage - -Rust docs can be found on [docs.rs](https://docs.rs/bitcoinpqc/latest/bitcoinpqc/). - -```rust -use bitcoinpqc::{Algorithm, generate_keypair, sign, verify}; -use rand::{RngCore, rngs::OsRng}; - -// Generate random data for key generation -let mut random_data = vec![0u8; 128]; -OsRng.fill_bytes(&mut random_data); - -// Generate a key pair -let keypair = generate_keypair(Algorithm::MLDSA44, &random_data).unwrap(); - -// Create a message to sign -let message = b"Message to sign"; - -// Sign the message deterministically -let signature = sign(&keypair.secret_key, message).unwrap(); - -// Verify the signature -verify(&keypair.public_key, message, &signature).unwrap(); -``` - -## Python API Usage - -[Python bindings are also available for libbitcoinpqc](https://pypi.org/project/bitcoinpqc/0.1.0/), allowing you to use the post-quantum cryptographic algorithms from Python code. - -### Installation - -```bash -# Install the Python package -cd python -pip install -e . -``` - -### Prerequisites - -- Python 3.7 or higher -- The libbitcoinpqc C library must be built and installed - -### Example Usage - -```python -import secrets -from bitcoinpqc import Algorithm, keygen, sign, verify - -# Generate random data for key generation -random_data = secrets.token_bytes(128) - -# Generate a key pair -algorithm = Algorithm.ML_DSA_44 # CRYSTALS-Dilithium -keypair = keygen(algorithm, random_data) - -# Create a message to sign -message = b"Hello, Bitcoin PQC!" - -# Sign the message -signature = sign(algorithm, keypair.secret_key, message) - -# Verify the signature -is_valid = verify(algorithm, keypair.public_key, message, signature) -print(f"Signature valid: {is_valid}") # Should print True - -# Verification with incorrect message will fail -bad_message = b"Tampered message!" -is_valid = verify(algorithm, keypair.public_key, bad_message, signature) -print(f"Signature valid: {is_valid}") # Should print False -``` - -### Python API Reference - -The Python API mirrors the C API closely, with some Pythonic improvements: - -- **Algorithm** - Enum class for algorithm selection - - `SECP256K1_SCHNORR` - - `ML_DSA_44` (CRYSTALS-Dilithium) - - `SLH_DSA_SHAKE_128S` (SPHINCS+) - -- **KeyPair** - Class to hold a public/secret key pair - - `algorithm` - The algorithm used - - `public_key` - The public key as bytes - - `secret_key` - The secret key as bytes - -- **Signature** - Class to hold a signature - - `algorithm` - The algorithm used - - `signature` - The signature as bytes - -- **Functions** - - `public_key_size(algorithm)` - Get the public key size for an algorithm - - `secret_key_size(algorithm)` - Get the secret key size for an algorithm - - `signature_size(algorithm)` - Get the signature size for an algorithm - - `keygen(algorithm, random_data)` - Generate a key pair - - `sign(algorithm, secret_key, message)` - Sign a message - - `verify(algorithm, public_key, message, signature)` - Verify a signature - -## NodeJS TypeScript API Usage - -[NodeJS TypeScript bindings](https://www.npmjs.com/package/bitcoinpqc) allow you to use post-quantum cryptographic algorithms in JavaScript/TypeScript projects. - -### Installation - -```bash -# Install the Node.js package -npm install bitcoinpqc -``` - -### Prerequisites - -- Node.js 16 or higher -- The libbitcoinpqc C library must be built and installed - -### Example Usage - -```typescript -import { Algorithm, generateKeyPair, sign, verify } from 'bitcoinpqc'; -import crypto from 'crypto'; - -// Generate random data for key generation -const randomData = crypto.randomBytes(128); - -// Generate a key pair using ML-DSA-44 (CRYSTALS-Dilithium) -const keypair = generateKeyPair(Algorithm.ML_DSA_44, randomData); - -// Create a message to sign -const message = Buffer.from('Message to sign'); - -// Sign the message deterministically -const signature = sign(keypair.secretKey, message); - -// Verify the signature -verify(keypair.publicKey, message, signature); -// If verification fails, it will throw a PqcError - -// You can also verify using the raw signature bytes -verify(keypair.publicKey, message, signature.bytes); -``` - -### NodeJS TypeScript API Reference - -The TypeScript API provides a clean, modern interface: - -- **Algorithm** - Enum for algorithm selection - - `SECP256K1_SCHNORR` - - `ML_DSA_44` (CRYSTALS-Dilithium) - - `SLH_DSA_SHAKE_128S` (SPHINCS+) - -- **Classes** - - `PublicKey` - Public key wrapper - - `SecretKey` - Secret key wrapper with secure handling - - `KeyPair` - Container for public/secret key pairs - - `Signature` - Signature wrapper - -- **Functions** - - `publicKeySize(algorithm)` - Get the public key size for an algorithm - - `secretKeySize(algorithm)` - Get the secret key size for an algorithm - - `signatureSize(algorithm)` - Get the signature size for an algorithm - - `generateKeyPair(algorithm, randomData)` - Generate a key pair - - `sign(secretKey, message)` - Sign a message - - `verify(publicKey, message, signature)` - Verify a signature - -For more details, see the [NodeJS TypeScript bindings README](nodejs/README.md). - ## Acknowledgments - The original NIST PQC competition teams for their reference implementations diff --git a/benches/README.md b/benches/README.md deleted file mode 100644 index e6decfd39802..000000000000 --- a/benches/README.md +++ /dev/null @@ -1,89 +0,0 @@ -# Post-Quantum Cryptography Benchmarks - -This directory contains benchmarks for the post-quantum cryptography algorithms implemented in the library, as well as benchmarks for secp256k1 for comparison. - -## Running All Benchmarks - -To run all benchmarks: - -``` -cargo bench -``` - -## Running Algorithm-Specific Benchmarks - -You can run benchmarks for a specific algorithm by using the filter option with `cargo bench`: - -### ML-DSA-44 (CRYSTALS-Dilithium) - -``` -cargo bench -- ml_dsa_44 -``` - -### SLH-DSA-128S (SPHINCS+) - -``` -cargo bench -- slh_dsa_128s -``` - -### secp256k1 (for comparison) - -``` -cargo bench -- secp256k1 -``` - -## Running Operation-Specific Benchmarks - -You can also run benchmarks for specific operations: - -### Key Generation Benchmarks - -``` -cargo bench -- keygen -``` - -### Signing Benchmarks - -``` -cargo bench -- signing -``` - -### Verification Benchmarks - -``` -cargo bench -- verification -``` - -### Size Comparison Benchmarks - -``` -cargo bench -- sizes -``` - -## Comparing Algorithms - -To see how post-quantum algorithms compare to current standards: - -``` -# Compare key generation speed -cargo bench -- keygen - -# Compare signing speed -cargo bench -- signing - -# Compare verification speed -cargo bench -- verification - -# Compare key and signature sizes -cargo bench -- sizes -``` - -## Troubleshooting - -If you encounter any issues with a specific algorithm, try running only that algorithm's benchmarks: - -``` -cargo bench -- ml_dsa_44 -``` - -This can help identify any issues with the algorithm implementation. diff --git a/benches/REPORT.md b/benches/REPORT.md deleted file mode 100644 index e8538eec8132..000000000000 --- a/benches/REPORT.md +++ /dev/null @@ -1,31 +0,0 @@ -# Benchmark Report: Post-Quantum Cryptography vs secp256k1 - -This report compares the performance and size characteristics of post-quantum cryptographic algorithms with secp256k1. - -## Performance Comparison - -All values show relative performance compared to secp256k1 (lower is better). - -| Algorithm | Key Generation | Signing | Verification | -|-----------|----------------|---------|--------------| -| secp256k1 | 1.00x | 1.00x | 1.00x | -| ML-DSA-44 | *Needs Update* | *Needs Update* | *Needs Update* | -| SLH-DSA-128S | *Needs Update* | *Needs Update* | *Needs Update* | - -*Note: Performance values require parsing Criterion output and are not yet updated automatically.* - -## Size Comparison - -All values show actual sizes with relative comparison to secp256k1. - -| Algorithm | Secret Key | Public Key | Signature | Public Key + Signature | -|-----------|------------|------------|-----------|------------------------| -| secp256k1 | 32 bytes (1.00x) | 32 bytes (1.00x) | 64 bytes (1.00x) | 96 bytes (1.00x) | -| ML-DSA-44 | 2560 bytes (80.00x) | 1312 bytes (41.00x) | 2420 bytes (37.81x) | 3732 bytes (38.88x) | -| SLH-DSA-128S | 64 bytes (2.00x) | 32 bytes (1.00x) | 7856 bytes (122.75x) | 7888 bytes (82.17x) | - -## Summary - -This benchmark comparison demonstrates the performance and size tradeoffs between post-quantum cryptographic algorithms and traditional elliptic curve cryptography (secp256k1). - -While post-quantum algorithms generally have larger keys and signatures, they provide security against quantum computer attacks that could break elliptic curve cryptography. diff --git a/benches/sig_benchmarks.rs b/benches/sig_benchmarks.rs deleted file mode 100644 index 796bdbb384c3..000000000000 --- a/benches/sig_benchmarks.rs +++ /dev/null @@ -1,479 +0,0 @@ -use std::collections::HashMap; -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; -use std::sync::Mutex; -use std::sync::OnceLock; -use std::time::Duration; - -use criterion::{criterion_group, criterion_main, Criterion}; -use rand::{rng, RngCore}; - -use bitcoinpqc::{generate_keypair, sign, verify, Algorithm}; - -// Set to true to enable debug output, false to disable -const DEBUG_MODE: bool = false; - -// Global storage for sizes -static SIZE_RESULTS: OnceLock>> = OnceLock::new(); - -// Helper function to get or initialize the size results -fn get_size_results() -> &'static Mutex> { - SIZE_RESULTS.get_or_init(|| Mutex::new(HashMap::new())) -} - -// Conditional debug print macro -macro_rules! debug_println { - ($($arg:tt)*) => { - if DEBUG_MODE { - println!($($arg)*); - } - }; -} - -// Get random data of a specified size -fn get_random_data(size: usize) -> Vec { - let mut random_data = vec![0u8; size]; - rng().fill_bytes(&mut random_data); - random_data -} - -// Configure benchmark group with common settings -fn configure_group(group: &mut criterion::BenchmarkGroup) { - group.measurement_time(Duration::from_secs(10)); -} - -// Helper function to store size results -fn store_size_result(name: &str, value: usize) { - let results = get_size_results(); - let mut results = results.lock().unwrap(); - results.insert(name.to_string(), value); -} - -// ML-DSA-44 BENCHMARKS - -fn bench_ml_dsa_44_keygen(c: &mut Criterion) { - let mut group = c.benchmark_group("ml_dsa_keygen"); - configure_group(&mut group); - - group.bench_function("ML_DSA_44", |b| { - b.iter(|| { - let random_data = get_random_data(256); - generate_keypair(Algorithm::ML_DSA_44, &random_data).unwrap() - }); - }); - - group.finish(); -} - -fn bench_ml_dsa_44_signing(c: &mut Criterion) { - let mut group = c.benchmark_group("ml_dsa_signing"); - configure_group(&mut group); - - let message = b"This is a test message for benchmarking"; - let random_data = get_random_data(256); - let ml_keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data).unwrap(); - - group.bench_function("ML_DSA_44", |b| { - b.iter(|| sign(&ml_keypair.secret_key, message)); - }); - - group.finish(); -} - -fn bench_ml_dsa_44_verification(c: &mut Criterion) { - let mut group = c.benchmark_group("ml_dsa_verification"); - configure_group(&mut group); - - let message = b"This is a test message for benchmarking"; - let random_data = get_random_data(256); - let ml_keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data).unwrap(); - let ml_sig = sign(&ml_keypair.secret_key, message).unwrap(); - - group.bench_function("ML_DSA_44", |b| { - b.iter(|| verify(&ml_keypair.public_key, message, &ml_sig).unwrap()); - }); - - group.finish(); -} - -// SLH-DSA-128S BENCHMARKS - -fn bench_slh_dsa_128s_keygen(c: &mut Criterion) { - let mut group = c.benchmark_group("slh_dsa_keygen"); - configure_group(&mut group); - group.sample_size(10); // Reduce sample count for SLH-DSA which is slower - - group.bench_function("SLH_DSA_128S", |b| { - b.iter(|| { - let random_data = get_random_data(256); - generate_keypair(Algorithm::SLH_DSA_128S, &random_data).unwrap() - }); - }); - - group.finish(); -} - -fn bench_slh_dsa_128s_signing(c: &mut Criterion) { - let mut group = c.benchmark_group("slh_dsa_signing"); - configure_group(&mut group); - group.sample_size(10); // Reduce sample count for SLH-DSA which is slower - - let message = b"This is a test message for benchmarking"; - let random_data = get_random_data(256); - let slh_keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data).unwrap(); - - group.bench_function("SLH_DSA_128S", |b| { - b.iter(|| sign(&slh_keypair.secret_key, message)); - }); - - group.finish(); -} - -fn bench_slh_dsa_128s_verification(c: &mut Criterion) { - let mut group = c.benchmark_group("slh_dsa_verification"); - configure_group(&mut group); - group.sample_size(10); // Reduce sample count for SLH-DSA which is slower - - let message = b"This is a test message for benchmarking"; - let random_data = get_random_data(256); - let slh_keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data).unwrap(); - let slh_sig = sign(&slh_keypair.secret_key, message).unwrap(); - - group.bench_function("SLH_DSA_128S", |b| { - b.iter(|| verify(&slh_keypair.public_key, message, &slh_sig).unwrap()); - }); - - group.finish(); -} - -// SIZE REPORTING - Combined in one benchmark - -fn bench_sizes(c: &mut Criterion) { - let group = c.benchmark_group("sizes"); - - let message = b"This is a test message for benchmarking"; - - // ML-DSA-44 - let random_data = get_random_data(256); - let ml_keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data).unwrap(); - let ml_sig = sign(&ml_keypair.secret_key, message).unwrap(); - let ml_pk_size = ml_keypair.public_key.bytes.len(); - let ml_sk_size = ml_keypair.secret_key.bytes.len(); - let ml_sig_size = ml_sig.bytes.len(); - let ml_pk_sig_size = ml_pk_size + ml_sig_size; - - // Store size results - store_size_result("ml_dsa_44_pubkey", ml_pk_size); - store_size_result("ml_dsa_44_seckey", ml_sk_size); - store_size_result("ml_dsa_44_sig", ml_sig_size); - store_size_result("ml_dsa_44_pk_sig", ml_pk_sig_size); - - // SLH-DSA-128S - let random_data = get_random_data(256); - let slh_keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data).unwrap(); - let slh_sig = sign(&slh_keypair.secret_key, message).unwrap(); - let slh_pk_size = slh_keypair.public_key.bytes.len(); - let slh_sk_size = slh_keypair.secret_key.bytes.len(); - let slh_sig_size = slh_sig.bytes.len(); - let slh_pk_sig_size = slh_pk_size + slh_sig_size; - - // Store size results - store_size_result("slh_dsa_128s_pubkey", slh_pk_size); - store_size_result("slh_dsa_128s_seckey", slh_sk_size); - store_size_result("slh_dsa_128s_sig", slh_sig_size); - store_size_result("slh_dsa_128s_pk_sig", slh_pk_sig_size); - - // Print key and signature sizes - debug_println!("Key and Signature Sizes (bytes):"); - debug_println!("ML-DSA-44:"); - debug_println!( - " Public key: {}, Secret key: {}, Signature: {}", - ml_pk_size, - ml_sk_size, - ml_sig_size - ); - - debug_println!("SLH-DSA-128S:"); - debug_println!( - " Public key: {}, Secret key: {}, Signature: {}", - slh_pk_size, - slh_sk_size, - slh_sig_size - ); - - group.finish(); -} - -// Function to generate the markdown report by updating existing file -fn generate_report(_c: &mut Criterion) { - let report_path = "benches/REPORT.md"; - let mut report_content = String::new(); - - // Try to read the existing report file - match File::open(report_path) { - Ok(mut file) => { - if file.read_to_string(&mut report_content).is_err() { - eprintln!( - "Error reading existing report file: {}. Creating a new one.", - report_path - ); - report_content.clear(); - } - } - Err(_) => { - println!("Report file {} not found. Creating a new one.", report_path); - } - } - - // Get size results - let size_results = get_size_results(); - let size_results = size_results.lock().unwrap(); - - // --- Parse existing secp256k1 values or use defaults --- - let mut secp_pubkey_size = 32; // Default - let mut secp_seckey_size = 32; // Default - let mut secp_sig_size = 64; // Default - let mut secp_pk_sig_size = secp_pubkey_size + secp_sig_size; // Default derived - - // Find and parse secp256k1 sizes from the report if available - if let Some(line) = report_content - .lines() - .find(|l| l.starts_with("| secp256k1 |")) - { - let parts: Vec<&str> = line.split('|').map(|s| s.trim()).collect(); - // Expecting format: | secp256k1 | SK bytes (rel) | PK bytes (rel) | Sig bytes (rel) | PK+Sig bytes (rel) | - if parts.len() > 5 { - // Parse Secret Key Size (Column 2) - if let Ok(sk) = parts[2] - .split_whitespace() - .next() - .unwrap_or("0") - .parse::() - { - secp_seckey_size = sk; - } - // Parse Public Key Size (Column 3) - if let Ok(pk) = parts[3] - .split_whitespace() - .next() - .unwrap_or("0") - .parse::() - { - secp_pubkey_size = pk; - } - // Parse Signature Size (Column 4) - if let Ok(sig) = parts[4] - .split_whitespace() - .next() - .unwrap_or("0") - .parse::() - { - secp_sig_size = sig; - } - // Recalculate combined size based on parsed values (Column 5 is derived) - secp_pk_sig_size = secp_pubkey_size + secp_sig_size; - } else { - println!( - "Warning: Found secp256k1 line but failed to parse sizes correctly from: {}", - line - ); - } - } - - // --- Process lines and update size table --- - let mut updated_lines = Vec::new(); - let mut in_size_table = false; - let mut size_table_header_found = false; - // Define the expected header and separator for the size table (matching the commit diff) - let size_table_header = - "| Algorithm | Secret Key | Public Key | Signature | Public Key + Signature |"; - let size_table_separator = - "|-----------|------------|------------|-----------|------------------------|"; - - for line in report_content.lines() { - let mut line_to_push = line.to_string(); // Default to original line - let trimmed_line = line.trim(); - - // Detect entering/leaving the size table - if trimmed_line == size_table_separator && size_table_header_found { - in_size_table = true; // Mark start of data rows - } else if trimmed_line == size_table_header { - size_table_header_found = true; // Found the header - } else if trimmed_line.is_empty() || trimmed_line.starts_with("#") { - // Stop processing table rows if we hit an empty line or a new section header - if in_size_table { - in_size_table = false; - size_table_header_found = false; // Reset for potential future tables - } - } - - // Update rows within the size table - if in_size_table { - if trimmed_line.starts_with("| secp256k1 |") { - // Format the secp256k1 line using parsed/default values - line_to_push = format!( - "| secp256k1 | {} bytes (1.00x) | {} bytes (1.00x) | {} bytes (1.00x) | {} bytes (1.00x) |", - secp_seckey_size, secp_pubkey_size, secp_sig_size, secp_pk_sig_size - ); - } else if trimmed_line.starts_with("| ML-DSA-44 |") { - let ml_pubkey_size = size_results.get("ml_dsa_44_pubkey").cloned().unwrap_or(0); - let ml_seckey_size = size_results.get("ml_dsa_44_seckey").cloned().unwrap_or(0); - let ml_sig_size = size_results.get("ml_dsa_44_sig").cloned().unwrap_or(0); - let ml_pk_sig_size = size_results.get("ml_dsa_44_pk_sig").cloned().unwrap_or(0); - line_to_push = format!( - "| ML-DSA-44 | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) |", - ml_seckey_size, if secp_seckey_size > 0 { ml_seckey_size as f64 / secp_seckey_size as f64 } else { 0.0 }, - ml_pubkey_size, if secp_pubkey_size > 0 { ml_pubkey_size as f64 / secp_pubkey_size as f64 } else { 0.0 }, - ml_sig_size, if secp_sig_size > 0 { ml_sig_size as f64 / secp_sig_size as f64 } else { 0.0 }, - ml_pk_sig_size, if secp_pk_sig_size > 0 { ml_pk_sig_size as f64 / secp_pk_sig_size as f64 } else { 0.0 } - ); - } else if trimmed_line.starts_with("| SLH-DSA-128S |") { - let slh_pubkey_size = size_results - .get("slh_dsa_128s_pubkey") - .cloned() - .unwrap_or(0); - let slh_seckey_size = size_results - .get("slh_dsa_128s_seckey") - .cloned() - .unwrap_or(0); - let slh_sig_size = size_results.get("slh_dsa_128s_sig").cloned().unwrap_or(0); - let slh_pk_sig_size = size_results - .get("slh_dsa_128s_pk_sig") - .cloned() - .unwrap_or(0); - line_to_push = format!( - "| SLH-DSA-128S | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) |", - slh_seckey_size, if secp_seckey_size > 0 { slh_seckey_size as f64 / secp_seckey_size as f64 } else { 0.0 }, - slh_pubkey_size, if secp_pubkey_size > 0 { slh_pubkey_size as f64 / secp_pubkey_size as f64 } else { 0.0 }, - slh_sig_size, if secp_sig_size > 0 { slh_sig_size as f64 / secp_sig_size as f64 } else { 0.0 }, - slh_pk_sig_size, if secp_pk_sig_size > 0 { slh_pk_sig_size as f64 / secp_pk_sig_size as f64 } else { 0.0 } - ); - } - // Note: Any other lines within the size table block will keep their original content (e.g., comments) - } - - updated_lines.push(line_to_push); - } - - // --- Generate default report if needed --- - // If the report was empty or didn't contain the expected size table header, generate a default one. - if report_content.is_empty() || !report_content.contains(size_table_header) { - println!("Generating default report structure in {}.", report_path); - updated_lines.clear(); // Start fresh - - // Default Header - updated_lines - .push("# Benchmark Report: Post-Quantum Cryptography vs secp256k1".to_string()); - updated_lines.push("\nThis report compares the performance and size characteristics of post-quantum cryptographic algorithms with secp256k1.\n".to_string()); - - // Default Performance section (with placeholders) - updated_lines.push("## Performance Comparison\n".to_string()); - updated_lines.push( - "All values show relative performance compared to secp256k1 (lower is better).\n" - .to_string(), - ); - updated_lines.push("| Algorithm | Key Generation | Signing | Verification |".to_string()); - updated_lines.push("|-----------|----------------|---------|--------------|".to_string()); - updated_lines.push("| secp256k1 | 1.00x | 1.00x | 1.00x |".to_string()); - updated_lines - .push("| ML-DSA-44 | *Needs Update* | *Needs Update* | *Needs Update* |".to_string()); // Placeholders - updated_lines.push( - "| SLH-DSA-128S | *Needs Update* | *Needs Update* | *Needs Update* |".to_string(), - ); // Placeholders - updated_lines.push("\n*Note: Performance values require parsing Criterion output and are not yet updated automatically.*".to_string()); - - // Default Size section (using current data and new format) - updated_lines.push("\n## Size Comparison\n".to_string()); - updated_lines.push( - "All values show actual sizes with relative comparison to secp256k1.\n".to_string(), - ); - updated_lines.push(size_table_header.to_string()); // Use the defined header - updated_lines.push(size_table_separator.to_string()); // Use the defined separator - - // secp line - updated_lines.push(format!( - "| secp256k1 | {} bytes (1.00x) | {} bytes (1.00x) | {} bytes (1.00x) | {} bytes (1.00x) |", - secp_seckey_size, secp_pubkey_size, secp_sig_size, secp_pk_sig_size - )); - - // ML-DSA line - let ml_pubkey_size = size_results.get("ml_dsa_44_pubkey").cloned().unwrap_or(0); - let ml_seckey_size = size_results.get("ml_dsa_44_seckey").cloned().unwrap_or(0); - let ml_sig_size = size_results.get("ml_dsa_44_sig").cloned().unwrap_or(0); - let ml_pk_sig_size = size_results.get("ml_dsa_44_pk_sig").cloned().unwrap_or(0); - updated_lines.push(format!( - "| ML-DSA-44 | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) |", - ml_seckey_size, if secp_seckey_size > 0 { ml_seckey_size as f64 / secp_seckey_size as f64 } else { 0.0 }, - ml_pubkey_size, if secp_pubkey_size > 0 { ml_pubkey_size as f64 / secp_pubkey_size as f64 } else { 0.0 }, - ml_sig_size, if secp_sig_size > 0 { ml_sig_size as f64 / secp_sig_size as f64 } else { 0.0 }, - ml_pk_sig_size, if secp_pk_sig_size > 0 { ml_pk_sig_size as f64 / secp_pk_sig_size as f64 } else { 0.0 } - )); - - // SLH-DSA line - let slh_pubkey_size = size_results - .get("slh_dsa_128s_pubkey") - .cloned() - .unwrap_or(0); - let slh_seckey_size = size_results - .get("slh_dsa_128s_seckey") - .cloned() - .unwrap_or(0); - let slh_sig_size = size_results.get("slh_dsa_128s_sig").cloned().unwrap_or(0); - let slh_pk_sig_size = size_results - .get("slh_dsa_128s_pk_sig") - .cloned() - .unwrap_or(0); - updated_lines.push(format!( - "| SLH-DSA-128S | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) | {} bytes ({:.2}x) |", - slh_seckey_size, if secp_seckey_size > 0 { slh_seckey_size as f64 / secp_seckey_size as f64 } else { 0.0 }, - slh_pubkey_size, if secp_pubkey_size > 0 { slh_pubkey_size as f64 / secp_pubkey_size as f64 } else { 0.0 }, - slh_sig_size, if secp_sig_size > 0 { slh_sig_size as f64 / secp_sig_size as f64 } else { 0.0 }, - slh_pk_sig_size, if secp_pk_sig_size > 0 { slh_pk_sig_size as f64 / secp_pk_sig_size as f64 } else { 0.0 } - )); - - // Default Summary - updated_lines.push("\n## Summary\n".to_string()); - updated_lines.push("This benchmark comparison demonstrates the performance and size tradeoffs between post-quantum cryptographic algorithms and traditional elliptic curve cryptography (secp256k1).".to_string()); - updated_lines.push("\nWhile post-quantum algorithms generally have larger keys and signatures, they provide security against quantum computer attacks that could break elliptic curve cryptography.".to_string()); - } - - // --- Write updated content back to file --- - match OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .open(report_path) - { - Ok(mut file) => { - let output_string = updated_lines.join("\n"); - if file.write_all(output_string.as_bytes()).is_err() { - eprintln!("Error writing updated report to {}", report_path); - } else { - // Add a trailing newline if the content doesn't end with one - if !output_string.ends_with('\n') { - if file.write_all(b"\n").is_err() { - eprintln!("Error writing trailing newline to {}", report_path); - } - } - println!("Report updated successfully: {}", report_path); - } - } - Err(e) => { - eprintln!("Failed to open {} for writing: {}", report_path, e); - } - } -} - -// Organize the benchmarks by algorithm rather than by operation -criterion_group!( - benches, - bench_ml_dsa_44_keygen, - bench_ml_dsa_44_signing, - bench_ml_dsa_44_verification, - bench_slh_dsa_128s_keygen, - bench_slh_dsa_128s_signing, - bench_slh_dsa_128s_verification, - bench_sizes, - generate_report -); -criterion_main!(benches); diff --git a/build.rs b/build.rs deleted file mode 100644 index eb5e25a295c7..000000000000 --- a/build.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::env; -use std::path::PathBuf; - -fn main() { - // Build the C library - let dst = cmake::build("."); - - // Link against the built library - println!("cargo:rustc-link-search=native={}/lib", dst.display()); - println!("cargo:rustc-link-lib=static=bitcoinpqc"); - - // Tell cargo to invalidate the built crate whenever the headers change - println!("cargo:rerun-if-changed=include/libbitcoinpqc/bitcoinpqc.h"); - println!("cargo:rerun-if-changed=include/libbitcoinpqc/ml_dsa.h"); - println!("cargo:rerun-if-changed=include/libbitcoinpqc/slh_dsa.h"); - - // The bindgen::Builder is the main entry point to bindgen - let bindings = bindgen::Builder::default() - // The input header to generate bindings for - .header("include/libbitcoinpqc/bitcoinpqc.h") - // Tell bindgen to generate constants for enums - .bitfield_enum("bitcoin_pqc_algorithm_t") - .bitfield_enum("bitcoin_pqc_error_t") - // Tell cargo to invalidate the built crate whenever the wrapper changes - .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) - // Suppress warnings for unused code in the generated bindings - .allowlist_function("bitcoin_pqc_.*") - .allowlist_type("bitcoin_pqc_.*") - .allowlist_var("BITCOIN_PQC_.*") - // Generate bindings - .generate() - // Unwrap the Result and panic on failure - .expect("Unable to generate bindings"); - - // Write the bindings to the $OUT_DIR/bindings.rs file - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); - bindings - .write_to_file(out_path.join("bindings.rs")) - .expect("Couldn't write bindings!"); -} diff --git a/examples/basic.rs b/examples/basic.rs deleted file mode 100644 index 2305e45585bb..000000000000 --- a/examples/basic.rs +++ /dev/null @@ -1,77 +0,0 @@ -use bitcoinpqc::{generate_keypair, sign, verify, Algorithm}; -use rand::{rng, RngCore}; -use std::time::Instant; - -fn main() { - println!("Bitcoin PQC Library Example"); - println!("==========================\n"); - println!("This example tests the post-quantum signature algorithms designed for BIP-360 and the Bitcoin QuBit soft fork.\n"); - - // Generate random data for key generation - let mut random_data = vec![0u8; 128]; - rng().fill_bytes(&mut random_data); - - // Test each algorithm - test_algorithm(Algorithm::ML_DSA_44, "ML-DSA-44", &random_data); - test_algorithm(Algorithm::SLH_DSA_128S, "SLH-DSA-Shake-128s", &random_data); -} - -fn test_algorithm(algorithm: Algorithm, name: &str, random_data: &[u8]) { - println!("Testing {name} algorithm:"); - println!("------------------------"); - - // Get key and signature sizes - let pk_size = bitcoinpqc::public_key_size(algorithm); - let sk_size = bitcoinpqc::secret_key_size(algorithm); - let sig_size = bitcoinpqc::signature_size(algorithm); - - println!("Public key size: {pk_size} bytes"); - println!("Secret key size: {sk_size} bytes"); - println!("Signature size: {sig_size} bytes"); - - // Generate a key pair - let start = Instant::now(); - let keypair = match generate_keypair(algorithm, random_data) { - Ok(kp) => kp, - Err(e) => { - println!("Error generating key pair: {e}"); - return; - } - }; - let duration = start.elapsed(); - println!("Key generation time: {duration:?}"); - - // Create a message to sign - let message = b"This is a test message for PQC signature verification"; - - // Sign the message deterministically - let start = Instant::now(); - let signature = match sign(&keypair.secret_key, message) { - Ok(sig) => sig, - Err(e) => { - println!("Error signing message: {e}"); - return; - } - }; - let duration = start.elapsed(); - println!("Signing time: {duration:?}"); - println!("Actual signature size: {} bytes", signature.bytes.len()); - - // Verify the signature - let start = Instant::now(); - match verify(&keypair.public_key, message, &signature) { - Ok(()) => println!("Signature verified successfully!"), - Err(e) => println!("Signature verification failed: {e}"), - } - let duration = start.elapsed(); - println!("Verification time: {duration:?}"); - - // Try to verify with a modified message - let modified_message = b"This is a MODIFIED message for PQC signature verification"; - match verify(&keypair.public_key, modified_message, &signature) { - Ok(()) => println!("ERROR: Signature verified for modified message!"), - Err(_) => println!("Correctly rejected signature for modified message"), - } - - println!(); -} diff --git a/fuzz/.gitignore b/fuzz/.gitignore deleted file mode 100644 index 2eb15f8ed0e7..000000000000 --- a/fuzz/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -target -corpus -coverage diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock deleted file mode 100644 index 1ef40c7daa44..000000000000 --- a/fuzz/Cargo.lock +++ /dev/null @@ -1,505 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "bindgen" -version = "0.71.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", - "syn", -] - -[[package]] -name = "bitcoin-io" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" - -[[package]] -name = "bitcoin_hashes" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" -dependencies = [ - "bitcoin-io", - "hex-conservative", -] - -[[package]] -name = "bitcoinpqc" -version = "0.2.0" -dependencies = [ - "bindgen", - "bitmask-enum", - "cmake", - "hex", - "libc", - "secp256k1", -] - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "bitmask-enum" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6cbbb8f56245b5a479b30a62cdc86d26e2f35c2b9f594bc4671654b03851380" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "cc" -version = "1.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmake" -version = "0.1.54" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" -dependencies = [ - "cc", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "getrandom" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasi", -] - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex-conservative" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" -dependencies = [ - "arrayvec", -] - -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "libbitcoinpqc-fuzz" -version = "0.0.0" -dependencies = [ - "bitcoinpqc", - "libfuzzer-sys", -] - -[[package]] -name = "libc" -version = "0.2.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "libfuzzer-sys" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75" -dependencies = [ - "arbitrary", - "cc", -] - -[[package]] -name = "libloading" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" -dependencies = [ - "cfg-if", - "windows-targets", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "prettyplease" -version = "0.2.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5316f57387668042f561aae71480de936257848f9c43ce528e311d89a07cadeb" -dependencies = [ - "proc-macro2", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "secp256k1" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a3dff2d01c9aa65c3186a45ff846bfea52cbe6de3b6320ed2a358d90dad0d76" -dependencies = [ - "bitcoin_hashes", - "rand", - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" -dependencies = [ - "cc", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml deleted file mode 100644 index 87bea896d982..000000000000 --- a/fuzz/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "libbitcoinpqc-fuzz" -version = "0.0.0" -publish = false -edition = "2021" - -[package.metadata] -cargo-fuzz = true - -[dependencies] -libfuzzer-sys = "0.4" - -[dependencies.bitcoinpqc] -path = ".." - -# Renamed and repurposed from the original target -[[bin]] -name = "keypair_generation" -path = "fuzz_targets/keypair_generation_fuzz.rs" -test = false -doc = false -bench = false - -# New target for sign and verify operations -[[bin]] -name = "sign_verify" -path = "fuzz_targets/sign_verify_fuzz.rs" -test = false -doc = false -bench = false - -# New target for cross-algorithm verification -[[bin]] -name = "cross_algorithm" -path = "fuzz_targets/cross_algorithm_fuzz.rs" -test = false -doc = false -bench = false - -# New target for key parsing -[[bin]] -name = "key_parsing" -path = "fuzz_targets/key_parsing_fuzz.rs" -test = false -doc = false -bench = false - -# New target for signature parsing -[[bin]] -name = "signature_parsing" -path = "fuzz_targets/signature_parsing_fuzz.rs" -test = false -doc = false -bench = false diff --git a/fuzz/README.md b/fuzz/README.md deleted file mode 100644 index dbc8c7e5faa8..000000000000 --- a/fuzz/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Fuzz Testing for libbitcoinpqc - -This directory contains fuzz testing for the libbitcoinpqc library using [cargo-fuzz](https://github.com/rust-fuzz/cargo-fuzz). - -## Prerequisites - -You need to have cargo-fuzz installed: - -``` -cargo install cargo-fuzz -``` - -## Available Fuzz Targets - -1. **`keypair_generation`** - Tests key pair generation with different algorithms using fuzzed randomness. -2. **`sign_verify`** - Tests signature creation and verification using generated keys and fuzzed messages. -3. **`cross_algorithm`** - Tests verification with mismatched keys and signatures from different algorithms. -4. **`key_parsing`** - Tests parsing of arbitrary byte sequences into `PublicKey` and `SecretKey` structs across algorithms. -5. **`signature_parsing`** - Tests parsing of arbitrary byte sequences into `Signature` structs across algorithms. - -## Running the Fuzz Tests - -To run a specific fuzz target: - -```bash -cargo fuzz run keypair_generation -cargo fuzz run sign_verify -cargo fuzz run cross_algorithm -cargo fuzz run key_parsing -cargo fuzz run signature_parsing -``` - -To run a fuzz target for a specific amount of time: - -```bash -cargo fuzz run keypair_generation -- -max_total_time=60 -``` - -To run a fuzz target with a specific number of iterations: - -```bash -cargo fuzz run keypair_generation -- -runs=1000000 -``` - -To run **all** fuzz targets sequentially, use the provided script (make sure it's executable: `chmod +x fuzz/run_all_fuzzers.sh`): - -```bash -./fuzz/run_all_fuzzers.sh -``` - -This script will iterate through all defined targets **in parallel** using **GNU Parallel**. -If you don't have GNU Parallel installed, the script will output an error. You can install it using your system's package manager: - -- **Debian/Ubuntu:** `sudo apt update && sudo apt install parallel` -- **Fedora:** `sudo dnf install parallel` -- **Arch Linux:** `sudo pacman -S parallel` -- **macOS (Homebrew):** `brew install parallel` - -## Corpus Management - -Cargo-fuzz automatically manages a corpus of interesting inputs. You can find them in the `fuzz/corpus` directory once you've run the fuzz tests. - -## Finding and Reporting Issues - -If a fuzz test finds a crash, it will save the crashing input to `fuzz/artifacts`. You can reproduce the crash with: - -``` -cargo fuzz run target_name fuzz/artifacts/target_name/crash-* -``` - -When reporting an issue found by fuzzing, please include: - -1. The exact command used to run the fuzzer -2. The crash input file -3. The full output of the crash - -## Adding New Fuzz Targets - -To add a new fuzz target: - -1. Create a new Rust file in the `fuzz_targets` directory -2. Add the target to `fuzz/Cargo.toml` -3. Run the new target with `cargo fuzz run target_name` diff --git a/fuzz/artifacts/sign_verify/crash-256ac14220a2ca53e6006f2ed7f036b98864e08a b/fuzz/artifacts/sign_verify/crash-256ac14220a2ca53e6006f2ed7f036b98864e08a deleted file mode 100644 index 2939dba8158241452cdb1e259812683fbb966548..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 zcmZQzcn^e(?-{`0{rej*@E;9CK*4MVB#9e0c7gy*4;p;|#D9-uCYn4@3L9W#0E==1 E09y-qrvLx| diff --git a/fuzz/fuzz_targets/cross_algorithm_fuzz.rs b/fuzz/fuzz_targets/cross_algorithm_fuzz.rs deleted file mode 100644 index a79806c27569..000000000000 --- a/fuzz/fuzz_targets/cross_algorithm_fuzz.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![no_main] - -use bitcoinpqc::{generate_keypair, sign, verify, Algorithm, Signature}; -use libfuzzer_sys::fuzz_target; - -fuzz_target!(|data: &[u8]| { - if data.len() < 150 { - // Need sufficient bytes for all operations - return; - } - - // Use first 128 bytes for key generation - let key_data = &data[0..128]; - - // Generate two keypairs with different algorithms - let alg1 = Algorithm::SECP256K1_SCHNORR; - let alg2 = Algorithm::ML_DSA_44; - - let keypair1 = match generate_keypair(alg1, key_data) { - Ok(kp) => kp, - Err(_) => return, // Skip if key generation fails - }; - - let keypair2 = match generate_keypair(alg2, key_data) { - Ok(kp) => kp, - Err(_) => return, // Skip if key generation fails - }; - - // Use remaining bytes as message to sign - let message = &data[128..]; - - // Sign with both keys - let signature1 = match sign(&keypair1.secret_key, message) { - Ok(sig) => sig, - Err(_) => return, // Skip if signing fails - }; - - let signature2 = match sign(&keypair2.secret_key, message) { - Ok(sig) => sig, - Err(_) => return, // Skip if signing fails - }; - - // Try to verify with correct key-signature pairs (should succeed) - let _ = verify(&keypair1.public_key, message, &signature1); - let _ = verify(&keypair2.public_key, message, &signature2); - - // Now try incorrect combinations (should fail) - - // Case 1: Use signature1 with public key2 - let sig1_with_wrong_alg = Signature { - algorithm: keypair2.public_key.algorithm, - bytes: signature1.bytes.clone(), - }; - let _ = verify(&keypair2.public_key, message, &sig1_with_wrong_alg); - - // Case 2: Use signature2 with public key1 - let sig2_with_wrong_alg = Signature { - algorithm: keypair1.public_key.algorithm, - bytes: signature2.bytes.clone(), - }; - let _ = verify(&keypair1.public_key, message, &sig2_with_wrong_alg); - - // Case 3: Use original signatures but with the wrong public key - let _ = verify(&keypair1.public_key, message, &signature2); - let _ = verify(&keypair2.public_key, message, &signature1); -}); diff --git a/fuzz/fuzz_targets/key_parsing_fuzz.rs b/fuzz/fuzz_targets/key_parsing_fuzz.rs deleted file mode 100644 index ea4f3a46abf0..000000000000 --- a/fuzz/fuzz_targets/key_parsing_fuzz.rs +++ /dev/null @@ -1,40 +0,0 @@ -#![no_main] - -use bitcoinpqc::{algorithm_from_index, PublicKey, SecretKey}; -use libfuzzer_sys::fuzz_target; - -const NUM_ALGORITHMS: u8 = 3; // SECP256K1_SCHNORR, ML_DSA_44, SLH_DSA_128S - -fuzz_target!(|data: &[u8]| { - if data.len() < 2 { - // Need at least 2 bytes: 1 for algorithm, 1+ for key data - return; - } - - // First byte selects algorithm - let alg_byte = data[0]; - let algorithm = algorithm_from_index(alg_byte); - - // Rest of the data is treated as a potential key - let key_data = &data[1..]; - - // Try to interpret this as a secret key - // The key_parsing should correctly validate this without crashing - let sk_result = SecretKey::try_from_slice(algorithm, key_data); - if key_data.len() == bitcoinpqc::secret_key_size(algorithm) { - // If length matches, it should parse correctly - // (assuming bytewise validation passes) - let _ = sk_result.unwrap_or_else(|_| { - panic!( - "Secret key parsing failed! Algorithm: {}", - algorithm.debug_name() - ) - }); - } else { - // Otherwise it should return an error - assert!( - sk_result.is_err(), - "Parsing should fail for invalid key length!" - ); - } -}); diff --git a/fuzz/fuzz_targets/keypair_generation_fuzz.rs b/fuzz/fuzz_targets/keypair_generation_fuzz.rs deleted file mode 100644 index 2344ad2a4239..000000000000 --- a/fuzz/fuzz_targets/keypair_generation_fuzz.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![no_main] - -use bitcoinpqc::{algorithm_from_index, generate_keypair}; -use libfuzzer_sys::fuzz_target; - -fuzz_target!(|data: &[u8]| { - if data.len() < 130 { - // Need at least 1 byte for algorithm + 129 bytes for key seed - return; - } - - // First byte selects algorithm - let alg_byte = data[0]; - let algorithm = algorithm_from_index(alg_byte); - - // Rest is key generation data - let key_data = &data[1..]; // Should be 129+ bytes - - // Try to generate a keypair - let keypair_result = generate_keypair(algorithm, key_data); - assert!( - keypair_result.is_ok(), - "Keypair generation failed! Algorithm: {}", - algorithm.debug_name() - ); - let _keypair = keypair_result.unwrap(); - // Success! -}); diff --git a/fuzz/fuzz_targets/sign_verify_fuzz.rs b/fuzz/fuzz_targets/sign_verify_fuzz.rs deleted file mode 100644 index a8b11569ce5c..000000000000 --- a/fuzz/fuzz_targets/sign_verify_fuzz.rs +++ /dev/null @@ -1,77 +0,0 @@ -#![no_main] - -use bitcoinpqc::{algorithm_from_index, generate_keypair, sign, verify}; -use libfuzzer_sys::fuzz_target; - -fuzz_target!(|data: &[u8]| { - // Need sufficient bytes for all operations: - // 1 byte for algorithm + 128 bytes for key generation + 32 bytes for message (Secp256k1 requires 32) - if data.len() < 1 + 128 + 32 { - return; - } - - // Use first byte to select an algorithm - let alg_byte = data[0]; - let algorithm = algorithm_from_index(alg_byte); - - // Use 128 bytes for key generation - let key_data = &data[1..129]; - - // Try to generate a keypair - let keypair_result = generate_keypair(algorithm, key_data); - if let Err(err) = &keypair_result { - panic!( - "Key generation failed for algorithm: {}, error: {:?}", - algorithm.debug_name(), - err - ); - } - let keypair = keypair_result.unwrap(); - - // Use remaining bytes as message to sign - // We've already checked above that we have at least 32 bytes left - let message = &data[129..]; - - // Try to sign the message - let signature_result = sign(&keypair.secret_key, message); - if let Err(err) = &signature_result { - panic!( - "Signing failed for algorithm: {}, error: {:?}", - algorithm.debug_name(), - err - ); - } - let signature = signature_result.unwrap(); - - // Try to verify the signature with the correct public key - let verify_result = verify(&keypair.public_key, message, &signature); - if let Err(err) = &verify_result { - panic!("Verification failed for a signature generated with the corresponding private key! Algorithm: {}, error: {:?}", - algorithm.debug_name(), err); - } - - // Also try some invalid cases (if we have a valid signature) - if message.len() > 1 { - // Try with modified message - let mut modified_msg = message.to_vec(); - modified_msg[0] ^= 0xFF; // Flip bits in first byte - let verify_result_bad_msg = verify(&keypair.public_key, &modified_msg, &signature); - assert!( - verify_result_bad_msg.is_err(), - "Verification should fail with modified message! Algorithm: {}", - algorithm.debug_name() - ); - } - - if signature.bytes.len() > 1 { - // Try with modified signature - let mut modified_sig = signature.clone(); - modified_sig.bytes[0] ^= 0xFF; // Flip bits in first byte - let verify_result_bad_sig = verify(&keypair.public_key, message, &modified_sig); - assert!( - verify_result_bad_sig.is_err(), - "Verification should fail with modified signature! Algorithm: {}", - algorithm.debug_name() - ); - } -}); diff --git a/fuzz/fuzz_targets/signature_parsing_fuzz.rs b/fuzz/fuzz_targets/signature_parsing_fuzz.rs deleted file mode 100644 index 8ab27e97821c..000000000000 --- a/fuzz/fuzz_targets/signature_parsing_fuzz.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![no_main] - -use bitcoinpqc::{algorithm_from_index, Signature}; -use libfuzzer_sys::fuzz_target; - -const NUM_ALGORITHMS: u8 = 3; // SECP256K1_SCHNORR, ML_DSA_44, SLH_DSA_128S - -fuzz_target!(|data: &[u8]| { - if data.is_empty() { - return; // Need at least one byte for algorithm selection - } - - // Use first byte to select an algorithm - let alg_byte = data[0]; - let algorithm = algorithm_from_index(alg_byte); - - // Use remaining bytes as potential signature data - let sig_data = &data[1..]; - - // Attempt to parse as Signature - let _ = Signature::try_from_slice(algorithm, sig_data); -}); diff --git a/fuzz/output.txt b/fuzz/output.txt deleted file mode 100644 index cb627d55ad77..000000000000 --- a/fuzz/output.txt +++ /dev/null @@ -1,176 +0,0 @@ -/fuzz/run_all_fuzzers.sh 9.1s  Fri Apr 25 10:46:23 2025 -Running all fuzz targets in parallel: keypair_generation sign_verify cross_algorithm key_parsing signature_parsing ---- Starting fuzzer: cross_algorithm --- ---- Starting fuzzer: keypair_generation --- ---- Starting fuzzer: sign_verify --- ---- Starting fuzzer: key_parsing --- ---- Starting fuzzer: signature_parsing --- - Running `fuzz/target/x86_64-unknown-linux-gnu/release/cross_algorithm -artifact_prefix=/home/hunter/Projects/pqc/libbitcoinpqc/fuzz/artifacts/cross_algorithm/ /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/cross_algorithm` -INFO: Running with entropic power schedule (0xFF, 100). -INFO: Seed: 2416094420 -INFO: Loaded 1 modules (21002 inline 8-bit counters): 21002 [0x5c4378f253f0, 0x5c4378f2a5fa), -INFO: Loaded 1 PC tables (21002 PCs): 21002 [0x5c4378f2a600,0x5c4378f7c6a0), -INFO: 0 files found in /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/cross_algorithm -INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes -INFO: A corpus is not provided, starting from an empty corpus -#2 INITED cov: 19 ft: 20 corp: 1/1b exec/s: 0 rss: 48Mb - Finished `release` profile [optimized + debuginfo] target(s) in 2.69s - Finished `release` profile [optimized + debuginfo] target(s) in 1.18s - Running `fuzz/target/x86_64-unknown-linux-gnu/release/keypair_generation -artifact_prefix=/home/hunter/Projects/pqc/libbitcoinpqc/fuzz/artifacts/keypair_generation/ /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/keypair_generation` -INFO: Running with entropic power schedule (0xFF, 100). -INFO: Seed: 2420079927 -INFO: Loaded 1 modules (20737 inline 8-bit counters): 20737 [0x604bb8a91270, 0x604bb8a96371), -INFO: Loaded 1 PC tables (20737 PCs): 20737 [0x604bb8a96378,0x604bb8ae7388), -INFO: 4 files found in /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/keypair_generation -INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes -INFO: seed corpus: files: 4 min: 129b max: 129b total: 516b rss: 47Mb - Finished `release` profile [optimized + debuginfo] target(s) in 1.19s - Running `fuzz/target/x86_64-unknown-linux-gnu/release/sign_verify -artifact_prefix=/home/hunter/Projects/pqc/libbitcoinpqc/fuzz/artifacts/sign_verify/ /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/sign_verify` -INFO: Running with entropic power schedule (0xFF, 100). -INFO: Seed: 2427464392 -INFO: Loaded 1 modules (20974 inline 8-bit counters): 20974 [0x63f5c0000430, 0x63f5c000561e), -INFO: Loaded 1 PC tables (20974 PCs): 20974 [0x63f5c0005620,0x63f5c0057500), -INFO: 0 files found in /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/sign_verify -INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes -INFO: A corpus is not provided, starting from an empty corpus -#2 INITED cov: 19 ft: 20 corp: 1/1b exec/s: 0 rss: 45Mb - Finished `release` profile [optimized + debuginfo] target(s) in 0.56s - Running `fuzz/target/x86_64-unknown-linux-gnu/release/key_parsing -artifact_prefix=/home/hunter/Projects/pqc/libbitcoinpqc/fuzz/artifacts/key_parsing/ /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/key_parsing` -INFO: Running with entropic power schedule (0xFF, 100). -INFO: Seed: 2432138094 -INFO: Loaded 1 modules (20738 inline 8-bit counters): 20738 [0x645adaae9270, 0x645adaaee372), -INFO: Loaded 1 PC tables (20738 PCs): 20738 [0x645adaaee378,0x645adab3f398), -INFO: 0 files found in /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/key_parsing -INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes -INFO: A corpus is not provided, starting from an empty corpus -#2 INITED cov: 37 ft: 38 corp: 1/1b exec/s: 0 rss: 45Mb -#4 NEW cov: 39 ft: 40 corp: 2/2b lim: 4 exec/s: 0 rss: 45Mb L: 1/1 MS: 2 ShuffleBytes-ChangeByte- -#15 NEW cov: 41 ft: 42 corp: 3/4b lim: 4 exec/s: 0 rss: 45Mb L: 2/2 MS: 1 InsertByte- -#21 NEW cov: 43 ft: 44 corp: 4/6b lim: 4 exec/s: 0 rss: 45Mb L: 2/2 MS: 1 ChangeBinInt- -#138 REDUCE cov: 43 ft: 44 corp: 4/5b lim: 4 exec/s: 0 rss: 47Mb L: 1/2 MS: 2 ShuffleBytes-EraseBytes- -#375 REDUCE cov: 43 ft: 44 corp: 4/4b lim: 6 exec/s: 0 rss: 47Mb L: 1/1 MS: 2 ShuffleBytes-EraseBytes- -#680 REDUCE cov: 44 ft: 45 corp: 5/12b lim: 8 exec/s: 0 rss: 47Mb L: 8/8 MS: 5 InsertRepeatedBytes-EraseBytes-InsertByte-ChangeByte-CrossOver- -#3550 REDUCE cov: 50 ft: 51 corp: 6/45b lim: 33 exec/s: 0 rss: 48Mb L: 33/33 MS: 5 CopyPart-ChangeByte-CopyPart-InsertRepeatedBytes-CrossOver- - Finished `release` profile [optimized + debuginfo] target(s) in 0.02s - Running `fuzz/target/x86_64-unknown-linux-gnu/release/signature_parsing -artifact_prefix=/home/hunter/Projects/pqc/libbitcoinpqc/fuzz/artifacts/signature_parsing/ /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/signature_parsing` -INFO: Running with entropic power schedule (0xFF, 100). -INFO: Seed: 2512484958 -INFO: Loaded 1 modules (20712 inline 8-bit counters): 20712 [0x563d379d6270, 0x563d379db358), -INFO: Loaded 1 PC tables (20712 PCs): 20712 [0x563d379db358,0x563d37a2c1d8), -INFO: 0 files found in /home/hunter/Projects/pqc/libbitcoinpqc/fuzz/corpus/signature_parsing -INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes -INFO: A corpus is not provided, starting from an empty corpus -#2 INITED cov: 28 ft: 29 corp: 1/1b exec/s: 0 rss: 45Mb -#6 NEW cov: 29 ft: 30 corp: 2/3b lim: 4 exec/s: 0 rss: 45Mb L: 2/2 MS: 4 ShuffleBytes-CopyPart-ShuffleBytes-ChangeByte- -#20 NEW cov: 30 ft: 31 corp: 3/7b lim: 4 exec/s: 0 rss: 47Mb L: 4/4 MS: 4 CrossOver-CopyPart-CMP-ChangeBinInt- DE: "\377\377"- -#31 NEW cov: 31 ft: 32 corp: 4/9b lim: 4 exec/s: 0 rss: 47Mb L: 2/4 MS: 1 InsertByte- -#123 REDUCE cov: 31 ft: 32 corp: 4/8b lim: 4 exec/s: 0 rss: 47Mb L: 1/4 MS: 2 ChangeBinInt-EraseBytes- -#180 REDUCE cov: 31 ft: 32 corp: 4/7b lim: 4 exec/s: 0 rss: 47Mb L: 3/3 MS: 2 ShuffleBytes-EraseBytes- -#191 REDUCE cov: 31 ft: 32 corp: 4/6b lim: 4 exec/s: 0 rss: 47Mb L: 1/3 MS: 1 EraseBytes- -#200 REDUCE cov: 31 ft: 32 corp: 4/5b lim: 4 exec/s: 0 rss: 47Mb L: 2/2 MS: 4 CrossOver-CopyPart-ChangeBit-EraseBytes- -#379 REDUCE cov: 31 ft: 32 corp: 4/4b lim: 4 exec/s: 0 rss: 47Mb L: 1/1 MS: 4 CMP-ShuffleBytes-ChangeBit-EraseBytes- DE: "\001\000"- -#830 REDUCE cov: 32 ft: 33 corp: 5/12b lim: 8 exec/s: 0 rss: 48Mb L: 8/8 MS: 1 InsertRepeatedBytes- -#6967 REDUCE cov: 37 ft: 38 corp: 6/77b lim: 68 exec/s: 0 rss: 48Mb L: 65/65 MS: 2 CopyPart-InsertRepeatedBytes- -#5 INITED cov: 41 ft: 42 corp: 4/516b exec/s: 0 rss: 52Mb -#21 NEW cov: 42 ft: 44 corp: 5/615b lim: 129 exec/s: 0 rss: 52Mb L: 99/129 MS: 1 EraseBytes- - NEW_FUNC[1/4]: 0x5c4378b045e0 in core::ptr::drop_in_place$LT$bitcoinpqc..SecretKey$GT$::h6059cf8040e36a38 /home/hunter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:524 -#47 REDUCE cov: 42 ft: 44 corp: 5/605b lim: 129 exec/s: 0 rss: 52Mb L: 89/129 MS: 1 EraseBytes- -#52 REDUCE cov: 42 ft: 44 corp: 5/585b lim: 129 exec/s: 0 rss: 52Mb L: 69/129 MS: 5 InsertByte-ShuffleBytes-CrossOver-ChangeBinInt-EraseBytes- - NEW_FUNC[1/1]: 0x645ada745ee0 in _$LT$bitcoinpqc..SecretKey$u20$as$u20$core..ops..drop..Drop$GT$::drop::hfd0245cc145361e9 /home/hunter/Projects/pqc/libbitcoinpqc/src/lib.rs:274 -#3691 NEW cov: 58 ft: 59 corp: 7/78b lim: 33 exec/s: 0 rss: 48Mb L: 33/33 MS: 1 CrossOver- -#3744 NEW cov: 60 ft: 61 corp: 8/111b lim: 33 exec/s: 0 rss: 48Mb L: 33/33 MS: 3 ShuffleBytes-ChangeBinInt-ChangeByte- -#7342 NEW cov: 63 ft: 64 corp: 9/176b lim: 68 exec/s: 0 rss: 48Mb L: 65/65 MS: 3 CMP-CrossOver-InsertByte- DE: "\001\000"- - NEW_FUNC[2/4]: 0x5c4378b80ee0 in _$LT$bitcoinpqc..SecretKey$u20$as$u20$core..ops..drop..Drop$GT$::drop::hfd0245cc145361e9 /home/hunter/Projects/pqc/libbitcoinpqc/src/lib.rs:274 -#16437 NEW cov: 55 ft: 57 corp: 2/158b lim: 163 exec/s: 0 rss: 50Mb L: 157/157 MS: 5 CopyPart-CopyPart-InsertRepeatedBytes-InsertRepeatedBytes-CMP- DE: "\377\377\377\377\377\377\377z"- - NEW_FUNC[1/2]: 0x5c4378b07bb0 in _$LT$alloc..vec..Vec$LT$T$C$A$GT$$u20$as$u20$core..clone..Clone$GT$::clone::hc345d965bd3841bb /home/hunter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3318 - NEW_FUNC[2/2]: 0x5c4378b848d0 in bitcoinpqc::verify::h33067318d4f4719c /home/hunter/Projects/pqc/libbitcoinpqc/src/lib.rs:561 -#16438 NEW cov: 92 ft: 99 corp: 3/315b lim: 163 exec/s: 0 rss: 52Mb L: 157/157 MS: 1 ChangeASCIIInt- -#29236 NEW cov: 64 ft: 65 corp: 10/209b lim: 285 exec/s: 0 rss: 50Mb L: 33/65 MS: 4 ShuffleBytes-ChangeBit-InsertRepeatedBytes-CrossOver- -#16486 REDUCE cov: 92 ft: 99 corp: 3/311b lim: 163 exec/s: 0 rss: 56Mb L: 153/157 MS: 3 CopyPart-EraseBytes-PersAutoDict- DE: "\377\377\377\377\377\377\377z"- -#16574 REDUCE cov: 92 ft: 99 corp: 3/308b lim: 163 exec/s: 16574 rss: 60Mb L: 150/157 MS: 3 InsertByte-EraseBytes-InsertRepeatedBytes- -#90 REDUCE cov: 42 ft: 44 corp: 5/583b lim: 129 exec/s: 90 rss: 52Mb L: 67/129 MS: 3 CMP-ChangeBinInt-EraseBytes- DE: "\377\377\377\377"- -#92 REDUCE cov: 42 ft: 44 corp: 5/540b lim: 129 exec/s: 92 rss: 52Mb L: 24/129 MS: 2 CMP-CrossOver- DE: "\377\377\377\377\377\377\377\377"- -#123 REDUCE cov: 42 ft: 44 corp: 5/537b lim: 129 exec/s: 123 rss: 52Mb L: 21/129 MS: 1 EraseBytes- -#125 REDUCE cov: 42 ft: 44 corp: 5/528b lim: 129 exec/s: 125 rss: 52Mb L: 12/129 MS: 2 CMP-EraseBytes- DE: "\000\000\000\000\000\000\000f"- -#146 REDUCE cov: 42 ft: 44 corp: 5/522b lim: 129 exec/s: 146 rss: 52Mb L: 6/129 MS: 1 EraseBytes- - NEW_FUNC[1/6]: 0x63f5bfbe05e0 in core::ptr::drop_in_place$LT$bitcoinpqc..SecretKey$GT$::hbe70475d19333e6a /home/hunter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:524 - NEW_FUNC[2/6]: 0x63f5bfbe3bb0 in _$LT$alloc..vec..Vec$LT$T$C$A$GT$$u20$as$u20$core..clone..Clone$GT$::clone::hfa906a19917719ff /home/hunter/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/alloc/src/vec/mod.rs:3318 -#15631 NEW cov: 71 ft: 73 corp: 2/157b lim: 156 exec/s: 15631 rss: 49Mb L: 156/156 MS: 4 ChangeByte-InsertRepeatedBytes-InsertRepeatedBytes-CopyPart- -#163 REDUCE cov: 42 ft: 44 corp: 5/520b lim: 129 exec/s: 81 rss: 52Mb L: 4/129 MS: 2 ShuffleBytes-EraseBytes- -#1048576 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 524288 rss: 163Mb -#256 pulse cov: 42 ft: 44 corp: 5/520b lim: 129 exec/s: 85 rss: 53Mb -#264 REDUCE cov: 42 ft: 44 corp: 5/518b lim: 129 exec/s: 88 rss: 53Mb L: 2/129 MS: 1 EraseBytes- -#265 REDUCE cov: 42 ft: 44 corp: 5/517b lim: 129 exec/s: 88 rss: 53Mb L: 1/129 MS: 1 EraseBytes- -#2097152 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 699050 rss: 245Mb -#2097152 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 419430 rss: 277Mb -#4194304 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 599186 rss: 444Mb -#512 pulse cov: 42 ft: 44 corp: 5/517b lim: 129 exec/s: 73 rss: 53Mb -#4194304 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 466033 rss: 510Mb -#1024 pulse cov: 42 ft: 44 corp: 5/517b lim: 136 exec/s: 93 rss: 56Mb -#8388608 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 559240 rss: 560Mb -#15674 REDUCE cov: 71 ft: 73 corp: 2/153b lim: 156 exec/s: 979 rss: 52Mb L: 152/152 MS: 3 ChangeBit-ChangeBinInt-EraseBytes- -#8388608 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 441505 rss: 524Mb -#2048 pulse cov: 42 ft: 44 corp: 5/517b lim: 143 exec/s: 81 rss: 60Mb -#16777216 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 559240 rss: 561Mb -#16777216 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 453438 rss: 524Mb -#15781 REDUCE cov: 75 ft: 77 corp: 3/305b lim: 156 exec/s: 292 rss: 53Mb L: 152/152 MS: 2 CopyPart-CMP- DE: "\261\036\000\000\000\000\000\000"- -#32768 pulse cov: 92 ft: 99 corp: 3/308b lim: 317 exec/s: 595 rss: 367Mb -#4096 pulse cov: 42 ft: 44 corp: 5/517b lim: 164 exec/s: 71 rss: 72Mb -#33554432 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 559240 rss: 561Mb -^[[2~#33554432 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 453438 rss: 524Mb -#15893 REDUCE cov: 75 ft: 77 corp: 3/303b lim: 156 exec/s: 209 rss: 55Mb L: 150/152 MS: 2 CrossOver-InsertRepeatedBytes- -#16096 REDUCE cov: 75 ft: 77 corp: 3/302b lim: 156 exec/s: 149 rss: 59Mb L: 151/151 MS: 3 CopyPart-ChangeByte-CrossOver- -#67108864 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 559240 rss: 561Mb -#8192 pulse cov: 42 ft: 44 corp: 5/517b lim: 206 exec/s: 60 rss: 95Mb -#67108864 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 453438 rss: 525Mb -#65536 pulse cov: 92 ft: 99 corp: 3/308b lim: 643 exec/s: 383 rss: 368Mb -#16316 REDUCE cov: 75 ft: 77 corp: 3/301b lim: 156 exec/s: 91 rss: 67Mb L: 150/150 MS: 5 CrossOver-ChangeByte-ChangeBinInt-EraseBytes-CopyPart- -#16384 pulse cov: 75 ft: 77 corp: 3/301b lim: 156 exec/s: 84 rss: 69Mb -#134217728 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 559240 rss: 561Mb -#16384 pulse cov: 42 ft: 44 corp: 5/517b lim: 286 exec/s: 57 rss: 141Mb -#16817 REDUCE cov: 79 ft: 81 corp: 4/451b lim: 156 exec/s: 57 rss: 86Mb L: 150/150 MS: 1 ChangeByte- -#134217728 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 451911 rss: 525Mb -#131072 pulse cov: 92 ft: 99 corp: 3/308b lim: 1300 exec/s: 325 rss: 368Mb -#17749 NEW cov: 82 ft: 85 corp: 5/602b lim: 163 exec/s: 39 rss: 112Mb L: 151/151 MS: 2 ChangeBit-InsertByte- -#268435456 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 556920 rss: 561Mb -#18271 REDUCE cov: 82 ft: 85 corp: 5/601b lim: 163 exec/s: 36 rss: 124Mb L: 150/150 MS: 2 CrossOver-EraseBytes- -#32768 pulse cov: 42 ft: 44 corp: 5/517b lim: 446 exec/s: 56 rss: 241Mb -#268435456 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 451152 rss: 526Mb -#262144 pulse cov: 92 ft: 99 corp: 3/308b lim: 2600 exec/s: 302 rss: 368Mb -#536870912 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 556342 rss: 561Mb -#536870912 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 451911 rss: 527Mb -#65536 pulse cov: 42 ft: 44 corp: 5/517b lim: 770 exec/s: 54 rss: 377Mb -#524288 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 291 rss: 369Mb -#1073741824 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 556631 rss: 561Mb -#1073741824 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 451531 rss: 527Mb -#131072 pulse cov: 42 ft: 44 corp: 5/517b lim: 1421 exec/s: 52 rss: 379Mb -#32768 pulse cov: 82 ft: 85 corp: 5/601b lim: 301 exec/s: 13 rss: 370Mb -#1048576 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 283 rss: 369Mb -#2147483648 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 554189 rss: 563Mb -#2147483648 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 447485 rss: 528Mb -#262144 pulse cov: 42 ft: 44 corp: 5/517b lim: 2733 exec/s: 50 rss: 379Mb -#65536 pulse cov: 82 ft: 85 corp: 5/601b lim: 625 exec/s: 8 rss: 373Mb -#2097152 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 275 rss: 370Mb -#4294967296 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 542156 rss: 563Mb -#4294967296 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 436746 rss: 528Mb -#524288 pulse cov: 42 ft: 44 corp: 5/517b lim: 4096 exec/s: 49 rss: 380Mb -#4194304 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 263 rss: 397Mb -#8589934592 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 513260 rss: 563Mb -#131072 pulse cov: 82 ft: 85 corp: 5/601b lim: 1280 exec/s: 7 rss: 397Mb -#8589934592 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 419922 rss: 531Mb -#1048576 pulse cov: 42 ft: 44 corp: 5/517b lim: 4096 exec/s: 48 rss: 382Mb -#8388608 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 263 rss: 397Mb -#17179869184 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 530439 rss: 563Mb -#262144 pulse cov: 82 ft: 85 corp: 5/601b lim: 2589 exec/s: 7 rss: 397Mb -#17179869184 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 422182 rss: 531Mb -#2097152 pulse cov: 42 ft: 44 corp: 5/517b lim: 4096 exec/s: 47 rss: 382Mb -#16777216 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 250 rss: 397Mb -#34359738368 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 492323 rss: 563Mb -#524288 pulse cov: 82 ft: 85 corp: 5/601b lim: 4096 exec/s: 6 rss: 397Mb -#34359738368 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 405913 rss: 531Mb -#4194304 pulse cov: 42 ft: 44 corp: 5/517b lim: 4096 exec/s: 47 rss: 382Mb -#33554432 pulse cov: 92 ft: 99 corp: 3/308b lim: 4096 exec/s: 255 rss: 397Mb -#68719476736 pulse cov: 37 ft: 38 corp: 6/77b lim: 4096 exec/s: 514814 rss: 563Mb -#1048576 pulse cov: 82 ft: 85 corp: 5/601b lim: 4096 exec/s: 6 rss: 397Mb -#68719476736 pulse cov: 64 ft: 65 corp: 10/209b lim: 4096 exec/s: 421643 rss: 531Mb -#8388608 pulse cov: 42 ft: 44 corp: 5/517b lim: 4096 exec/s: 48 rss: 382Mb diff --git a/fuzz/run_all_fuzzers.sh b/fuzz/run_all_fuzzers.sh deleted file mode 100755 index 02bfc2129d95..000000000000 --- a/fuzz/run_all_fuzzers.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -# Exit immediately if a command exits with a non-zero status. -set -e - -# Define the fuzz targets to run (names must match Cargo.toml) -TARGETS="keypair_generation sign_verify cross_algorithm key_parsing signature_parsing" - -echo "Running all fuzz targets in parallel: $TARGETS" - -# Check if GNU Parallel is installed -if ! command -v parallel &> /dev/null -then - echo "Error: GNU Parallel is not installed. Please install it to run fuzzers in parallel." - echo "(e.g., 'sudo apt install parallel' or 'brew install parallel')" - exit 1 -fi - -# Run targets in parallel using GNU Parallel -# -j 0: Run one job per CPU core. Adjust if needed (e.g., -j 4 for 4 cores). -# --line-buffer: Buffer output line by line, helps prevent excessively interleaved output. -# {}: Placeholder for each target name. - -printf "%s\n" $TARGETS | parallel -j 0 --line-buffer \ - 'echo "--- Starting fuzzer: {} ---"; cargo fuzz run "{}"; echo "--- Finished fuzzer: {} ---"' - - -echo "-------------------------------------" -echo "All parallel fuzz jobs launched (may still be running)." diff --git a/nodejs/.gitignore b/nodejs/.gitignore deleted file mode 100644 index 73db82f6b9fa..000000000000 --- a/nodejs/.gitignore +++ /dev/null @@ -1,25 +0,0 @@ -# Node.js -node_modules/ -npm-debug.log -yarn-debug.log -yarn-error.log - -# Build artifacts -dist/ -build/ -*.node - -# Coverage -coverage/ - -# OS specific -.DS_Store -.env - -# IDE specific -.idea/ -.vscode/ -*.swp -*.swo - -c_sources diff --git a/nodejs/README.md b/nodejs/README.md deleted file mode 100644 index 9cec3fc79dab..000000000000 --- a/nodejs/README.md +++ /dev/null @@ -1,167 +0,0 @@ -# BitcoinPQC - NodeJS TypeScript Bindings - -TypeScript bindings for the [libbitcoinpqc](https://github.com/bitcoin/libbitcoinpqc) library, which provides post-quantum cryptographic signature algorithms for use with BIP-360 and the Bitcoin QuBit soft fork. - -## Features - -- Full TypeScript support with typings -- Clean, ergonomic API -- Compatible with NodeJS 16+ -- Works with both PQC algorithms: - - ML-DSA-44 (formerly CRYSTALS-Dilithium) - - SLH-DSA-Shake-128s (formerly SPHINCS+) - -## Installation - -```bash -npm install bitcoinpqc -``` - -### Prerequisites - -This package requires the native `libbitcoinpqc` library to be installed on your system. See the main [libbitcoinpqc README](https://github.com/bitcoin/libbitcoinpqc) for instructions on installing the C library. - -## API Usage - -```typescript -import { Algorithm, generateKeyPair, sign, verify } from 'bitcoinpqc'; -import crypto from 'crypto'; - -// Generate random data for key generation -const randomData = crypto.randomBytes(128); - -// Generate a key pair using ML-DSA-44 (CRYSTALS-Dilithium) -const keypair = generateKeyPair(Algorithm.ML_DSA_44, randomData); - -// Create a message to sign -const message = Buffer.from('Message to sign'); - -// Sign the message deterministically -const signature = sign(keypair.secretKey, message); - -// Verify the signature -verify(keypair.publicKey, message, signature); -// If verification fails, it will throw a PqcError - -// You can also verify using the raw signature bytes -verify(keypair.publicKey, message, signature.bytes); -``` - -## API Reference - -### Enums - -#### `Algorithm` - -```typescript -enum Algorithm { - /** BIP-340 Schnorr + X-Only - Elliptic Curve Digital Signature Algorithm */ - SECP256K1_SCHNORR = 0, - /** ML-DSA-44 (CRYSTALS-Dilithium) - Lattice-based signature scheme */ - ML_DSA_44 = 1, - /** SLH-DSA-Shake-128s (SPHINCS+) - Hash-based signature scheme */ - SLH_DSA_SHAKE_128S = 2 -} -``` - -### Classes - -#### `PublicKey` - -```typescript -class PublicKey { - readonly algorithm: Algorithm; - readonly bytes: Uint8Array; -} -``` - -#### `SecretKey` - -```typescript -class SecretKey { - readonly algorithm: Algorithm; - readonly bytes: Uint8Array; -} -``` - -#### `KeyPair` - -```typescript -class KeyPair { - readonly publicKey: PublicKey; - readonly secretKey: SecretKey; -} -``` - -#### `Signature` - -```typescript -class Signature { - readonly algorithm: Algorithm; - readonly bytes: Uint8Array; -} -``` - -#### `PqcError` - -```typescript -class PqcError extends Error { - readonly code: ErrorCode; - constructor(code: ErrorCode, message?: string); -} - -enum ErrorCode { - OK = 0, - BAD_ARGUMENT = -1, - BAD_KEY = -2, - BAD_SIGNATURE = -3, - NOT_IMPLEMENTED = -4 -} -``` - -### Functions - -#### `publicKeySize(algorithm: Algorithm): number` - -Get the public key size for an algorithm. - -#### `secretKeySize(algorithm: Algorithm): number` - -Get the secret key size for an algorithm. - -#### `signatureSize(algorithm: Algorithm): number` - -Get the signature size for an algorithm. - -#### `generateKeyPair(algorithm: Algorithm, randomData: Uint8Array): KeyPair` - -Generate a key pair for the specified algorithm. The `randomData` must be at least 128 bytes. - -#### `sign(secretKey: SecretKey, message: Uint8Array): Signature` - -Sign a message using the specified secret key. The signature is deterministic based on the message and key. - -#### `verify(publicKey: PublicKey, message: Uint8Array, signature: Signature | Uint8Array): void` - -Verify a signature using the specified public key. Throws a `PqcError` if verification fails. - -## Algorithm Characteristics - -| Algorithm | Public Key Size | Secret Key Size | Signature Size | Security Level | -| ------------------ | --------------- | --------------- | -------------- | -------------- | -| ML-DSA-44 | 1,312 bytes | 2,528 bytes | 2,420 bytes | NIST Level 2 | -| SLH-DSA-Shake-128s | 32 bytes | 64 bytes | 7,856 bytes | NIST Level 1 | - -## Security Notes - -- Random data is required for key generation but not for signing. All signatures are deterministic, based on the message and secret key. -- The implementations are based on reference code from the NIST PQC standardization process and are not production-hardened. -- Care should be taken to securely manage secret keys in applications. - -## BIP-360 Compliance - -This library implements the TypeScript bindings for cryptographic primitives required by [BIP-360](https://github.com/bitcoin/bips/blob/master/bip-0360.mediawiki), which defines the standard for post-quantum resistant signatures in Bitcoin. - -## License - -This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/nodejs/binding.gyp b/nodejs/binding.gyp deleted file mode 100644 index e9d385e63603..000000000000 --- a/nodejs/binding.gyp +++ /dev/null @@ -1,79 +0,0 @@ -{ - "targets": [ - { - "target_name": "bitcoinpqc", - "sources": [ - "src/native/bitcoinpqc_addon.cc", - "src/c_sources/bitcoinpqc.c", - "src/c_sources/ml_dsa/keygen.c", - "src/c_sources/ml_dsa/sign.c", - "src/c_sources/ml_dsa/verify.c", - "src/c_sources/ml_dsa/utils.c", - "src/c_sources/slh_dsa/keygen.c", - "src/c_sources/slh_dsa/sign.c", - "src/c_sources/slh_dsa/verify.c", - "src/c_sources/slh_dsa/utils.c", - "src/c_sources/dilithium_ref/sign.c", - "src/c_sources/dilithium_ref/packing.c", - "src/c_sources/dilithium_ref/polyvec.c", - "src/c_sources/dilithium_ref/poly.c", - "src/c_sources/dilithium_ref/ntt.c", - "src/c_sources/dilithium_ref/reduce.c", - "src/c_sources/dilithium_ref/rounding.c", - "src/c_sources/dilithium_ref/fips202.c", - "src/c_sources/dilithium_ref/symmetric-shake.c", - "src/c_sources/randombytes_custom.c", - "src/c_sources/sphincsplus_ref/address.c", - "src/c_sources/sphincsplus_ref/fors.c", - "src/c_sources/sphincsplus_ref/hash_shake.c", - "src/c_sources/sphincsplus_ref/merkle.c", - "src/c_sources/sphincsplus_ref/sign.c", - "src/c_sources/sphincsplus_ref/thash_shake_simple.c", - "src/c_sources/sphincsplus_ref/utils.c", - "src/c_sources/sphincsplus_ref/utilsx1.c", - "src/c_sources/sphincsplus_ref/wots.c", - "src/c_sources/sphincsplus_ref/wotsx1.c", - "src/c_sources/sphincsplus_ref/fips202.c" - ], - "include_dirs": [ - "=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.10.tgz", - "integrity": "sha512-rRHT8siFIXQrAYOYqZQVsAr8vJ+cBNqcVAY6m5V8/4QqzaPl+zDBe6cLEPRDuNOUf3ww8RfJVlOyQMoSI+5Ang==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.10", - "@babel/types": "^7.26.10", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.26.5.tgz", - "integrity": "sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.5", - "@babel/helper-validator-option": "^7.25.9", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz", - "integrity": "sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.10.tgz", - "integrity": "sha512-6aQR2zGE/QFi8JpDLjUZEPYOs7+mhKXm86VaKFiLP35JQwQb6bwUE+XbvkH0EptsYhbNBSUGaUBLKqxH1xSgsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.10" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", - "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.9.tgz", - "integrity": "sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.26.9", - "@babel/types": "^7.26.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.10.tgz", - "integrity": "sha512-k8NuDrxr0WrPH5Aupqb2LCVURP/S0vBEn5mK6iH+GIYob66U5EtoZvcdudR2jQ4cmTwhEwW1DLB+Yyas9zjF6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/types": "^7.26.10", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.10.tgz", - "integrity": "sha512-emqcG3vHrpxUKTrxcblR36dcrcoRDvKmnL/dCL6ZsHaShW80qxCAcNhzQZrpeM765VzEos+xOi4s+r4IXzTwdQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", - "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", - "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/reporters": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.7.0", - "jest-config": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-resolve-dependencies": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "jest-watcher": "^29.7.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/environment": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", - "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.7.0", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", - "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", - "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/types": "^29.6.3", - "jest-mock": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", - "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^6.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", - "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", - "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", - "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.6.3", - "@jridgewell/trace-mapping": "^0.3.18", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@gar/promisify": "^1.1.3", - "semver": "^7.3.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.8", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", - "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", - "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", - "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/node": { - "version": "20.17.25", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.25.tgz", - "integrity": "sha512-bT+r2haIlplJUYtlZrEanFHdPIZTeiMeh/fSOEbOOfWf9uTn+lg8g0KU6Q3iMgjd9FLuuMAgfCNSkjUbxL6E3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true, - "license": "ISC" - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "dev": true, - "license": "MIT" - }, - "node_modules/babel-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", - "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/transform": "^29.7.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.6.3", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", - "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", - "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-import-attributes": "^7.24.7", - "@babel/plugin-syntax-import-meta": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", - "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "babel-plugin-jest-hoist": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "caniuse-lite": "^1.0.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bs-logger": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-json-stable-stringify": "2.x" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001706", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001706.tgz", - "integrity": "sha512-3ZczoTApMAZwPKYWmwVbQMFpXBDds3/0VciVoUwPUbldlYyVLmRVuRs/PcUZtHpbLRpzzDvrvnFuREsGt6lUug==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", - "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", - "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/create-jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", - "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "prompts": "^2.0.1" - }, - "bin": { - "create-jest": "bin/create-jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/dedent": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", - "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "babel-plugin-macros": "^3.1.0" - }, - "peerDependenciesMeta": { - "babel-plugin-macros": { - "optional": true - } - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/ejs": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", - "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jake": "^10.8.5" - }, - "bin": { - "ejs": "bin/cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.123", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.123.tgz", - "integrity": "sha512-refir3NlutEZqlKaBLK0tzlVLe5P2wDKS7UQt/3SpibizgsRAPOsqQC3ffw1nlv3ze5gjRQZYHoPymgVZkplFA==", - "dev": true, - "license": "ISC" - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "license": "BSD-2-Clause", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/exponential-backoff": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", - "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/filelist": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", - "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "minimatch": "^5.0.1" - } - }, - "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/import-local": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", - "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC" - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jake": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", - "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" - }, - "bin": { - "jake": "bin/cli.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", - "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/types": "^29.6.3", - "import-local": "^3.0.2", - "jest-cli": "^29.7.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", - "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^5.0.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", - "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/expect": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^1.0.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.7.0", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.7.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-config": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", - "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-jest": "^29.7.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-runner": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", - "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", - "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "jest-util": "^29.7.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", - "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-mock": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", - "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.6.3", - "jest-util": "^29.7.0", - "jest-worker": "^29.7.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", - "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", - "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", - "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", - "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-regex-util": "^29.6.3", - "jest-snapshot": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", - "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/console": "^29.7.0", - "@jest/environment": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.7.0", - "jest-environment-node": "^29.7.0", - "jest-haste-map": "^29.7.0", - "jest-leak-detector": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-resolve": "^29.7.0", - "jest-runtime": "^29.7.0", - "jest-util": "^29.7.0", - "jest-watcher": "^29.7.0", - "jest-worker": "^29.7.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", - "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/environment": "^29.7.0", - "@jest/fake-timers": "^29.7.0", - "@jest/globals": "^29.7.0", - "@jest/source-map": "^29.6.3", - "@jest/test-result": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-mock": "^29.7.0", - "jest-regex-util": "^29.6.3", - "jest-resolve": "^29.7.0", - "jest-snapshot": "^29.7.0", - "jest-util": "^29.7.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", - "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.7.0", - "@jest/transform": "^29.7.0", - "@jest/types": "^29.6.3", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.7.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.7.0", - "semver": "^7.5.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", - "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.6.3", - "leven": "^3.1.0", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", - "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.7.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", - "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "jest-util": "^29.7.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.1.6", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "license": "MIT" - }, - "node_modules/node-gyp": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", - "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "dev": true, - "license": "MIT" - }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "dev": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.3.tgz", - "integrity": "sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true, - "license": "ISC" - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", - "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ip-address": "^9.0.5", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-jest": { - "version": "29.2.6", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.6.tgz", - "integrity": "sha512-yTNZVZqc8lSixm+QGVFcPe6+yj7+TWZwIesuOWvfcn4B9bz5x4NDzVCQQjOs7Hfouu36aEqfEbo9Qpo+gq8dDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "bs-logger": "^0.2.6", - "ejs": "^3.1.10", - "fast-json-stable-stringify": "^2.1.0", - "jest-util": "^29.0.0", - "json5": "^2.2.3", - "lodash.memoize": "^4.1.2", - "make-error": "^1.3.6", - "semver": "^7.7.1", - "yargs-parser": "^21.1.1" - }, - "bin": { - "ts-jest": "cli.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" - }, - "peerDependencies": { - "@babel/core": ">=7.0.0-beta.0 <8", - "@jest/transform": "^29.0.0", - "@jest/types": "^29.0.0", - "babel-jest": "^29.0.0", - "jest": "^29.0.0", - "typescript": ">=4.3 <6" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "@jest/transform": { - "optional": true - }, - "@jest/types": { - "optional": true - }, - "babel-jest": { - "optional": true - }, - "esbuild": { - "optional": true - } - } - }, - "node_modules/ts-jest/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, - "license": "MIT" - }, - "node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, - "license": "ISC", - "dependencies": { - "unique-slug": "^3.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", - "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", - "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, - "license": "ISC", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/nodejs/package.json b/nodejs/package.json deleted file mode 100644 index 48003c61e425..000000000000 --- a/nodejs/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "@jbride/bitcoinpqc", - "version": "0.2.9", - "description": "NodeJS TypeScript bindings for Bitcoin PQC library", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "sync-c-sources": "./scripts/sync-c-sources.sh", - "build": "npm run sync-c-sources && tsc -p . && node-gyp rebuild", - "install": "node-gyp rebuild", - "test": "jest", - "prepare": "npm run build", - "examples": "ts-node examples/basic-usage.ts" - }, - "keywords": [ - "bitcoin", - "cryptocurrency", - "post-quantum", - "cryptography", - "signature", - "dilithium", - "sphincs+" - ], - "author": "Hunter Beast ", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/bitcoin/libbitcoinpqc.git", - "directory": "nodejs" - }, - "bugs": { - "url": "https://github.com/bitcoin/libbitcoinpqc/issues" - }, - "homepage": "https://github.com/bitcoin/libbitcoinpqc#readme", - "type": "commonjs", - "devDependencies": { - "@types/jest": "^29.5.12", - "@types/node": "^20.11.30", - "jest": "^29.7.0", - "ts-jest": "^29.1.2", - "ts-node": "^10.9.2", - "typescript": "^5.4.2", - "node-gyp": "^9.0.0" - }, - "dependencies": { - "node-addon-api": "^5.0.0" - }, - "files": [ - "dist", - "README.md", - "binding.gyp", - "tsconfig.json", - "src/native", - "src/c_sources" - ], - "gypfile": true, - "publishConfig": { - "access": "public" - } -} diff --git a/nodejs/scripts/sync-c-sources.sh b/nodejs/scripts/sync-c-sources.sh deleted file mode 100755 index c1b673dbe6df..000000000000 --- a/nodejs/scripts/sync-c-sources.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -# Script to sync C source files from parent directory to src/c_sources -# This should be run before building or publishing the package - -set -e - -echo "Syncing C source files..." - -# Remove existing c_sources directory -rm -rf src/c_sources - -# Create new c_sources directory -mkdir -p src/c_sources - -# Copy C source files -echo "Copying main C source file..." -cp ../src/bitcoinpqc.c src/c_sources/ - -echo "Copying ML-DSA source files..." -cp -r ../src/ml_dsa src/c_sources/ - -echo "Copying SLH-DSA source files..." -cp -r ../src/slh_dsa src/c_sources/ - -echo "Copying Dilithium reference implementation..." -cp -r ../dilithium/ref src/c_sources/dilithium_ref - -echo "Copying SPHINCS+ reference implementation..." -cp -r ../sphincsplus/ref src/c_sources/sphincsplus_ref - -echo "Copying include files..." -cp -r ../include src/c_sources/ - -# Update include paths in C source files -echo "Updating include paths..." -find src/c_sources -name "*.c" -exec sed -i 's|../../dilithium/ref/|../dilithium_ref/|g' {} \; -find src/c_sources -name "*.c" -exec sed -i 's|../../sphincsplus/ref/|../sphincsplus_ref/|g' {} \; -find src/c_sources -name "*.c" -exec sed -i 's|../../include/|../include/|g' {} \; - -echo "C source files synced successfully!" \ No newline at end of file diff --git a/nodejs/src/__tests__/bitcoinpqc.test.ts b/nodejs/src/__tests__/bitcoinpqc.test.ts deleted file mode 100644 index 54f7c7c3f5f0..000000000000 --- a/nodejs/src/__tests__/bitcoinpqc.test.ts +++ /dev/null @@ -1,149 +0,0 @@ -import { - Algorithm, - ErrorCode, - PqcError, - generateKeyPair, - publicKeySize, - secretKeySize, - sign, - signatureSize, - verify, -} from "../index"; - -import { getLibrary, setLibraryForTesting, BitcoinPqcNative } from "../library"; - -describe("Bitcoin PQC", () => { - // Generate random data for tests - function getRandomBytes(size: number): Uint8Array { - const bytes = new Uint8Array(size); - for (let i = 0; i < size; i++) { - bytes[i] = Math.floor(Math.random() * 256); - } - return bytes; - } - - describe("key sizes", () => { - test("should report correct key sizes for each algorithm", () => { - // Test key size reporting functions - for (const algo of [ - Algorithm.SECP256K1_SCHNORR, - Algorithm.ML_DSA_44, - Algorithm.SLH_DSA_SHAKE_128S, - ]) { - expect(publicKeySize(algo)).toBeGreaterThan(0); - expect(secretKeySize(algo)).toBeGreaterThan(0); - expect(signatureSize(algo)).toBeGreaterThan(0); - } - }); - }); - - describe("ML-DSA-44 (Dilithium)", () => { - const algorithm = Algorithm.ML_DSA_44; - - // Skip this test for now - test.skip("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); - - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); - - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); - - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); - - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - - // Verify with raw signature bytes - expect(() => { - verify(keypair.publicKey, message, signature.bytes); - }).not.toThrow(); - - // Verify that the signature doesn't verify for a different message - const badMessage = new TextEncoder().encode("Bad message!"); - expect(() => { - verify(keypair.publicKey, badMessage, signature); - }).toThrow(PqcError); - }); - }); - - describe("SLH-DSA-SHAKE-128s (SPHINCS+)", () => { - const algorithm = Algorithm.SLH_DSA_SHAKE_128S; - - test("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); - - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); - - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); - - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); - - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - }); - }); - - - test("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); - - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); - - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); - - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); - - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - }); -}); - -describe("error conditions", () => { - test("should throw on invalid input", () => { - // Invalid algorithm - expect(() => { - const randomData = getRandomBytes(128); - generateKeyPair(99 as Algorithm, randomData); - }).toThrow(PqcError); - - // Invalid random data size - expect(() => { - const randomData = getRandomBytes(16); // Less than 128 bytes - generateKeyPair(Algorithm.ML_DSA_44, randomData); - }).toThrow(PqcError); - }); -}); -}); diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts deleted file mode 100644 index 9cd25774bccc..000000000000 --- a/nodejs/src/index.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { getLibrary } from "./library"; -import { - Algorithm, - ErrorCode, - KeyPair, - PqcError, - PublicKey, - SecretKey, - Signature, -} from "./types"; - -// Re-export types -export { - Algorithm, - ErrorCode, - KeyPair, - PqcError, - PublicKey, - SecretKey, - Signature, -}; - -/** - * Get the public key size for an algorithm - * - * @param algorithm - The algorithm identifier - * @returns The public key size in bytes - */ -export function publicKeySize(algorithm: Algorithm): number { - return getLibrary().bitcoin_pqc_public_key_size(algorithm); -} - -/** - * Get the secret key size for an algorithm - * - * @param algorithm - The algorithm identifier - * @returns The secret key size in bytes - */ -export function secretKeySize(algorithm: Algorithm): number { - return getLibrary().bitcoin_pqc_secret_key_size(algorithm); -} - -/** - * Get the signature size for an algorithm - * - * @param algorithm - The algorithm identifier - * @returns The signature size in bytes - */ -export function signatureSize(algorithm: Algorithm): number { - return getLibrary().bitcoin_pqc_signature_size(algorithm); -} - -/** - * Generate a key pair for the specified algorithm - * - * @param algorithm - The PQC algorithm to use - * @param randomData - Random bytes for key generation (must be at least 128 bytes) - * @returns A new key pair - * @throws {PqcError} If key generation fails - */ -export function generateKeyPair( - algorithm: Algorithm, - randomData: Uint8Array -): KeyPair { - if (!(randomData instanceof Uint8Array)) { - throw new PqcError( - ErrorCode.BAD_ARGUMENT, - "Random data must be a Uint8Array" - ); - } - - if (randomData.length < 128) { - throw new PqcError( - ErrorCode.BAD_ARGUMENT, - "Random data must be at least 128 bytes" - ); - } - - const lib = getLibrary(); - const result = lib.bitcoin_pqc_keygen(algorithm, randomData); - - if (result.resultCode !== ErrorCode.OK) { - throw new PqcError(result.resultCode); - } - - const publicKey = new PublicKey(algorithm, result.publicKey); - const secretKey = new SecretKey(algorithm, result.secretKey); - - return new KeyPair(publicKey, secretKey); -} - -/** - * Sign a message using the specified secret key - * - * @param secretKey - The secret key to sign with - * @param message - The message to sign - * @returns A signature - * @throws {PqcError} If signing fails - */ -export function sign(secretKey: SecretKey, message: Uint8Array): Signature { - if (!(secretKey instanceof SecretKey)) { - throw new PqcError( - ErrorCode.BAD_ARGUMENT, - "Secret key must be a SecretKey instance" - ); - } - - if (!(message instanceof Uint8Array)) { - throw new PqcError(ErrorCode.BAD_ARGUMENT, "Message must be a Uint8Array"); - } - - const lib = getLibrary(); - const result = lib.bitcoin_pqc_sign( - secretKey.algorithm, - secretKey.bytes, - message - ); - - if (result.resultCode !== ErrorCode.OK) { - throw new PqcError(result.resultCode); - } - - return new Signature(secretKey.algorithm, result.signature); -} - -/** - * Verify a signature using the specified public key - * - * @param publicKey - The public key to verify with - * @param message - The message that was signed - * @param signature - The signature to verify - * @returns {void} - * @throws {PqcError} If verification fails - */ -export function verify( - publicKey: PublicKey, - message: Uint8Array, - signature: Signature | Uint8Array -): void { - if (!(publicKey instanceof PublicKey)) { - throw new PqcError( - ErrorCode.BAD_ARGUMENT, - "Public key must be a PublicKey instance" - ); - } - - if (!(message instanceof Uint8Array)) { - throw new PqcError(ErrorCode.BAD_ARGUMENT, "Message must be a Uint8Array"); - } - - const lib = getLibrary(); - const sigBytes = signature instanceof Signature ? signature.bytes : signature; - - if (!(sigBytes instanceof Uint8Array)) { - throw new PqcError( - ErrorCode.BAD_ARGUMENT, - "Signature must be a Signature or Uint8Array instance" - ); - } - - const result = lib.bitcoin_pqc_verify( - publicKey.algorithm, - publicKey.bytes, - message, - sigBytes - ); - - if (result !== ErrorCode.OK) { - throw new PqcError(result); - } -} diff --git a/nodejs/src/library.ts b/nodejs/src/library.ts deleted file mode 100644 index 4b755174599e..000000000000 --- a/nodejs/src/library.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { join } from "path"; -import { existsSync } from "fs"; -import { Algorithm, ErrorCode } from "./types"; - -// Try to load the native addon -let nativeAddon: any = null; -try { - nativeAddon = require("../build/Release/bitcoinpqc"); - console.log("Loaded native addon successfully"); -} catch (error) { - console.warn("Failed to load native addon:", error); -} - -// Define functions from the native library -export interface BitcoinPqcNative { - // Size information - bitcoin_pqc_public_key_size(algorithm: number): number; - bitcoin_pqc_secret_key_size(algorithm: number): number; - bitcoin_pqc_signature_size(algorithm: number): number; - - // Key generation, signing and verification - bitcoin_pqc_keygen( - algorithm: number, - randomData: Uint8Array - ): { publicKey: Uint8Array; secretKey: Uint8Array; resultCode: number }; - - bitcoin_pqc_sign( - algorithm: number, - secretKey: Uint8Array, - message: Uint8Array - ): { signature: Uint8Array; resultCode: number }; - - bitcoin_pqc_verify( - algorithm: number, - publicKey: Uint8Array, - message: Uint8Array, - signature: Uint8Array - ): number; -} - -interface KeySizeConfig { - publicKey: number; - secretKey: number; - signature: number; -} - -// Mock library implementation as fallback -class MockBitcoinPqcNative implements BitcoinPqcNative { - // These values are from the actual implementation - private keySizes: { [key: number]: KeySizeConfig } = { - [Algorithm.SECP256K1_SCHNORR]: { - publicKey: 32, - secretKey: 32, - signature: 64, - }, - [Algorithm.ML_DSA_44]: { - publicKey: 1312, - secretKey: 2528, - signature: 2420, - }, - [Algorithm.SLH_DSA_SHAKE_128S]: { - publicKey: 32, - secretKey: 64, - signature: 7856, - }, - }; - - bitcoin_pqc_public_key_size(algorithm: number): number { - return this.keySizes[algorithm]?.publicKey || 0; - } - - bitcoin_pqc_secret_key_size(algorithm: number): number { - return this.keySizes[algorithm]?.secretKey || 0; - } - - bitcoin_pqc_signature_size(algorithm: number): number { - return this.keySizes[algorithm]?.signature || 0; - } - - bitcoin_pqc_keygen( - algorithm: number, - randomData: Uint8Array - ): { publicKey: Uint8Array; secretKey: Uint8Array; resultCode: number } { - if (randomData.length < 128) { - return { - publicKey: new Uint8Array(0), - secretKey: new Uint8Array(0), - resultCode: ErrorCode.BAD_ARGUMENT, - }; - } - - if (algorithm < 0 || algorithm > 3) { - return { - publicKey: new Uint8Array(0), - secretKey: new Uint8Array(0), - resultCode: ErrorCode.BAD_ARGUMENT, - }; - } - - const pkSize = this.bitcoin_pqc_public_key_size(algorithm); - const skSize = this.bitcoin_pqc_secret_key_size(algorithm); - - // In a real implementation, this would call the native library - // Here we're just creating dummy keys based on the random data - const publicKey = new Uint8Array(pkSize); - const secretKey = new Uint8Array(skSize); - - // Use random data to populate the key - for (let i = 0; i < pkSize && i < randomData.length; i++) { - publicKey[i] = randomData[i]; - } - - for (let i = 0; i < skSize && i < randomData.length; i++) { - secretKey[i] = randomData[i + Math.floor(randomData.length / 2)]; - } - - return { publicKey, secretKey, resultCode: ErrorCode.OK }; - } - - bitcoin_pqc_sign( - algorithm: number, - secretKey: Uint8Array, - message: Uint8Array - ): { signature: Uint8Array; resultCode: number } { - if (algorithm < 0 || algorithm > 3) { - return { - signature: new Uint8Array(0), - resultCode: ErrorCode.BAD_ARGUMENT, - }; - } - - const expectedSize = this.bitcoin_pqc_secret_key_size(algorithm); - if (secretKey.length !== expectedSize) { - return { signature: new Uint8Array(0), resultCode: ErrorCode.BAD_KEY }; - } - - const sigSize = this.bitcoin_pqc_signature_size(algorithm); - const signature = new Uint8Array(sigSize); - - // In a real implementation, this would call the native library - // Here we're just creating a dummy signature - // In reality, this would be a deterministic signature based on the message and secret key - for (let i = 0; i < sigSize; i++) { - signature[i] = i < message.length ? message[i] : 0; - } - - return { signature, resultCode: ErrorCode.OK }; - } - - bitcoin_pqc_verify( - algorithm: number, - publicKey: Uint8Array, - message: Uint8Array, - signature: Uint8Array - ): number { - if (algorithm < 0 || algorithm > 3) { - return ErrorCode.BAD_ARGUMENT; - } - - const expectedPkSize = this.bitcoin_pqc_public_key_size(algorithm); - if (publicKey.length !== expectedPkSize) { - return ErrorCode.BAD_KEY; - } - - const expectedSigSize = this.bitcoin_pqc_signature_size(algorithm); - if (signature.length !== expectedSigSize) { - return ErrorCode.BAD_SIGNATURE; - } - - // In a real implementation, this would verify the signature - // Here we're just pretending it's valid - return ErrorCode.OK; - } -} - -// Fall back to mock implementation if native addon is not available -const addonOrMock = nativeAddon || new MockBitcoinPqcNative(); - -// Get the library instance -export function getLibrary(): BitcoinPqcNative { - return addonOrMock; -} - -// For testing - allow library to be replaced -export function setLibraryForTesting(mockLib: BitcoinPqcNative): void { - nativeAddon = mockLib; -} diff --git a/nodejs/src/native/bitcoinpqc_addon.cc b/nodejs/src/native/bitcoinpqc_addon.cc deleted file mode 100644 index b8e9c43cecaf..000000000000 --- a/nodejs/src/native/bitcoinpqc_addon.cc +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include - -/** - * Get the public key size for an algorithm - */ -Napi::Value GetPublicKeySize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - size_t size = bitcoin_pqc_public_key_size(static_cast(algorithm)); - - return Napi::Number::New(env, static_cast(size)); -} - -/** - * Get the secret key size for an algorithm - */ -Napi::Value GetSecretKeySize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - size_t size = bitcoin_pqc_secret_key_size(static_cast(algorithm)); - - return Napi::Number::New(env, static_cast(size)); -} - -/** - * Get the signature size for an algorithm - */ -Napi::Value GetSignatureSize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - size_t size = bitcoin_pqc_signature_size(static_cast(algorithm)); - - return Napi::Number::New(env, static_cast(size)); -} - -/** - * Generate a key pair - */ -Napi::Value GenerateKeypair(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array randomData = info[1].As(); - - if (randomData.ByteLength() < 128) { - Napi::Error::New(env, "Random data must be at least 128 bytes").ThrowAsJavaScriptException(); - return env.Null(); - } - - // Set up keypair struct - bitcoin_pqc_keypair_t keypair; - bitcoin_pqc_error_t result = bitcoin_pqc_keygen( - static_cast(algorithm), - &keypair, - randomData.Data(), - randomData.ByteLength() - ); - - // Create result object - Napi::Object returnValue = Napi::Object::New(env); - - // Check for errors - if (result != BITCOIN_PQC_OK) { - returnValue.Set("resultCode", Napi::Number::New(env, static_cast(result))); - returnValue.Set("publicKey", Napi::Uint8Array::New(env, 0)); - returnValue.Set("secretKey", Napi::Uint8Array::New(env, 0)); - return returnValue; - } - - // Copy public key - Napi::Uint8Array publicKey = Napi::Uint8Array::New(env, keypair.public_key_size); - memcpy(publicKey.Data(), keypair.public_key, keypair.public_key_size); - returnValue.Set("publicKey", publicKey); - - // Copy secret key - Napi::Uint8Array secretKey = Napi::Uint8Array::New(env, keypair.secret_key_size); - memcpy(secretKey.Data(), keypair.secret_key, keypair.secret_key_size); - returnValue.Set("secretKey", secretKey); - - // Set result code - returnValue.Set("resultCode", Napi::Number::New(env, 0)); // BITCOIN_PQC_OK - - // Clean up - bitcoin_pqc_keypair_free(&keypair); - - return returnValue; -} - -/** - * Sign a message - */ -Napi::Value SignMessage(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 3 || !info[0].IsNumber() || !info[1].IsTypedArray() || !info[2].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array secretKey = info[1].As(); - Napi::Uint8Array message = info[2].As(); - - // Set up signature struct - bitcoin_pqc_signature_t signature; - bitcoin_pqc_error_t result = bitcoin_pqc_sign( - static_cast(algorithm), - secretKey.Data(), - secretKey.ByteLength(), - message.Data(), - message.ByteLength(), - &signature - ); - - // Create result object - Napi::Object returnValue = Napi::Object::New(env); - - // Check for errors - if (result != BITCOIN_PQC_OK) { - returnValue.Set("resultCode", Napi::Number::New(env, static_cast(result))); - returnValue.Set("signature", Napi::Uint8Array::New(env, 0)); - return returnValue; - } - - // Copy signature - Napi::Uint8Array signatureData = Napi::Uint8Array::New(env, signature.signature_size); - memcpy(signatureData.Data(), signature.signature, signature.signature_size); - returnValue.Set("signature", signatureData); - - // Set result code - returnValue.Set("resultCode", Napi::Number::New(env, 0)); // BITCOIN_PQC_OK - - // Clean up - bitcoin_pqc_signature_free(&signature); - - return returnValue; -} - -/** - * Verify a signature - */ -Napi::Value VerifySignature(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 4 || !info[0].IsNumber() || !info[1].IsTypedArray() || - !info[2].IsTypedArray() || !info[3].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array publicKey = info[1].As(); - Napi::Uint8Array message = info[2].As(); - Napi::Uint8Array signature = info[3].As(); - - // Verify signature - bitcoin_pqc_error_t result = bitcoin_pqc_verify( - static_cast(algorithm), - publicKey.Data(), - publicKey.ByteLength(), - message.Data(), - message.ByteLength(), - signature.Data(), - signature.ByteLength() - ); - - // Return result code - return Napi::Number::New(env, static_cast(result)); -} - -/** - * Initialize the module - */ -Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports.Set("bitcoin_pqc_public_key_size", Napi::Function::New(env, GetPublicKeySize)); - exports.Set("bitcoin_pqc_secret_key_size", Napi::Function::New(env, GetSecretKeySize)); - exports.Set("bitcoin_pqc_signature_size", Napi::Function::New(env, GetSignatureSize)); - exports.Set("bitcoin_pqc_keygen", Napi::Function::New(env, GenerateKeypair)); - exports.Set("bitcoin_pqc_sign", Napi::Function::New(env, SignMessage)); - exports.Set("bitcoin_pqc_verify", Napi::Function::New(env, VerifySignature)); - return exports; -} - -NODE_API_MODULE(bitcoinpqc, Init) diff --git a/nodejs/src/native/bitcoinpqc_wrapper.cc b/nodejs/src/native/bitcoinpqc_wrapper.cc deleted file mode 100644 index 5bfa4b733032..000000000000 --- a/nodejs/src/native/bitcoinpqc_wrapper.cc +++ /dev/null @@ -1,171 +0,0 @@ -#include "bitcoinpqc_wrapper.h" - -Napi::Value GetPublicKeySize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - size_t size = bitcoin_pqc_public_key_size(static_cast(algorithm)); - - return Napi::Number::New(env, static_cast(size)); -} - -Napi::Value GetSecretKeySize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - size_t size = bitcoin_pqc_secret_key_size(static_cast(algorithm)); - - return Napi::Number::New(env, static_cast(size)); -} - -Napi::Value GetSignatureSize(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - size_t size = bitcoin_pqc_signature_size(static_cast(algorithm)); - - return Napi::Number::New(env, static_cast(size)); -} - -Napi::Value GenerateKeypair(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array randomData = info[1].As(); - - if (randomData.ByteLength() < 128) { - Napi::Error::New(env, "Random data must be at least 128 bytes").ThrowAsJavaScriptException(); - return env.Null(); - } - - // Set up keypair struct - bitcoin_pqc_keypair_t keypair; - bitcoin_pqc_error_t result = bitcoin_pqc_keygen( - static_cast(algorithm), - &keypair, - randomData.Data(), - randomData.ByteLength() - ); - - // Check for errors - if (result != BITCOIN_PQC_OK) { - Napi::Error::New(env, "Key generation failed").ThrowAsJavaScriptException(); - return env.Null(); - } - - // Create result object - Napi::Object returnValue = Napi::Object::New(env); - - // Copy public key - Napi::Uint8Array publicKey = Napi::Uint8Array::New(env, keypair.public_key_size); - memcpy(publicKey.Data(), keypair.public_key, keypair.public_key_size); - returnValue.Set("publicKey", publicKey); - - // Copy secret key - Napi::Uint8Array secretKey = Napi::Uint8Array::New(env, keypair.secret_key_size); - memcpy(secretKey.Data(), keypair.secret_key, keypair.secret_key_size); - returnValue.Set("secretKey", secretKey); - - // Set result code - returnValue.Set("resultCode", Napi::Number::New(env, static_cast(result))); - - // Clean up - bitcoin_pqc_keypair_free(&keypair); - - return returnValue; -} - -Napi::Value SignMessage(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 3 || !info[0].IsNumber() || !info[1].IsTypedArray() || !info[2].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array secretKey = info[1].As(); - Napi::Uint8Array message = info[2].As(); - - // Set up signature struct - bitcoin_pqc_signature_t signature; - bitcoin_pqc_error_t result = bitcoin_pqc_sign( - static_cast(algorithm), - secretKey.Data(), - secretKey.ByteLength(), - message.Data(), - message.ByteLength(), - &signature - ); - - // Check for errors - if (result != BITCOIN_PQC_OK) { - Napi::Error::New(env, "Signing failed").ThrowAsJavaScriptException(); - return env.Null(); - } - - // Create result object - Napi::Object returnValue = Napi::Object::New(env); - - // Copy signature - Napi::Uint8Array signatureData = Napi::Uint8Array::New(env, signature.signature_size); - memcpy(signatureData.Data(), signature.signature, signature.signature_size); - returnValue.Set("signature", signatureData); - - // Set result code - returnValue.Set("resultCode", Napi::Number::New(env, static_cast(result))); - - // Clean up - bitcoin_pqc_signature_free(&signature); - - return returnValue; -} - -Napi::Value VerifySignature(const Napi::CallbackInfo& info) { - Napi::Env env = info.Env(); - - if (info.Length() < 4 || !info[0].IsNumber() || !info[1].IsTypedArray() || - !info[2].IsTypedArray() || !info[3].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array publicKey = info[1].As(); - Napi::Uint8Array message = info[2].As(); - Napi::Uint8Array signature = info[3].As(); - - // Verify signature - bitcoin_pqc_error_t result = bitcoin_pqc_verify( - static_cast(algorithm), - publicKey.Data(), - publicKey.ByteLength(), - message.Data(), - message.ByteLength(), - signature.Data(), - signature.ByteLength() - ); - - // Return result code - return Napi::Number::New(env, static_cast(result)); -} diff --git a/nodejs/src/native/bitcoinpqc_wrapper.h b/nodejs/src/native/bitcoinpqc_wrapper.h deleted file mode 100644 index ff7b4b25b5fe..000000000000 --- a/nodejs/src/native/bitcoinpqc_wrapper.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef BITCOINPQC_WRAPPER_H -#define BITCOINPQC_WRAPPER_H - -#include -#include - -// Key size functions -Napi::Value GetPublicKeySize(const Napi::CallbackInfo& info); -Napi::Value GetSecretKeySize(const Napi::CallbackInfo& info); -Napi::Value GetSignatureSize(const Napi::CallbackInfo& info); - -// Key generation, signing and verification -Napi::Value GenerateKeypair(const Napi::CallbackInfo& info); -Napi::Value SignMessage(const Napi::CallbackInfo& info); -Napi::Value VerifySignature(const Napi::CallbackInfo& info); - -#endif diff --git a/nodejs/src/native/mock_bitcoinpqc_addon.cc b/nodejs/src/native/mock_bitcoinpqc_addon.cc deleted file mode 100644 index 9332cc8b517b..000000000000 --- a/nodejs/src/native/mock_bitcoinpqc_addon.cc +++ /dev/null @@ -1,305 +0,0 @@ -#include -#include - -// Mock key sizes -const int SECP256K1_PK_SIZE = 32; -const int SECP256K1_SK_SIZE = 32; -const int SECP256K1_SIG_SIZE = 64; - -const int ML_DSA_44_PK_SIZE = 1312; -const int ML_DSA_44_SK_SIZE = 2528; -const int ML_DSA_44_SIG_SIZE = 2420; - -const int SLH_DSA_SHAKE_128S_PK_SIZE = 32; -const int SLH_DSA_SHAKE_128S_SK_SIZE = 64; -const int SLH_DSA_SHAKE_128S_SIG_SIZE = 7856; - -// Error codes -const int OK = 0; -const int BAD_ARGUMENT = -1; -const int BAD_KEY = -2; -const int BAD_SIGNATURE = -3; -const int NOT_IMPLEMENTED = -4; - -Napi::Value GetPublicKeySize(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - - int size = 0; - switch (algorithm) { - case 0: - size = SECP256K1_PK_SIZE; - break; - case 1: - size = ML_DSA_44_PK_SIZE; - break; - case 2: - size = SLH_DSA_SHAKE_128S_PK_SIZE; - break; - default: - size = 0; - } - - return Napi::Number::New(env, size); -} - -Napi::Value GetSecretKeySize(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - - int size = 0; - switch (algorithm) { - case 0: - size = SECP256K1_SK_SIZE; - break; - case 1: - size = ML_DSA_44_SK_SIZE; - break; - case 2: - size = SLH_DSA_SHAKE_128S_SK_SIZE; - break; - default: - size = 0; - } - - return Napi::Number::New(env, size); -} - -Napi::Value GetSignatureSize(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); - - if (info.Length() < 1 || !info[0].IsNumber()) { - Napi::TypeError::New(env, "Number expected").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - - int size = 0; - switch (algorithm) { - case 0: - size = SECP256K1_SIG_SIZE; - break; - case 1: - size = ML_DSA_44_SIG_SIZE; - break; - case 2: - size = SLH_DSA_SHAKE_128S_SIG_SIZE; - break; - default: - size = 0; - } - - return Napi::Number::New(env, size); -} - -Napi::Value GenerateKeypair(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); - - if (info.Length() < 2 || !info[0].IsNumber() || !info[1].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array randomData = info[1].As(); - - if (randomData.ByteLength() < 128) { - Napi::Error::New(env, "Random data must be at least 128 bytes") - .ThrowAsJavaScriptException(); - return env.Null(); - } - - if (algorithm < 0 || algorithm > 3) { - Napi::Error::New(env, "Invalid algorithm").ThrowAsJavaScriptException(); - return env.Null(); - } - - // Get key sizes - int pkSize = 0; - int skSize = 0; - - switch (algorithm) { - case 0: - pkSize = SECP256K1_PK_SIZE; - skSize = SECP256K1_SK_SIZE; - break; - case 1: - pkSize = ML_DSA_44_PK_SIZE; - skSize = ML_DSA_44_SK_SIZE; - break; - case 2: - pkSize = SLH_DSA_SHAKE_128S_PK_SIZE; - skSize = SLH_DSA_SHAKE_128S_SK_SIZE; - break; - default: - return Napi::Number::New(env, BAD_ARGUMENT); - } - - // Create result object - Napi::Object result = Napi::Object::New(env); - - // Create dummy keys - Napi::Uint8Array publicKey = Napi::Uint8Array::New(env, pkSize); - Napi::Uint8Array secretKey = Napi::Uint8Array::New(env, skSize); - - // Use random data to fill the keys - for (size_t i = 0; i < pkSize && i < randomData.ByteLength(); i++) { - publicKey[i] = randomData[i]; - } - - for (size_t i = 0; i < skSize && i < randomData.ByteLength(); i++) { - secretKey[i] = randomData[i + randomData.ByteLength() / 2]; - } - - result.Set("publicKey", publicKey); - result.Set("secretKey", secretKey); - result.Set("resultCode", OK); - - return result; -} - -Napi::Value SignMessage(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); - - if (info.Length() < 3 || !info[0].IsNumber() || !info[1].IsTypedArray() || - !info[2].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array secretKey = info[1].As(); - Napi::Uint8Array message = info[2].As(); - - if (algorithm < 0 || algorithm > 3) { - Napi::Error::New(env, "Invalid algorithm").ThrowAsJavaScriptException(); - return env.Null(); - } - - // Get expected signature size - int sigSize = 0; - int expectedSkSize = 0; - - switch (algorithm) { - case 0: - sigSize = SECP256K1_SIG_SIZE; - expectedSkSize = SECP256K1_SK_SIZE; - break; - case 1: - sigSize = ML_DSA_44_SIG_SIZE; - expectedSkSize = ML_DSA_44_SK_SIZE; - break; - case 2: - sigSize = SLH_DSA_SHAKE_128S_SIG_SIZE; - expectedSkSize = SLH_DSA_SHAKE_128S_SK_SIZE; - break; - default: - return Napi::Number::New(env, BAD_ARGUMENT); - } - - // Check key size - if (secretKey.ByteLength() != expectedSkSize) { - Napi::Object result = Napi::Object::New(env); - result.Set("signature", Napi::Uint8Array::New(env, 0)); - result.Set("resultCode", BAD_KEY); - return result; - } - - // Create result object - Napi::Object result = Napi::Object::New(env); - - // Create dummy signature - Napi::Uint8Array signature = Napi::Uint8Array::New(env, sigSize); - - // Use message to fill the signature (in a real implementation this would be a - // proper signature) - for (size_t i = 0; i < sigSize; i++) { - signature[i] = i < message.ByteLength() ? message[i] : 0; - } - - result.Set("signature", signature); - result.Set("resultCode", OK); - - return result; -} - -Napi::Value VerifySignature(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); - - if (info.Length() < 4 || !info[0].IsNumber() || !info[1].IsTypedArray() || - !info[2].IsTypedArray() || !info[3].IsTypedArray()) { - Napi::TypeError::New(env, "Wrong arguments").ThrowAsJavaScriptException(); - return env.Null(); - } - - int algorithm = info[0].As().Int32Value(); - Napi::Uint8Array publicKey = info[1].As(); - Napi::Uint8Array message = info[2].As(); - Napi::Uint8Array signature = info[3].As(); - - if (algorithm < 0 || algorithm > 3) { - return Napi::Number::New(env, BAD_ARGUMENT); - } - - // Get expected key and signature sizes - int expectedPkSize = 0; - int expectedSigSize = 0; - - switch (algorithm) { - case 0: - expectedPkSize = SECP256K1_PK_SIZE; - expectedSigSize = SECP256K1_SIG_SIZE; - break; - case 1: - expectedPkSize = ML_DSA_44_PK_SIZE; - expectedSigSize = ML_DSA_44_SIG_SIZE; - break; - case 2: - expectedPkSize = SLH_DSA_SHAKE_128S_PK_SIZE; - expectedSigSize = SLH_DSA_SHAKE_128S_SIG_SIZE; - break; - default: - return Napi::Number::New(env, BAD_ARGUMENT); - } - - // Check key and signature sizes - if (publicKey.ByteLength() != expectedPkSize) { - return Napi::Number::New(env, BAD_KEY); - } - - if (signature.ByteLength() != expectedSigSize) { - return Napi::Number::New(env, BAD_SIGNATURE); - } - - // In a real implementation, this would verify the signature - // Here we're just pretending it's valid - return Napi::Number::New(env, OK); -} - -Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports.Set("bitcoin_pqc_public_key_size", - Napi::Function::New(env, GetPublicKeySize)); - exports.Set("bitcoin_pqc_secret_key_size", - Napi::Function::New(env, GetSecretKeySize)); - exports.Set("bitcoin_pqc_signature_size", - Napi::Function::New(env, GetSignatureSize)); - exports.Set("bitcoin_pqc_keygen", Napi::Function::New(env, GenerateKeypair)); - exports.Set("bitcoin_pqc_sign", Napi::Function::New(env, SignMessage)); - exports.Set("bitcoin_pqc_verify", Napi::Function::New(env, VerifySignature)); - return exports; -} - -NODE_API_MODULE(mock_bitcoinpqc, Init) diff --git a/nodejs/src/types.ts b/nodejs/src/types.ts deleted file mode 100644 index 282c4085f7ba..000000000000 --- a/nodejs/src/types.ts +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Bitcoin PQC algorithm identifiers - */ -export enum Algorithm { - /** BIP-340 Schnorr + X-Only - Elliptic Curve Digital Signature Algorithm */ - SECP256K1_SCHNORR = 0, - /** ML-DSA-44 (CRYSTALS-Dilithium) - Lattice-based signature scheme */ - ML_DSA_44 = 1, - /** SLH-DSA-Shake-128s (SPHINCS+) - Hash-based signature scheme */ - SLH_DSA_SHAKE_128S = 2, -} - -/** - * Error types for PQC operations - */ -export enum ErrorCode { - /** Operation completed successfully */ - OK = 0, - /** Invalid arguments provided */ - BAD_ARGUMENT = -1, - /** Invalid key provided */ - BAD_KEY = -2, - /** Invalid signature provided */ - BAD_SIGNATURE = -3, - /** Algorithm not implemented */ - NOT_IMPLEMENTED = -4, -} - -/** - * Error class for PQC operations - */ -export class PqcError extends Error { - readonly code: ErrorCode; - - constructor(code: ErrorCode, message?: string) { - // Use a default message if none provided - const defaultMessage = (() => { - switch (code) { - case ErrorCode.BAD_ARGUMENT: - return "Invalid arguments provided"; - case ErrorCode.BAD_KEY: - return "Invalid key provided"; - case ErrorCode.BAD_SIGNATURE: - return "Invalid signature provided"; - case ErrorCode.NOT_IMPLEMENTED: - return "Algorithm not implemented"; - default: - return `Unexpected error code: ${code}`; - } - })(); - - super(message || defaultMessage); - this.code = code; - this.name = "PqcError"; - - // For better stack traces in Node.js - Error.captureStackTrace(this, PqcError); - } -} - -/** - * Public key wrapper - */ -export class PublicKey { - /** The algorithm this key belongs to */ - readonly algorithm: Algorithm; - /** The raw key bytes */ - readonly bytes: Uint8Array; - - constructor(algorithm: Algorithm, bytes: Uint8Array) { - this.algorithm = algorithm; - this.bytes = bytes; - } -} - -/** - * Secret key wrapper - */ -export class SecretKey { - /** The algorithm this key belongs to */ - readonly algorithm: Algorithm; - /** The raw key bytes */ - readonly bytes: Uint8Array; - - constructor(algorithm: Algorithm, bytes: Uint8Array) { - this.algorithm = algorithm; - this.bytes = bytes; - } -} - -/** - * Signature wrapper - */ -export class Signature { - /** The algorithm this signature belongs to */ - readonly algorithm: Algorithm; - /** The raw signature bytes */ - readonly bytes: Uint8Array; - - constructor(algorithm: Algorithm, bytes: Uint8Array) { - this.algorithm = algorithm; - this.bytes = bytes; - } -} - -/** - * Key pair containing both public and secret keys - */ -export class KeyPair { - /** The public key */ - readonly publicKey: PublicKey; - /** The secret key */ - readonly secretKey: SecretKey; - - constructor(publicKey: PublicKey, secretKey: SecretKey) { - if (publicKey.algorithm !== secretKey.algorithm) { - throw new PqcError( - ErrorCode.BAD_ARGUMENT, - "Public and secret key algorithms must match" - ); - } - this.publicKey = publicKey; - this.secretKey = secretKey; - } -} diff --git a/nodejs/tests/bitcoinpqc.test.ts b/nodejs/tests/bitcoinpqc.test.ts deleted file mode 100644 index 9930055eb2f2..000000000000 --- a/nodejs/tests/bitcoinpqc.test.ts +++ /dev/null @@ -1,153 +0,0 @@ -import { - Algorithm, - ErrorCode, - PqcError, - generateKeyPair, - publicKeySize, - secretKeySize, - sign, - signatureSize, - verify, -} from "../src"; - -import { - getLibrary, - setLibraryForTesting, - BitcoinPqcNative, -} from "../src/library"; - -describe("Bitcoin PQC", () => { - // Generate random data for tests - function getRandomBytes(size: number): Uint8Array { - const bytes = new Uint8Array(size); - for (let i = 0; i < size; i++) { - bytes[i] = Math.floor(Math.random() * 256); - } - return bytes; - } - - describe("key sizes", () => { - test("should report correct key sizes for each algorithm", () => { - // Test key size reporting functions - for (const algo of [ - Algorithm.SECP256K1_SCHNORR, - Algorithm.ML_DSA_44, - Algorithm.SLH_DSA_SHAKE_128S, - ]) { - expect(publicKeySize(algo)).toBeGreaterThan(0); - expect(secretKeySize(algo)).toBeGreaterThan(0); - expect(signatureSize(algo)).toBeGreaterThan(0); - } - }); - }); - - describe("ML-DSA-44 (Dilithium)", () => { - const algorithm = Algorithm.ML_DSA_44; - - // Skip this test for now - test.skip("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); - - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); - - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); - - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); - - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - - // Verify with raw signature bytes - expect(() => { - verify(keypair.publicKey, message, signature.bytes); - }).not.toThrow(); - - // Verify that the signature doesn't verify for a different message - const badMessage = new TextEncoder().encode("Bad message!"); - expect(() => { - verify(keypair.publicKey, badMessage, signature); - }).toThrow(PqcError); - }); - }); - - describe("SLH-DSA-SHAKE-128s (SPHINCS+)", () => { - const algorithm = Algorithm.SLH_DSA_SHAKE_128S; - - test("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); - - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); - - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); - - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); - - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - }); - }); - - - test("should generate keypair, sign and verify", () => { - // Generate random data for key generation - const randomData = getRandomBytes(128); - - // Generate a keypair - const keypair = generateKeyPair(algorithm, randomData); - - // Verify key sizes match reported sizes - expect(keypair.publicKey.bytes.length).toBe(publicKeySize(algorithm)); - expect(keypair.secretKey.bytes.length).toBe(secretKeySize(algorithm)); - - // Test message signing - const message = new TextEncoder().encode("Hello, Bitcoin PQC!"); - const signature = sign(keypair.secretKey, message); - - // Verify signature size matches reported size - expect(signature.bytes.length).toBe(signatureSize(algorithm)); - - // Verify the signature - should not throw - expect(() => { - verify(keypair.publicKey, message, signature); - }).not.toThrow(); - }); -}); - -describe("error conditions", () => { - test("should throw on invalid input", () => { - // Invalid algorithm - expect(() => { - const randomData = getRandomBytes(128); - generateKeyPair(99 as Algorithm, randomData); - }).toThrow(PqcError); - - // Invalid random data size - expect(() => { - const randomData = getRandomBytes(16); // Less than 128 bytes - generateKeyPair(Algorithm.ML_DSA_44, randomData); - }).toThrow(PqcError); - }); -}); -}); diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json deleted file mode 100644 index 7c2a08735de7..000000000000 --- a/nodejs/tsconfig.json +++ /dev/null @@ -1,116 +0,0 @@ -{ - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - /* Language and Environment */ - "target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "libReplacement": true, /* Enable lib replacement. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - /* Modules */ - "module": "commonjs", /* Specify what module code is generated. */ - "rootDir": "./src", /* Specify the root folder within your source files. */ - "baseUrl": ".", /* Specify the base directory to resolve non-relative module names. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - /* Emit */ - "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - "outDir": "./dist", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ - // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ - /* Type Checking */ - "strict": true, /* Enable all strict type-checking options. */ - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "include": [ - "src/**/*.ts" - ], - "exclude": [ - "node_modules", - "**/*.test.ts", - "dist", - "src/__tests__/**/*", - "src/c_sources/**/*" - ] -} \ No newline at end of file diff --git a/python/MANIFEST.in b/python/MANIFEST.in deleted file mode 100644 index 46790ebe00db..000000000000 --- a/python/MANIFEST.in +++ /dev/null @@ -1,4 +0,0 @@ -include README.md -include LICENSE -recursive-include examples *.py -recursive-include tests *.py diff --git a/python/README.md b/python/README.md deleted file mode 100644 index fb5db3624afc..000000000000 --- a/python/README.md +++ /dev/null @@ -1,77 +0,0 @@ -# Python Bindings for libbitcoinpqc - -This package provides Python bindings for the libbitcoinpqc library, which implements post-quantum cryptographic signature algorithms for use with BIP-360 and the Bitcoin QuBit soft fork. - -## Supported Algorithms - -- **ML-DSA-44** (CRYSTALS-Dilithium): A structured lattice-based digital signature scheme -- **SLH-DSA-Shake-128s** (SPHINCS+): A stateless hash-based signature scheme -- **FN-DSA-512** (FALCON): A lattice-based signature scheme designed for efficiency - -## Installation - -```bash -# Install the package -pip install bitcoinpqc -``` - -or from source: - -```bash -# Clone the repository -git clone https://github.com/bitcoin/libbitcoinpqc.git -cd libbitcoinpqc - -# Build the C library -mkdir build && cd build -cmake .. -make -cd .. - -# Install the Python package -cd python -pip install -e . -``` - -## Requirements - -- Python 3.7 or higher -- The libbitcoinpqc C library must be built and installed - -## Example Usage - -```python -import secrets -from bitcoinpqc import Algorithm, keygen, sign, verify - -# Generate random data for key generation -random_data = secrets.token_bytes(128) - -# Generate a key pair -algorithm = Algorithm.ML_DSA_44 # CRYSTALS-Dilithium -keypair = keygen(algorithm, random_data) - -# Create a message to sign -message = b"Hello, Bitcoin PQC!" - -# Sign the message -signature = sign(algorithm, keypair.secret_key, message) - -# Verify the signature -is_valid = verify(algorithm, keypair.public_key, message, signature) -print(f"Signature valid: {is_valid}") # Should print True -``` - -## Running Tests - -```bash -# Run the tests -./run_tests.sh - -# Or using unittest directly -python -m unittest discover -s tests -``` - -## License - -This project is licensed under the MIT License. diff --git a/python/bitcoinpqc/__init__.py b/python/bitcoinpqc/__init__.py deleted file mode 100644 index 04fcc0692f10..000000000000 --- a/python/bitcoinpqc/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -""" -Bitcoin PQC Python API - -This package provides Python bindings for the libbitcoinpqc library, -which implements post-quantum cryptographic signature algorithms. -""" - -from .bitcoinpqc import ( - Algorithm, - Error, - KeyPair, - Signature, - public_key_size, - secret_key_size, - signature_size, - keygen, - sign, - verify -) - -__version__ = "0.1.0" diff --git a/python/bitcoinpqc/bitcoinpqc.py b/python/bitcoinpqc/bitcoinpqc.py deleted file mode 100644 index 7a720ce7f95b..000000000000 --- a/python/bitcoinpqc/bitcoinpqc.py +++ /dev/null @@ -1,533 +0,0 @@ -""" -Bitcoin PQC Python Bindings - -This module provides Python bindings for the libbitcoinpqc C library. -""" - -import ctypes -import enum -import os -import platform -from pathlib import Path -from typing import Optional, Tuple, Union, List - - -# Find the library file -def _find_library(): - """Find the bitcoinpqc shared library.""" - # Try to find the library in common locations - search_paths = [ - # Current directory - Path.cwd(), - # Library's parent directory - Path(__file__).parent.parent.parent, - # Standard system paths - Path("/usr/lib"), - Path("/usr/local/lib"), - ] - - # Add build directories - # CMake build directory - search_paths.append(Path(__file__).parent.parent.parent / "build" / "lib") - # Rust build directories - search_paths.append(Path(__file__).parent.parent.parent / "target" / "debug") - search_paths.append(Path(__file__).parent.parent.parent / "target" / "debug" / "deps") - search_paths.append(Path(__file__).parent.parent.parent / "target" / "release") - search_paths.append(Path(__file__).parent.parent.parent / "target" / "release" / "deps") - - # Add paths from LD_LIBRARY_PATH environment variable - lib_path_env = None - if platform.system() == "Windows": - lib_path_env = os.environ.get("PATH", "") - elif platform.system() == "Darwin": - lib_path_env = os.environ.get("DYLD_LIBRARY_PATH", "") - else: # Linux/Unix - lib_path_env = os.environ.get("LD_LIBRARY_PATH", "") - - if lib_path_env: - for path in lib_path_env.split(os.pathsep): - if path: - search_paths.append(Path(path)) - - # Platform-specific library name - if platform.system() == "Windows": - lib_names = ["bitcoinpqc.dll"] - elif platform.system() == "Darwin": # macOS - lib_names = ["libbitcoinpqc.dylib", "libbitcoinpqc.so"] - else: # Linux/Unix - lib_names = ["libbitcoinpqc.so", "libbitcoinpqc.dylib"] - - # Don't try to load static libraries with ctypes - # lib_names.append("libbitcoinpqc.a") - - # Try each possible file path - found_paths = [] - for path in search_paths: - for name in lib_names: - lib_path = path / name - if lib_path.exists(): - found_paths.append(str(lib_path)) - - if found_paths: - return found_paths[0] # Return the first found library - - # If not found, let the OS loader find it - if platform.system() == "Windows": - return "bitcoinpqc" - else: - return "bitcoinpqc" - - -# Define enums to match C API -class Algorithm(enum.IntEnum): - """Algorithm types from bitcoin_pqc_algorithm_t.""" - SECP256K1_SCHNORR = 0 - FN_DSA_512 = 1 # FALCON-512 - ML_DSA_44 = 2 # CRYSTALS-Dilithium Level I - SLH_DSA_SHAKE_128S = 3 # SPHINCS+-128s - - -class Error(enum.IntEnum): - """Error codes from bitcoin_pqc_error_t.""" - OK = 0 - BAD_ARG = -1 - BAD_KEY = -2 - BAD_SIGNATURE = -3 - NOT_IMPLEMENTED = -4 - - -# Find and load the library -_lib_path = _find_library() -_MOCK_MODE = False # Flag to indicate if we're using mock mode - -try: - print(f"Attempting to load library from: {_lib_path}") - _lib = ctypes.CDLL(_lib_path) - - # Check if the library has the required functions - required_functions = [ - "bitcoin_pqc_public_key_size", - "bitcoin_pqc_secret_key_size", - "bitcoin_pqc_signature_size", - "bitcoin_pqc_keygen", - "bitcoin_pqc_keypair_free", - "bitcoin_pqc_sign", - "bitcoin_pqc_signature_free", - "bitcoin_pqc_verify" - ] - - missing_functions = [] - for func_name in required_functions: - if not hasattr(_lib, func_name): - missing_functions.append(func_name) - - if missing_functions: - print(f"Library found but missing required functions: {', '.join(missing_functions)}") - print("This appears to be the Rust library without the C API exposed.") - print("Using mock implementation instead.") - _MOCK_MODE = True - else: - print(f"Successfully loaded library with all required functions") -except (OSError, TypeError) as e: - # Try with just the basename as a last resort - try: - if platform.system() == "Windows": - _lib = ctypes.CDLL("bitcoinpqc") - else: - _lib = ctypes.CDLL("libbitcoinpqc") - print("Loaded library using system search paths") - except (OSError, TypeError) as e2: - print(f"Failed to load library from {_lib_path}: {e}") - print(f"Also failed with default name: {e2}") - - print("Using mock implementation for testing purposes") - _MOCK_MODE = True - -# If we're using mock mode, create a mock implementation -if _MOCK_MODE: - print("Creating mock implementation of the Bitcoin PQC library") - - # Create a mock function class that supports argtypes and restype - class MockFunction: - def __init__(self, func): - self.func = func - self.argtypes = None - self.restype = None - - def __call__(self, *args, **kwargs): - return self.func(*args, **kwargs) - - # Create mock class with all required functions - class MockLib: - def __init__(self): - # Create function attributes with MockFunction wrappers - self.bitcoin_pqc_public_key_size = MockFunction(self._bitcoin_pqc_public_key_size) - self.bitcoin_pqc_secret_key_size = MockFunction(self._bitcoin_pqc_secret_key_size) - self.bitcoin_pqc_signature_size = MockFunction(self._bitcoin_pqc_signature_size) - self.bitcoin_pqc_keygen = MockFunction(self._bitcoin_pqc_keygen) - self.bitcoin_pqc_keypair_free = MockFunction(self._bitcoin_pqc_keypair_free) - self.bitcoin_pqc_sign = MockFunction(self._bitcoin_pqc_sign) - self.bitcoin_pqc_signature_free = MockFunction(self._bitcoin_pqc_signature_free) - self.bitcoin_pqc_verify = MockFunction(self._bitcoin_pqc_verify) - - def _bitcoin_pqc_public_key_size(self, algorithm): - sizes = { - 0: 32, # SECP256K1_SCHNORR - 1: 897, # FN_DSA_512 - 2: 1312, # ML_DSA_44 - 3: 32, # SLH_DSA_SHAKE_128S - } - return sizes.get(algorithm, 32) - - def _bitcoin_pqc_secret_key_size(self, algorithm): - sizes = { - 0: 32, # SECP256K1_SCHNORR - 1: 1281, # FN_DSA_512 - 2: 2528, # ML_DSA_44 - 3: 64, # SLH_DSA_SHAKE_128S - } - return sizes.get(algorithm, 64) - - def _bitcoin_pqc_signature_size(self, algorithm): - sizes = { - 0: 64, # SECP256K1_SCHNORR - 1: 666, # FN_DSA_512 - 2: 2420, # ML_DSA_44 - 3: 7856, # SLH_DSA_SHAKE_128S - } - return sizes.get(algorithm, 64) - - def _bitcoin_pqc_keygen(self, algorithm, keypair_ptr, random_data, random_data_size): - # In the mock, we need to directly access the pointer - # Check if we're dealing with a pointer from byref or a direct pointer - try: - # Try to access the object this is pointing to - keypair = keypair_ptr._obj - except (AttributeError, TypeError): - try: - # Try the regular contents access - keypair = keypair_ptr.contents - except (AttributeError, TypeError): - # Last resort: assume it's already the object - keypair = keypair_ptr - - keypair.algorithm = algorithm - - # Allocate mock public key - pub_size = self._bitcoin_pqc_public_key_size(algorithm) - pub_key = (ctypes.c_uint8 * pub_size)() - for i in range(min(pub_size, len(random_data))): - pub_key[i] = random_data[i] - keypair.public_key = ctypes.cast(pub_key, ctypes.c_void_p) - keypair.public_key_size = pub_size - - # Allocate mock secret key - sec_size = self._bitcoin_pqc_secret_key_size(algorithm) - sec_key = (ctypes.c_uint8 * sec_size)() - for i in range(min(sec_size, len(random_data))): - sec_key[i] = random_data[i] - keypair.secret_key = ctypes.cast(sec_key, ctypes.c_void_p) - keypair.secret_key_size = sec_size - - return 0 # Success - - def _bitcoin_pqc_keypair_free(self, keypair_ptr): - # In a real implementation, we would free the memory - pass - - def _bitcoin_pqc_sign(self, algorithm, secret_key, secret_key_size, - message, message_size, signature_ptr): - # In the mock, we need to directly access the pointer - try: - # Try to access the object this is pointing to - signature = signature_ptr._obj - except (AttributeError, TypeError): - try: - # Try the regular contents access - signature = signature_ptr.contents - except (AttributeError, TypeError): - # Last resort: assume it's already the object - signature = signature_ptr - - signature.algorithm = algorithm - - # Allocate mock signature - sig_size = self._bitcoin_pqc_signature_size(algorithm) - sig_data = (ctypes.c_uint8 * sig_size)() - - # Create a deterministic "signature" based on the message - import hashlib - msg_bytes = bytes(message[:message_size]) - digest = hashlib.sha256(msg_bytes).digest() - for i in range(min(sig_size, len(digest))): - sig_data[i] = digest[i] - - signature.signature = ctypes.cast(sig_data, ctypes.POINTER(ctypes.c_uint8)) - signature.signature_size = sig_size - - return 0 # Success - - def _bitcoin_pqc_signature_free(self, signature_ptr): - # In a real implementation, we would free the memory - pass - - def _bitcoin_pqc_verify(self, algorithm, public_key, public_key_size, - message, message_size, signature, signature_size): - # Mock verification - in real life we'd verify the signature - # For mock purposes, we'll just validate sizes are correct - if public_key_size != self._bitcoin_pqc_public_key_size(algorithm): - return -2 # BAD_KEY - - if signature_size != self._bitcoin_pqc_signature_size(algorithm): - return -3 # BAD_SIGNATURE - - # Create deterministic verification result based on the message - # For testing, we'll verify the same message that was signed - import hashlib - - # Convert message to bytes - handle both buffer types and direct pointers - try: - # Try to get a slice directly - msg_bytes = bytes(message[:message_size]) - except (TypeError, AttributeError): - # If that fails, try to create a ctypes buffer and copy - try: - msg_buffer = (ctypes.c_uint8 * message_size)() - for i in range(message_size): - msg_buffer[i] = message[i] - msg_bytes = bytes(msg_buffer) - except: - # Last resort: assume it's already bytes - msg_bytes = message - - digest = hashlib.sha256(msg_bytes).digest() - - # Check first few bytes of signature match our mock signature generation - for i in range(min(16, signature_size, len(digest))): - if signature[i] != digest[i]: - return -3 # BAD_SIGNATURE - - return 0 # Success - - _lib = MockLib() - - -# Define C structures and function prototypes - -# KeyPair structure -class _CKeyPair(ctypes.Structure): - _fields_ = [ - ("algorithm", ctypes.c_int), - ("public_key", ctypes.c_void_p), - ("secret_key", ctypes.c_void_p), - ("public_key_size", ctypes.c_size_t), - ("secret_key_size", ctypes.c_size_t) - ] - - -# Signature structure -class _CSignature(ctypes.Structure): - _fields_ = [ - ("algorithm", ctypes.c_int), - ("signature", ctypes.POINTER(ctypes.c_uint8)), - ("signature_size", ctypes.c_size_t) - ] - - -# Define function prototypes -_lib.bitcoin_pqc_public_key_size.argtypes = [ctypes.c_int] -_lib.bitcoin_pqc_public_key_size.restype = ctypes.c_size_t - -_lib.bitcoin_pqc_secret_key_size.argtypes = [ctypes.c_int] -_lib.bitcoin_pqc_secret_key_size.restype = ctypes.c_size_t - -_lib.bitcoin_pqc_signature_size.argtypes = [ctypes.c_int] -_lib.bitcoin_pqc_signature_size.restype = ctypes.c_size_t - -_lib.bitcoin_pqc_keygen.argtypes = [ - ctypes.c_int, - ctypes.POINTER(_CKeyPair), - ctypes.POINTER(ctypes.c_uint8), - ctypes.c_size_t -] -_lib.bitcoin_pqc_keygen.restype = ctypes.c_int - -_lib.bitcoin_pqc_keypair_free.argtypes = [ctypes.POINTER(_CKeyPair)] -_lib.bitcoin_pqc_keypair_free.restype = None - -_lib.bitcoin_pqc_sign.argtypes = [ - ctypes.c_int, - ctypes.POINTER(ctypes.c_uint8), - ctypes.c_size_t, - ctypes.POINTER(ctypes.c_uint8), - ctypes.c_size_t, - ctypes.POINTER(_CSignature) -] -_lib.bitcoin_pqc_sign.restype = ctypes.c_int - -_lib.bitcoin_pqc_signature_free.argtypes = [ctypes.POINTER(_CSignature)] -_lib.bitcoin_pqc_signature_free.restype = None - -_lib.bitcoin_pqc_verify.argtypes = [ - ctypes.c_int, - ctypes.POINTER(ctypes.c_uint8), - ctypes.c_size_t, - ctypes.POINTER(ctypes.c_uint8), - ctypes.c_size_t, - ctypes.POINTER(ctypes.c_uint8), - ctypes.c_size_t -] -_lib.bitcoin_pqc_verify.restype = ctypes.c_int - - -# Python wrapper classes - -class KeyPair: - """Bitcoin PQC key pair wrapper.""" - - def __init__(self, algorithm: Algorithm, keypair: _CKeyPair): - """Initialize from a C keypair structure.""" - self.algorithm = algorithm - self._keypair = keypair - - # Extract public and secret keys - if keypair.public_key and keypair.public_key_size > 0: - public_key = (ctypes.c_uint8 * keypair.public_key_size)() - ctypes.memmove(public_key, keypair.public_key, keypair.public_key_size) - self.public_key = bytes(public_key) - else: - self.public_key = b'' - - if keypair.secret_key and keypair.secret_key_size > 0: - secret_key = (ctypes.c_uint8 * keypair.secret_key_size)() - ctypes.memmove(secret_key, keypair.secret_key, keypair.secret_key_size) - self.secret_key = bytes(secret_key) - else: - self.secret_key = b'' - - def __del__(self): - """Free C resources.""" - try: - if hasattr(self, '_keypair'): - _lib.bitcoin_pqc_keypair_free(ctypes.byref(self._keypair)) - del self._keypair - except (AttributeError, TypeError): - # Library might already be unloaded during interpreter shutdown - pass - - -class Signature: - """Bitcoin PQC signature wrapper.""" - - def __init__(self, algorithm: Algorithm, signature: Optional[_CSignature] = None, raw_signature: Optional[bytes] = None): - """Initialize from either a C signature structure or raw bytes.""" - self.algorithm = algorithm - self._signature = signature - - if signature: - # Extract signature bytes - if signature.signature and signature.signature_size > 0: - sig_buffer = (ctypes.c_uint8 * signature.signature_size)() - ctypes.memmove(sig_buffer, signature.signature, signature.signature_size) - self.signature = bytes(sig_buffer) - else: - self.signature = b'' - elif raw_signature: - self.signature = raw_signature - else: - raise ValueError("Must provide either signature or raw_signature") - - def __del__(self): - """Free C resources.""" - try: - if hasattr(self, '_signature') and self._signature: - _lib.bitcoin_pqc_signature_free(ctypes.byref(self._signature)) - del self._signature - except (AttributeError, TypeError): - # Library might already be unloaded during interpreter shutdown - pass - - -# API Functions - -def public_key_size(algorithm: Algorithm) -> int: - """Get the public key size for an algorithm.""" - return _lib.bitcoin_pqc_public_key_size(algorithm) - - -def secret_key_size(algorithm: Algorithm) -> int: - """Get the secret key size for an algorithm.""" - return _lib.bitcoin_pqc_secret_key_size(algorithm) - - -def signature_size(algorithm: Algorithm) -> int: - """Get the signature size for an algorithm.""" - return _lib.bitcoin_pqc_signature_size(algorithm) - - -def keygen(algorithm: Algorithm, random_data: bytes) -> KeyPair: - """Generate a key pair.""" - if len(random_data) < 128: - raise ValueError("Random data must be at least 128 bytes") - - random_buffer = (ctypes.c_uint8 * len(random_data)).from_buffer_copy(random_data) - keypair = _CKeyPair() - - result = _lib.bitcoin_pqc_keygen( - algorithm, - ctypes.byref(keypair), - random_buffer, - len(random_data) - ) - - if result != Error.OK: - raise Exception(f"Key generation failed with error code: {result}") - - return KeyPair(algorithm, keypair) - - -def sign(algorithm: Algorithm, secret_key: bytes, message: bytes) -> Signature: - """Sign a message.""" - secret_buffer = (ctypes.c_uint8 * len(secret_key)).from_buffer_copy(secret_key) - message_buffer = (ctypes.c_uint8 * len(message)).from_buffer_copy(message) - signature = _CSignature() - - result = _lib.bitcoin_pqc_sign( - algorithm, - secret_buffer, - len(secret_key), - message_buffer, - len(message), - ctypes.byref(signature) - ) - - if result != Error.OK: - raise Exception(f"Signing failed with error code: {result}") - - return Signature(algorithm, signature) - - -def verify(algorithm: Algorithm, public_key: bytes, message: bytes, signature: Union[Signature, bytes]) -> bool: - """Verify a signature.""" - public_buffer = (ctypes.c_uint8 * len(public_key)).from_buffer_copy(public_key) - message_buffer = (ctypes.c_uint8 * len(message)).from_buffer_copy(message) - - # Handle both Signature objects and raw signature bytes - if isinstance(signature, Signature): - sig_bytes = signature.signature - else: - sig_bytes = signature - - sig_buffer = (ctypes.c_uint8 * len(sig_bytes)).from_buffer_copy(sig_bytes) - - result = _lib.bitcoin_pqc_verify( - algorithm, - public_buffer, - len(public_key), - message_buffer, - len(message), - sig_buffer, - len(sig_bytes) - ) - - return result == Error.OK diff --git a/python/check_library.py b/python/check_library.py deleted file mode 100755 index f086e793fd0e..000000000000 --- a/python/check_library.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -""" -Check if the libbitcoinpqc C library can be found and loaded. -""" - -import os -import sys -import ctypes -from pathlib import Path -import platform -from datetime import datetime - - -def find_library(): - """Find the bitcoinpqc shared library.""" - search_paths = [ - Path.cwd(), - Path(__file__).parent.parent, - Path("/usr/lib"), - Path("/usr/local/lib"), - # CMake build directory - Path(__file__).parent.parent / "build" / "lib", - # Rust build directories - Path(__file__).parent.parent / "target" / "debug", - Path(__file__).parent.parent / "target" / "debug" / "deps", - Path(__file__).parent.parent / "target" / "release", - Path(__file__).parent.parent / "target" / "release" / "deps", - ] - - if platform.system() == "Windows": - lib_names = ["bitcoinpqc.dll"] - elif platform.system() == "Darwin": # macOS - lib_names = ["libbitcoinpqc.dylib", "libbitcoinpqc.so"] - else: # Linux/Unix - lib_names = ["libbitcoinpqc.so", "libbitcoinpqc.dylib"] - - print("Searching for library...") - for path in search_paths: - print(f"Looking in {path}") - for name in lib_names: - lib_path = path / name - if lib_path.exists(): - print(f"Found at: {lib_path}") - return str(lib_path) - - print("Library not found in standard locations") - return None - - -def main(): - """Check if the C library can be loaded.""" - print("Bitcoin PQC Library Check Utility") - print("=================================") - - # Check if we're running from the source directory - if Path(__file__).parent.name == "python": - print("Running from python source directory") - - # Find the library - lib_path = find_library() - - if lib_path is None: - print("Could not find the libbitcoinpqc library") - print("\nTry building the C library with:") - print(" mkdir -p build && cd build && cmake .. && make") - print(" cd ..") - sys.exit(1) - - # Try to load the library - try: - print(f"Attempting to load {lib_path}") - lib = ctypes.CDLL(lib_path) - print("Successfully loaded the library!") - - # Check if basic functions are available - if hasattr(lib, "bitcoin_pqc_public_key_size"): - print("Found bitcoin_pqc_public_key_size function") - else: - print("WARNING: bitcoin_pqc_public_key_size function not found") - - # Print the library info - print("\nLibrary Information:") - print(f" Path: {lib_path}") - print(f" Size: {os.path.getsize(lib_path) / 1024:.1f} KB") - print(f" Modified: {datetime.fromtimestamp(os.path.getmtime(lib_path)).strftime('%Y-%m-%d %H:%M:%S')}") - - print("\nAll checks passed. The Python bindings should work correctly.") - return 0 - except Exception as e: - print(f"Failed to load the library: {e}") - print("\nPossible solutions:") - print("1. Make sure you have built the C library correctly") - print("2. Check that the library file exists and is readable") - print("3. On Linux, add the library directory to LD_LIBRARY_PATH:") - print(" export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/library/dir") - print("4. On macOS, add the library directory to DYLD_LIBRARY_PATH:") - print(" export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:/path/to/library/dir") - sys.exit(1) - - -if __name__ == "__main__": - sys.exit(main()) diff --git a/python/examples/__init__.py b/python/examples/__init__.py deleted file mode 100644 index 1182e629a609..000000000000 --- a/python/examples/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Examples for libbitcoinpqc Python bindings.""" diff --git a/python/examples/basic_usage.py b/python/examples/basic_usage.py deleted file mode 100644 index f6ba1cfc9f0f..000000000000 --- a/python/examples/basic_usage.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/env python3 -""" -Basic usage example for the bitcoinpqc Python bindings. -""" - -import os -import sys -import secrets -from pathlib import Path -import time - -# Add the parent directory to the path so we can import the module -sys.path.insert(0, str(Path(__file__).parent.parent)) - -from bitcoinpqc import Algorithm, keygen, sign, verify - - -def main(): - """Run a basic example of bitcoinpqc usage.""" - # Choose an algorithm - algorithm = Algorithm.ML_DSA_44 # CRYSTALS-Dilithium - - # Generate random data for key generation - random_data = secrets.token_bytes(128) - - print(f"Generating key pair for {algorithm.name}...") - start = time.time() - keypair = keygen(algorithm, random_data) - keygen_time = time.time() - start - - print(f"Key generation took {keygen_time:.4f} seconds") - print(f"Public key size: {len(keypair.public_key)} bytes") - print(f"Secret key size: {len(keypair.secret_key)} bytes") - - # Sign a message - message = b"This is a test message for Bitcoin PQC signatures." - print(f"\nSigning message: {message.decode('utf-8')}") - - start = time.time() - signature = sign(algorithm, keypair.secret_key, message) - sign_time = time.time() - start - - print(f"Signing took {sign_time:.4f} seconds") - print(f"Signature size: {len(signature.signature)} bytes") - - # Verify the signature - print("\nVerifying signature...") - - start = time.time() - is_valid = verify(algorithm, keypair.public_key, message, signature) - verify_time = time.time() - start - - print(f"Verification took {verify_time:.4f} seconds") - print(f"Signature is valid: {is_valid}") - - # Verify with incorrect message - bad_message = b"This is NOT the original message!" - print("\nVerifying signature with incorrect message...") - - is_valid = verify(algorithm, keypair.public_key, bad_message, signature) - print(f"Signature is valid (should be False): {is_valid}") - - -if __name__ == "__main__": - main() diff --git a/python/run_tests.sh b/python/run_tests.sh deleted file mode 100755 index 47e2af82ac2c..000000000000 --- a/python/run_tests.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash - -# Run the Python tests for libbitcoinpqc - -# Exit on any error -set -e - -echo "Running libbitcoinpqc Python API tests..." - -# Check if the library can be found -if [ -f "../build/lib/libbitcoinpqc.so" ] || [ -f "../build/lib/libbitcoinpqc.dylib" ]; then - echo "Found library at ../build/lib" -elif [ -f "../target/debug/libbitcoinpqc.so" ] || [ -f "../target/debug/libbitcoinpqc.dylib" ]; then - echo "Found Rust library at ../target/debug" - echo "Using mock implementation for testing" - export BITCOINPQC_ALLOW_MOCK=1 - - # Add this to LD_LIBRARY_PATH for the current session - # (Not needed with mock implementation, but kept for documentation) - # export LD_LIBRARY_PATH="../target/debug:$LD_LIBRARY_PATH" -elif [ -f "../target/release/libbitcoinpqc.so" ] || [ -f "../target/release/libbitcoinpqc.dylib" ]; then - echo "Found Rust library at ../target/release" - echo "Using mock implementation for testing" - export BITCOINPQC_ALLOW_MOCK=1 - - # Add this to LD_LIBRARY_PATH for the current session - # (Not needed with mock implementation, but kept for documentation) - # export LD_LIBRARY_PATH="../target/release:$LD_LIBRARY_PATH" -elif [ -f "/usr/lib/libbitcoinpqc.so" ] || [ -f "/usr/lib/libbitcoinpqc.dylib" ]; then - echo "Found library at /usr/lib" -elif [ -f "/usr/local/lib/libbitcoinpqc.so" ] || [ -f "/usr/local/lib/libbitcoinpqc.dylib" ]; then - echo "Found library at /usr/local/lib" -else - echo "WARNING: Library not found, using mock implementation for testing" - export BITCOINPQC_ALLOW_MOCK=1 -fi - -# Run unittest tests -python3 -m unittest discover -s tests - -echo "All tests passed!" - -# Run the example -echo -e "\nRunning example..." -python3 examples/basic_usage.py diff --git a/python/setup.py b/python/setup.py deleted file mode 100644 index 5fdd91906b3b..000000000000 --- a/python/setup.py +++ /dev/null @@ -1,38 +0,0 @@ -from setuptools import setup, find_packages -import os - -# Get the absolute path to the directory containing setup.py -here = os.path.abspath(os.path.dirname(__file__)) - -# Read the README.md file safely -with open(os.path.join(here, "README.md"), encoding="utf-8") as f: - long_description = f.read() - -# Use the README.md in the python directory if it exists, otherwise use the root README -if not os.path.exists(os.path.join(here, "README.md")): - with open(os.path.join(here, "..", "README.md"), encoding="utf-8") as f: - long_description = f.read() - -setup( - name="bitcoinpqc", - version="0.1.0", - packages=find_packages(), - description="Python bindings for libbitcoinpqc", - long_description=long_description, - long_description_content_type="text/markdown", - author="Bitcoin PQC Developers", - url="https://github.com/bitcoinpqc/libbitcoinpqc", - classifiers=[ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - ], - python_requires=">=3.7", - # Add explicit entry for test_suite if you have tests - test_suite="tests", -) diff --git a/python/tests/__init__.py b/python/tests/__init__.py deleted file mode 100644 index e679cdf0c313..000000000000 --- a/python/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""Test package for libbitcoinpqc Python bindings.""" diff --git a/python/tests/test_bitcoinpqc.py b/python/tests/test_bitcoinpqc.py deleted file mode 100644 index a209d32948c9..000000000000 --- a/python/tests/test_bitcoinpqc.py +++ /dev/null @@ -1,77 +0,0 @@ -import unittest -import os -import sys -import secrets -from pathlib import Path - -# Add the parent directory to the path so we can import the module -sys.path.insert(0, str(Path(__file__).parent.parent)) - -import bitcoinpqc -from bitcoinpqc import Algorithm - - -class TestBitcoinPQC(unittest.TestCase): - - def test_key_sizes(self): - """Test key size reporting functions.""" - for algo in [ - Algorithm.FN_DSA_512, - Algorithm.ML_DSA_44, - Algorithm.SLH_DSA_SHAKE_128S - ]: - # Verify sizes are non-zero - self.assertGreater(bitcoinpqc.public_key_size(algo), 0) - self.assertGreater(bitcoinpqc.secret_key_size(algo), 0) - self.assertGreater(bitcoinpqc.signature_size(algo), 0) - - def _test_algorithm(self, algorithm): - """Test key generation, signing, and verification for a specific algorithm.""" - # Generate random data for key generation - random_data = secrets.token_bytes(128) - - # Generate a keypair - keypair = bitcoinpqc.keygen(algorithm, random_data) - - # Verify key sizes match reported sizes - self.assertEqual(len(keypair.public_key), bitcoinpqc.public_key_size(algorithm)) - self.assertEqual(len(keypair.secret_key), bitcoinpqc.secret_key_size(algorithm)) - - # Test message signing - message = b"Hello, Bitcoin PQC!" - signature = bitcoinpqc.sign(algorithm, keypair.secret_key, message) - - # Verify signature size matches reported size - self.assertEqual(len(signature.signature), bitcoinpqc.signature_size(algorithm)) - - # Verify the signature - self.assertTrue(bitcoinpqc.verify( - algorithm, keypair.public_key, message, signature - )) - - # Verify with raw signature bytes - self.assertTrue(bitcoinpqc.verify( - algorithm, keypair.public_key, message, signature.signature - )) - - # Verify that the signature doesn't verify for a different message - bad_message = b"Bad message!" - self.assertFalse(bitcoinpqc.verify( - algorithm, keypair.public_key, bad_message, signature - )) - - def test_fn_dsa(self): - """Test FN-DSA-512 (FALCON) algorithm.""" - self._test_algorithm(Algorithm.FN_DSA_512) - - def test_ml_dsa(self): - """Test ML-DSA-44 (Dilithium) algorithm.""" - self._test_algorithm(Algorithm.ML_DSA_44) - - def test_slh_dsa(self): - """Test SLH-DSA-SHAKE-128s (SPHINCS+) algorithm.""" - self._test_algorithm(Algorithm.SLH_DSA_SHAKE_128S) - - -if __name__ == "__main__": - unittest.main() diff --git a/src/bindings_include.rs b/src/bindings_include.rs deleted file mode 100644 index f3a33ab70389..000000000000 --- a/src/bindings_include.rs +++ /dev/null @@ -1,207 +0,0 @@ -// This file exists to solve the problem with OUT_DIR not being -// available in the IDE but required for builds. -// The build script always generates bindings.rs in the OUT_DIR. - -// When compiling for real, include the real bindings -#[cfg(all(not(feature = "ide"), not(doc)))] -include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - -// For documentation, we need stubs to make doctests work -#[cfg(doc)] -pub mod doc_bindings { - // Define the essential types needed for documentation - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct bitcoin_pqc_algorithm_t(pub u32); - - impl bitcoin_pqc_algorithm_t { - pub const BITCOIN_PQC_SECP256K1_SCHNORR: bitcoin_pqc_algorithm_t = - bitcoin_pqc_algorithm_t(0); - pub const BITCOIN_PQC_ML_DSA_44: bitcoin_pqc_algorithm_t = bitcoin_pqc_algorithm_t(1); - pub const BITCOIN_PQC_SLH_DSA_SHAKE_128S: bitcoin_pqc_algorithm_t = - bitcoin_pqc_algorithm_t(2); - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct bitcoin_pqc_error_t(pub i32); - - impl bitcoin_pqc_error_t { - pub const BITCOIN_PQC_OK: bitcoin_pqc_error_t = bitcoin_pqc_error_t(0); - pub const BITCOIN_PQC_ERROR_BAD_ARG: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-1); - pub const BITCOIN_PQC_ERROR_BAD_KEY: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-2); - pub const BITCOIN_PQC_ERROR_BAD_SIGNATURE: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-3); - pub const BITCOIN_PQC_ERROR_NOT_IMPLEMENTED: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-4); - } - - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct bitcoin_pqc_keypair_t { - pub algorithm: bitcoin_pqc_algorithm_t, - pub public_key: *mut ::std::os::raw::c_uchar, - pub secret_key: *mut ::std::os::raw::c_uchar, - pub public_key_size: usize, - pub secret_key_size: usize, - } - - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct bitcoin_pqc_signature_t { - pub algorithm: bitcoin_pqc_algorithm_t, - pub signature: *mut ::std::os::raw::c_uchar, - pub signature_size: usize, - } - - // Dummy function declarations - pub unsafe fn bitcoin_pqc_keygen( - _algorithm: bitcoin_pqc_algorithm_t, - _keypair: *mut bitcoin_pqc_keypair_t, - _random_data: *const ::std::os::raw::c_uchar, - _random_data_len: usize, - ) -> bitcoin_pqc_error_t { - unimplemented!("This is a doc stub") - } - - pub unsafe fn bitcoin_pqc_keypair_free(_keypair: *mut bitcoin_pqc_keypair_t) {} - - #[allow(clippy::too_many_arguments)] - pub unsafe fn bitcoin_pqc_sign( - _algorithm: bitcoin_pqc_algorithm_t, - _secret_key: *const ::std::os::raw::c_uchar, - _secret_key_len: usize, - _message: *const ::std::os::raw::c_uchar, - _message_len: usize, - _signature: *mut bitcoin_pqc_signature_t, - ) -> bitcoin_pqc_error_t { - unimplemented!("This is a doc stub") - } - - pub unsafe fn bitcoin_pqc_verify( - _algorithm: bitcoin_pqc_algorithm_t, - _public_key: *const ::std::os::raw::c_uchar, - _public_key_len: usize, - _message: *const ::std::os::raw::c_uchar, - _message_len: usize, - _signature: *const ::std::os::raw::c_uchar, - _signature_len: usize, - ) -> bitcoin_pqc_error_t { - unimplemented!("This is a doc stub") - } - - pub unsafe fn bitcoin_pqc_signature_free(_signature: *mut bitcoin_pqc_signature_t) {} - - pub unsafe fn bitcoin_pqc_public_key_size(_algorithm: bitcoin_pqc_algorithm_t) -> usize { - 0 - } - - pub unsafe fn bitcoin_pqc_secret_key_size(_algorithm: bitcoin_pqc_algorithm_t) -> usize { - 0 - } - - pub unsafe fn bitcoin_pqc_signature_size(_algorithm: bitcoin_pqc_algorithm_t) -> usize { - 0 - } -} - -// For IDE support - similar stubs but are never compiled for release -#[cfg(feature = "ide")] -pub mod ide_bindings { - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct bitcoin_pqc_keypair_t { - pub algorithm: bitcoin_pqc_algorithm_t, - pub public_key: *mut ::std::os::raw::c_uchar, - pub secret_key: *mut ::std::os::raw::c_uchar, - pub public_key_size: usize, - pub secret_key_size: usize, - } - - #[repr(C)] - #[derive(Debug, Copy, Clone)] - pub struct bitcoin_pqc_signature_t { - pub algorithm: bitcoin_pqc_algorithm_t, - pub signature: *mut ::std::os::raw::c_uchar, - pub signature_size: usize, - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct bitcoin_pqc_algorithm_t(pub u32); - - impl bitcoin_pqc_algorithm_t { - pub const BITCOIN_PQC_SECP256K1_SCHNORR: bitcoin_pqc_algorithm_t = - bitcoin_pqc_algorithm_t(0); - pub const BITCOIN_PQC_ML_DSA_44: bitcoin_pqc_algorithm_t = bitcoin_pqc_algorithm_t(1); - pub const BITCOIN_PQC_SLH_DSA_SHAKE_128S: bitcoin_pqc_algorithm_t = - bitcoin_pqc_algorithm_t(2); - } - - #[repr(C)] - #[derive(Debug, Copy, Clone, PartialEq, Eq)] - pub struct bitcoin_pqc_error_t(pub i32); - - impl bitcoin_pqc_error_t { - pub const BITCOIN_PQC_OK: bitcoin_pqc_error_t = bitcoin_pqc_error_t(0); - pub const BITCOIN_PQC_ERROR_BAD_ARG: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-1); - pub const BITCOIN_PQC_ERROR_BAD_KEY: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-2); - pub const BITCOIN_PQC_ERROR_BAD_SIGNATURE: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-3); - pub const BITCOIN_PQC_ERROR_NOT_IMPLEMENTED: bitcoin_pqc_error_t = bitcoin_pqc_error_t(-4); - } - - // Function declarations for IDE support - pub unsafe fn bitcoin_pqc_keygen( - _algorithm: bitcoin_pqc_algorithm_t, - _keypair: *mut bitcoin_pqc_keypair_t, - _random_data: *const ::std::os::raw::c_uchar, - _random_data_len: usize, - ) -> bitcoin_pqc_error_t { - unimplemented!("This is an IDE stub") - } - - pub unsafe fn bitcoin_pqc_keypair_free(_keypair: *mut bitcoin_pqc_keypair_t) {} - - #[allow(clippy::too_many_arguments)] - pub unsafe fn bitcoin_pqc_sign( - _algorithm: bitcoin_pqc_algorithm_t, - _secret_key: *const ::std::os::raw::c_uchar, - _secret_key_len: usize, - _message: *const ::std::os::raw::c_uchar, - _message_len: usize, - _signature: *mut bitcoin_pqc_signature_t, - ) -> bitcoin_pqc_error_t { - unimplemented!("This is an IDE stub") - } - - pub unsafe fn bitcoin_pqc_verify( - _algorithm: bitcoin_pqc_algorithm_t, - _public_key: *const ::std::os::raw::c_uchar, - _public_key_len: usize, - _message: *const ::std::os::raw::c_uchar, - _message_len: usize, - _signature: *const ::std::os::raw::c_uchar, - _signature_len: usize, - ) -> bitcoin_pqc_error_t { - unimplemented!("This is an IDE stub") - } - - pub unsafe fn bitcoin_pqc_signature_free(_signature: *mut bitcoin_pqc_signature_t) {} - - pub unsafe fn bitcoin_pqc_public_key_size(_algorithm: bitcoin_pqc_algorithm_t) -> usize { - 0 - } - - pub unsafe fn bitcoin_pqc_secret_key_size(_algorithm: bitcoin_pqc_algorithm_t) -> usize { - 0 - } - - pub unsafe fn bitcoin_pqc_signature_size(_algorithm: bitcoin_pqc_algorithm_t) -> usize { - 0 - } -} - -// Re-export the right set of bindings based on configuration -#[cfg(doc)] -pub use doc_bindings::*; - -#[cfg(feature = "ide")] -pub use ide_bindings::*; diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 7e8e978ad6e7..000000000000 --- a/src/lib.rs +++ /dev/null @@ -1,698 +0,0 @@ -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -#[cfg(feature = "serde")] -use std::convert::TryFrom; -use std::error::Error as StdError; -use std::fmt; -use std::hash::Hash; -use std::ptr; - -use bitmask_enum::bitmask; -use secp256k1::{ - schnorr, All, Keypair as SecpKeypair, Secp256k1, SecretKey as SecpSecretKey, XOnlyPublicKey, -}; - -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -#[cfg(feature = "serde")] -mod hex_bytes { - use serde::{de::Error, Deserialize, Deserializer, Serializer}; - use std::vec::Vec; // Ensure Vec is in scope - - pub fn serialize(bytes: &Vec, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&hex::encode(bytes)) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - hex::decode(s).map_err(Error::custom) - } -} - -// Include the auto-generated bindings using our wrapper -// Make it pub(crate) so doctests can access these symbols -pub(crate) mod bindings_include; -// Use a glob import to get all the symbols consistently -use bindings_include::*; - -/// Error type for PQC operations -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] -pub enum PqcError { - /// Invalid arguments provided - BadArgument, - /// Not enough data provided (e.g., for key generation) - InsufficientData, - /// Invalid key provided or invalid format for the specified algorithm - BadKey, - /// Invalid signature provided or invalid format for the specified algorithm - BadSignature, - /// Algorithm not implemented (e.g., trying to sign/keygen Secp256k1) - NotImplemented, - /// Provided public key and signature algorithms do not match - AlgorithmMismatch, - /// Secp256k1 context error (should be rare with global context) - Secp256k1Error(secp256k1::Error), - /// Other unexpected error from the C library - Other(i32), -} - -impl fmt::Display for PqcError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - PqcError::BadArgument => write!(f, "Invalid arguments provided"), - PqcError::InsufficientData => write!(f, "Not enough data provided"), - PqcError::BadKey => write!(f, "Invalid key provided or invalid format"), - PqcError::BadSignature => write!(f, "Invalid signature provided or invalid format"), - PqcError::NotImplemented => write!(f, "Algorithm not implemented"), - PqcError::AlgorithmMismatch => { - write!(f, "Public key and signature algorithms mismatch") - } - PqcError::Secp256k1Error(e) => write!(f, "Secp256k1 error: {e}"), - PqcError::Other(code) => write!(f, "Unexpected error code: {code}"), - } - } -} - -impl StdError for PqcError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match self { - PqcError::Secp256k1Error(e) => Some(e), - _ => None, - } - } -} - -impl From for PqcError { - fn from(e: secp256k1::Error) -> Self { - PqcError::Secp256k1Error(e) - } -} - -impl From for Result<(), PqcError> { - fn from(error: bitcoin_pqc_error_t) -> Self { - match error { - bitcoin_pqc_error_t::BITCOIN_PQC_OK => Ok(()), - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => Err(PqcError::BadArgument), - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => Err(PqcError::BadKey), - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_SIGNATURE => Err(PqcError::BadSignature), - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => Err(PqcError::NotImplemented), - _ => Err(PqcError::Other(error.0)), - } - } -} - -/// PQC Algorithm type -#[bitmask(u8)] -// We derive serde conditionally, other traits like Debug, Clone, Eq, Hash etc. -// should be provided by the included C bindings or the bitmask macro. -#[cfg_attr( - feature = "serde", - derive(Serialize, Deserialize), - serde(try_from = "String", into = "String") -)] -pub enum Algorithm { - /// BIP-340 Schnorr + X-Only - Elliptic Curve Digital Signature Algorithm - SECP256K1_SCHNORR, - /// ML-DSA-44 (CRYSTALS-Dilithium) - Lattice-based signature scheme - ML_DSA_44, - /// SLH-DSA-Shake-128s (SPHINCS+) - Hash-based signature scheme - SLH_DSA_128S, -} - -impl From for bitcoin_pqc_algorithm_t { - fn from(alg: Algorithm) -> Self { - match alg { - Algorithm::SECP256K1_SCHNORR => bitcoin_pqc_algorithm_t::BITCOIN_PQC_SECP256K1_SCHNORR, - Algorithm::ML_DSA_44 => bitcoin_pqc_algorithm_t::BITCOIN_PQC_ML_DSA_44, - Algorithm::SLH_DSA_128S => bitcoin_pqc_algorithm_t::BITCOIN_PQC_SLH_DSA_SHAKE_128S, - _ => panic!("Invalid algorithm"), - } - } -} - -// Serde implementations using string representation directly on Algorithm -#[cfg(feature = "serde")] -impl TryFrom for Algorithm { - type Error = String; // Serde requires specific error handling - - fn try_from(s: String) -> Result { - match s.as_str() { - "SECP256K1_SCHNORR" => Ok(Algorithm::SECP256K1_SCHNORR), - "ML_DSA_44" => Ok(Algorithm::ML_DSA_44), - "SLH_DSA_128S" => Ok(Algorithm::SLH_DSA_128S), - _ => Err(format!("Unknown algorithm string: {s}")), - } - } -} - -#[cfg(feature = "serde")] -impl From for String { - fn from(alg: Algorithm) -> Self { - match alg { - Algorithm::SECP256K1_SCHNORR => "SECP256K1_SCHNORR".to_string(), - Algorithm::ML_DSA_44 => "ML_DSA_44".to_string(), - Algorithm::SLH_DSA_128S => "SLH_DSA_128S".to_string(), - _ => panic!("Invalid algorithm variant"), // Should not happen with bitmask - } - } -} - -impl fmt::Display for Algorithm { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - Algorithm::SECP256K1_SCHNORR => write!(f, "SECP256K1_SCHNORR"), - Algorithm::ML_DSA_44 => write!(f, "ML_DSA_44"), - Algorithm::SLH_DSA_128S => write!(f, "SLH_DSA_128S"), - _ => write!(f, "Unknown({:b})", self.bits), - } - } -} - -impl Algorithm { - /// Returns a user-friendly debug string with the algorithm name - pub fn debug_name(&self) -> String { - match *self { - Algorithm::SECP256K1_SCHNORR => "SECP256K1_SCHNORR".to_string(), - Algorithm::ML_DSA_44 => "ML_DSA_44".to_string(), - Algorithm::SLH_DSA_128S => "SLH_DSA_128S".to_string(), - _ => format!("Unknown({:b})", self.bits), - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct PublicKey { - /// The algorithm this key belongs to - #[cfg_attr(feature = "serde", serde(flatten))] - pub algorithm: Algorithm, - /// The raw key bytes (serialized as hex) - #[cfg_attr(feature = "serde", serde(with = "hex_bytes"))] - pub bytes: Vec, -} - -impl PublicKey { - /// Creates a PublicKey from an algorithm and a byte slice. - /// - /// Validates the length of the byte slice against the expected size for the algorithm. - /// For Secp256k1, also validates the byte format. - pub fn try_from_slice(algorithm: Algorithm, bytes: &[u8]) -> Result { - let expected_len = public_key_size(algorithm); - if bytes.len() != expected_len { - return Err(PqcError::BadKey); // Use BadKey for length mismatch - } - - // Additional validation for Secp256k1 keys - if algorithm == Algorithm::SECP256K1_SCHNORR { - XOnlyPublicKey::from_slice(bytes).map_err(|_| PqcError::BadKey)?; - } - - Ok(PublicKey { - algorithm, - bytes: bytes.to_vec(), - }) - } - - /// Creates a PublicKey from an algorithm and a hex string. - pub fn from_str(algorithm: Algorithm, s: &str) -> Result { - let bytes = hex::decode(s).map_err(|_| PqcError::BadArgument)?; - Self::try_from_slice(algorithm, &bytes) - } - - /// Returns the underlying secp256k1 XOnlyPublicKey if applicable. - pub fn secp256k1_key(&self) -> Result { - if self.algorithm == Algorithm::SECP256K1_SCHNORR { - XOnlyPublicKey::from_slice(&self.bytes).map_err(|_| PqcError::BadKey) - // Should be valid if constructed correctly - } else { - Err(PqcError::AlgorithmMismatch) - } - } -} - -/// Secret key wrapper -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct SecretKey { - /// The algorithm this key belongs to - #[cfg_attr(feature = "serde", serde(flatten))] - pub algorithm: Algorithm, - /// The raw key bytes (serialized as hex) - #[cfg_attr(feature = "serde", serde(with = "hex_bytes"))] - pub bytes: Vec, -} - -impl SecretKey { - /// Creates a SecretKey from an algorithm and a hex string. - pub fn from_str(algorithm: Algorithm, s: &str) -> Result { - let bytes = hex::decode(s).map_err(|_| PqcError::BadArgument)?; - Self::try_from_slice(algorithm, &bytes) - } - - /// Creates a SecretKey from an algorithm and a byte slice. - /// - /// Validates the length of the byte slice against the expected size for the algorithm. - /// For Secp256k1, also validates the byte format. - pub fn try_from_slice(algorithm: Algorithm, bytes: &[u8]) -> Result { - let expected_len = secret_key_size(algorithm); - if bytes.len() != expected_len { - return Err(PqcError::BadKey); - } - - // Additional validation for Secp256k1 keys - if algorithm == Algorithm::SECP256K1_SCHNORR { - // SecpSecretKey::from_slice does verification, checking if the key is valid (non-zero) - SecpSecretKey::from_slice(bytes).map_err(|_| PqcError::BadKey)?; - } - - Ok(SecretKey { - algorithm, - bytes: bytes.to_vec(), - }) - } - - /// Returns the underlying secp256k1 SecretKey if applicable. - pub fn secp256k1_key(&self) -> Result { - if self.algorithm == Algorithm::SECP256K1_SCHNORR { - SecpSecretKey::from_slice(&self.bytes).map_err(|_| PqcError::BadKey) - // Should be valid if constructed correctly - } else { - Err(PqcError::AlgorithmMismatch) - } - } -} - -impl Drop for SecretKey { - fn drop(&mut self) { - // Zero out secret key memory on drop - // Consider using crates like `zeroize` for more robust clearing - for byte in &mut self.bytes { - *byte = 0; - } - } -} - -/// Represents a signature (PQC or Secp256k1) -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct Signature { - /// The algorithm this signature belongs to - #[cfg_attr(feature = "serde", serde(flatten))] - pub algorithm: Algorithm, - /// The raw signature bytes (serialized as hex) - #[cfg_attr(feature = "serde", serde(with = "hex_bytes"))] - pub bytes: Vec, -} - -impl Signature { - /// Creates a Signature from an algorithm and a byte slice. - /// - /// Validates the length of the byte slice against the expected size for the algorithm. - /// For Secp256k1, also validates the byte format. - pub fn try_from_slice(algorithm: Algorithm, bytes: &[u8]) -> Result { - let expected_len = signature_size(algorithm); - if bytes.len() != expected_len { - return Err(PqcError::BadSignature); - } - - // Additional validation for Secp256k1 signatures - if algorithm == Algorithm::SECP256K1_SCHNORR { - // Schnorr signatures don't have a cheap validity check like keys, - // but from_slice checks the length (already done above). - schnorr::Signature::from_slice(bytes).map_err(|_| PqcError::BadSignature)?; - } - - Ok(Signature { - algorithm, - bytes: bytes.to_vec(), - }) - } - - /// Creates a Signature from an algorithm and a hex string. - pub fn from_str(algorithm: Algorithm, s: &str) -> Result { - let bytes = hex::decode(s).map_err(|_| PqcError::BadArgument)?; - Self::try_from_slice(algorithm, &bytes) - } - - /// Returns the underlying secp256k1 Schnorr Signature if applicable. - pub fn secp256k1_signature(&self) -> Result { - if self.algorithm == Algorithm::SECP256K1_SCHNORR { - schnorr::Signature::from_slice(&self.bytes).map_err(|_| PqcError::BadSignature) - // Should be valid if constructed correctly - } else { - Err(PqcError::AlgorithmMismatch) - } - } -} - -/// Key pair containing both public and secret keys -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -pub struct KeyPair { - /// The public key - pub public_key: PublicKey, - /// The secret key - pub secret_key: SecretKey, -} - -/// Generate a key pair for the specified algorithm using provided seed data. -/// -/// # Arguments -/// -/// * `algorithm` - The algorithm to use (PQC or Secp256k1) -/// * `random_data` - Seed bytes for key generation. -/// - For PQC algorithms, must be at least 128 bytes. -/// - For `SECP256K1_SCHNORR`, must be exactly 32 bytes representing the desired secret key. -/// -/// # Returns -/// -/// A new key pair on success, or an error if the `random_data` is invalid for the algorithm. -/// -pub fn generate_keypair(algorithm: Algorithm, random_data: &[u8]) -> Result { - if algorithm == Algorithm::SECP256K1_SCHNORR { - // For Secp256k1, random_data *is* the secret key. - let required_size = secret_key_size(algorithm); // Should be 32 - - // Check for insufficient data - if random_data.len() < required_size { - return Err(PqcError::InsufficientData); - } - - // Use the first 32 bytes, truncating excess data if provided - let key_data = &random_data[..required_size]; - - let secp = Secp256k1::::new(); // Context needed for key derivation - - // Attempt to create secret key from the provided data - let sk_result = SecpSecretKey::from_slice(key_data); - let sk = sk_result.map_err(|_| PqcError::BadKey)?; - - // Create KeyPair from secret key - let keypair = SecpKeypair::from_secret_key(&secp, &sk); - - // Derive the public key using from_keypair - let (pk, _parity) = XOnlyPublicKey::from_keypair(&keypair); // Destructure the tuple - - // Construct the structs - let public_key = PublicKey { - algorithm: Algorithm::SECP256K1_SCHNORR, - bytes: pk.serialize().to_vec(), // Serialize the XOnlyPublicKey part - }; - let secret_key = SecretKey { - algorithm: Algorithm::SECP256K1_SCHNORR, - bytes: sk.as_ref().to_vec(), // Use as_ref() to get &[u8] slice - }; - Ok(KeyPair { - public_key, - secret_key, - }) - } else { - // PQC key generation requires specific random data length - if random_data.len() < 128 { - return Err(PqcError::InsufficientData); - } - - unsafe { - let mut keypair = bitcoin_pqc_keypair_t { - algorithm: algorithm.into(), - public_key: ptr::null_mut(), - secret_key: ptr::null_mut(), - public_key_size: 0, - secret_key_size: 0, - }; - - let result = bitcoin_pqc_keygen( - algorithm.into(), - &mut keypair, - random_data.as_ptr(), - random_data.len(), - ); - - if result != bitcoin_pqc_error_t::BITCOIN_PQC_OK { - // Free potentially allocated (but invalid) memory on error - bitcoin_pqc_keypair_free(&mut keypair); - return Err(match result { - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => PqcError::BadArgument, - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => PqcError::BadKey, - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => { - PqcError::NotImplemented - } - _ => PqcError::Other(result.0 as i32), - }); - } - - // Extract and copy the keys - let pk_slice = std::slice::from_raw_parts( - keypair.public_key as *const u8, - keypair.public_key_size, - ); - let sk_slice = std::slice::from_raw_parts( - keypair.secret_key as *const u8, - keypair.secret_key_size, - ); - - let pk_bytes = pk_slice.to_vec(); - let sk_bytes = sk_slice.to_vec(); - - // Free the C memory - bitcoin_pqc_keypair_free(&mut keypair); - - // Construct the structs (validation is implicitly done by FFI success) - let public_key = PublicKey { - algorithm, - bytes: pk_bytes, - }; - let secret_key = SecretKey { - algorithm, - bytes: sk_bytes, - }; - - Ok(KeyPair { - public_key, - secret_key, - }) - } - } -} - -/// Sign a message using the specified secret key -/// -/// # Arguments -/// -/// * `secret_key` - The secret key to sign with -/// * `message` - The message to sign. -/// - For PQC algorithms, this is the raw message. -/// - For `SECP256K1_SCHNORR`, this *must* be a 32-byte hash of the message. -/// -/// # Returns -/// -/// A signature on success, or an error -pub fn sign(secret_key: &SecretKey, message: &[u8]) -> Result { - match secret_key.algorithm { - Algorithm::SECP256K1_SCHNORR => { - // For Secp256k1, message must be a 32-byte hash - let required_size = 32; - - // Check if message is too short - if message.len() < required_size { - return Err(PqcError::InsufficientData); - } - - // Use only the first 32 bytes if message is longer - let msg_data = &message[..required_size]; - - let secp = Secp256k1::::new(); // Signing context - - // Parse secret key - let sk = secret_key.secp256k1_key()?; - - // Create Keypair - let keypair = SecpKeypair::from_secret_key(&secp, &sk); - - // Sign using sign_schnorr_no_aux_rand with the (potentially truncated) message slice - let schnorr_sig = secp.sign_schnorr_no_aux_rand(msg_data, &keypair); - - // Construct result Signature - Ok(Signature { - algorithm: Algorithm::SECP256K1_SCHNORR, - bytes: schnorr_sig.as_ref().to_vec(), - }) - } - pqc_alg => { - // PQC Signing logic using FFI - unsafe { - let mut signature = bitcoin_pqc_signature_t { - algorithm: pqc_alg.into(), - signature: ptr::null_mut(), - signature_size: 0, - }; - - let result = bitcoin_pqc_sign( - pqc_alg.into(), - secret_key.bytes.as_ptr(), - secret_key.bytes.len(), - message.as_ptr(), - message.len(), - &mut signature, - ); - - if result != bitcoin_pqc_error_t::BITCOIN_PQC_OK { - return Err(match result { - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => PqcError::BadArgument, - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => PqcError::BadKey, - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_SIGNATURE => { - PqcError::BadSignature - } - bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => { - PqcError::NotImplemented - } - _ => PqcError::Other(result.0 as i32), - }); - } - - let sig_slice = std::slice::from_raw_parts( - signature.signature as *const u8, - signature.signature_size, - ); - let sig_bytes = sig_slice.to_vec(); - - bitcoin_pqc_signature_free(&mut signature); - - Ok(Signature { - algorithm: pqc_alg, - bytes: sig_bytes, - }) - } - } - } -} - -/// Verify a signature using the specified public key -/// -/// # Arguments -/// -/// * `public_key` - The public key to verify with -/// * `message` - The message that was signed (assumed to be pre-hashed for Secp256k1) -/// * `signature` - The signature to verify -/// -/// # Returns -/// -/// Ok(()) if the signature is valid, an error otherwise -pub fn verify( - public_key: &PublicKey, - message: &[u8], - signature: &Signature, -) -> Result<(), PqcError> { - // Ensure the key and signature algorithms match - if public_key.algorithm != signature.algorithm { - return Err(PqcError::AlgorithmMismatch); - } - - match public_key.algorithm { - Algorithm::SECP256K1_SCHNORR => { - // For Secp256k1, message must be a 32-byte hash - let required_size = 32; - - // Check if message is too short - if message.len() < required_size { - return Err(PqcError::InsufficientData); - } - - // Use only the first 32 bytes if message is longer - let msg_data = &message[..required_size]; - - // Use secp256k1 library for verification - let secp = Secp256k1::::verification_only(); - let pk = public_key.secp256k1_key()?; - let sig = signature.secp256k1_signature()?; - - // Verify using verify_schnorr with the (potentially truncated) message slice - secp.verify_schnorr(&sig, msg_data, &pk) - .map_err(PqcError::Secp256k1Error) - } - pqc_alg => { - // Length check for public key (still useful) - if public_key.bytes.len() != public_key_size(pqc_alg) { - return Err(PqcError::BadKey); - } - - // NOTE: We do NOT check the signature length here against signature_size(pqc_alg) - // because some algorithms like FN-DSA have variable signature lengths. - // The C library's verify function should handle invalid lengths internally. - - // PQC Verification logic using FFI - unsafe { - let result = bitcoin_pqc_verify( - pqc_alg.into(), - public_key.bytes.as_ptr(), - public_key.bytes.len(), - message.as_ptr(), - message.len(), - signature.bytes.as_ptr(), - signature.bytes.len(), - ); - result.into() // Converts C error enum to Result<(), PqcError> - } - } - } -} - -/// Get the public key size for an algorithm -/// -/// # Arguments -/// -/// * `algorithm` - The algorithm to get the size for -/// -/// # Returns -/// -/// The size in bytes -pub fn public_key_size(algorithm: Algorithm) -> usize { - if algorithm == Algorithm::SECP256K1_SCHNORR { - 32 // XOnlyPublicKey size - } else { - unsafe { bitcoin_pqc_public_key_size(algorithm.into()) } - } -} - -/// Get the secret key size for an algorithm -/// -/// # Arguments -/// -/// * `algorithm` - The algorithm to get the size for -/// -/// # Returns -/// -/// The size in bytes -pub fn secret_key_size(algorithm: Algorithm) -> usize { - if algorithm == Algorithm::SECP256K1_SCHNORR { - 32 // secp256k1::SecretKey size - } else { - unsafe { bitcoin_pqc_secret_key_size(algorithm.into()) } - } -} - -/// Get the signature size for an algorithm -/// -/// # Arguments -/// -/// * `algorithm` - The algorithm to get the size for -/// -/// # Returns -/// -/// The size in bytes -pub fn signature_size(algorithm: Algorithm) -> usize { - if algorithm == Algorithm::SECP256K1_SCHNORR { - 64 // schnorr::Signature size - } else { - unsafe { bitcoin_pqc_signature_size(algorithm.into()) } - } -} diff --git a/tests/algorithm_tests.rs b/tests/algorithm_tests.rs deleted file mode 100644 index e945e97e49b2..000000000000 --- a/tests/algorithm_tests.rs +++ /dev/null @@ -1,316 +0,0 @@ -use hex::decode as hex_decode; -use rand::{rng, RngCore}; - -use bitcoinpqc::{ - generate_keypair, public_key_size, secret_key_size, sign, signature_size, verify, Algorithm, -}; - -// Original random data generation function (commented out for deterministic tests) -fn _get_random_bytes_original(size: usize) -> Vec { - let mut bytes = vec![0u8; size]; - rng().fill_bytes(&mut bytes); - bytes -} - -// Function to return fixed test data based on predefined hex strings -// This ensures deterministic test results -fn get_random_bytes(size: usize) -> Vec { - match size { - 128 => { - // Fixed test vectors for key generation (128 bytes) - - // ML-DSA-44 key generation test vector - let ml_dsa_keygen_data = "20739d89b87379e83a915a0764366ed1e72eb307b3c7846dc135933370f00b266277961d536b47026f7eb874603384e3a2b9ea51f033aa4257acd17606d2cd86bc6c2a6745d59dcc148d5a8776be46e127e3ccf57212bd0eef8085aa871cc40b91693fd9a79034504f639cea0e618509afd84d943b3928524becc473c3fa3c2a"; - - // SLH-DSA-128S key generation test vector - let slh_dsa_keygen_data = "dd348981dfba96c006d27d64ad0ae37c9a358e3a03df7e9ffac1519eca12dc3b64bea0144f3536a74d9caba846b7143788e89a2a279a81947364f422d491dcb47925a77be4d551b25a81070e6a460effe30939224240e4f4dc9470d3d99f7312c24523a28128ea448ef47bcc1b0ae637ad6ece2251d3e2d55c0bba6d346ca66b"; - - // Deterministic signing test vectors - - // ML-DSA-44 deterministic signing test vector - let ml_dsa_det_data = "12187a59a14e1e9a0c37fc7625a0d3f8782f1e4cd361751abf7b85745173488e3e19afd47cbd4a823577cb360aed406791558ea1ff217fcd38af566e0e5d4d0903e6ea9c29108393c1a423f41b876b43ce0856ee436866f98d56ec8ceb169ed0470d847608f295474002a91a54937a64ac236fb9cf49fedf60b76500e3c0a7f0"; - - // SLH-DSA-128S deterministic signing test vector - let slh_dsa_det_data = "8ca905fd3e122d02e411683b52ecb1863104793aeba57718aabc9a65db5d61a66ca4bd29376d8118ceb555868b7054b59e23a45538d4ca28ad2080f70c56cce85f1fd5568661cb6ac06a9296ae77d97a7b854dab7eda10a4b78dd3a8f2e741f5c4686278eda9a1ac255a0cdbc79081435161331b69f9cbc04e7ae50cbfbab0ec"; - - // Choose which data to return based on the test context - let thread = std::thread::current(); - let test_name = thread.name().unwrap_or("unknown"); - - let hex_data = if test_name.contains("ml_dsa_44") { - ml_dsa_keygen_data - } else if test_name.contains("slh_dsa_128s") { - slh_dsa_keygen_data - } else if test_name.contains("deterministic_signing") { - // Choose based on current test progress - static mut COUNTER: usize = 0; - unsafe { - let data = match COUNTER { - 0 => ml_dsa_det_data, - _ => slh_dsa_det_data, - }; - COUNTER += 1; - data - } - } else { - // Default to ML-DSA data - ml_dsa_keygen_data - }; - - hex_decode(hex_data).expect("Invalid hex data") - } - 64 => { - // Fixed test vectors for signing (64 bytes) - - // ML-DSA-44 signing test vector - let ml_dsa_sign_data = "8fe682ed84da0fdfa9243c424c864b1d9137c0c87bc8f23dbea9268f3930c8a3778139311c18dadd6a9aea791486f2d7638a7be8f09ca3546580312a8bb95f97"; - - // SLH-DSA-128S signing test vector - let slh_dsa_sign_data = "c2dd94eec866f66b5fe8cbc07cfdbc8b4b92880f4fe53131feb1539323e87f64d3b32fd22375ead15c6c0f5c68323ed343041acfd3d962382b406e9aa30aa45c"; - - // Choose which data to return based on the test context - let thread = std::thread::current(); - let test_name = thread.name().unwrap_or("unknown"); - - let hex_data = if test_name.contains("ml_dsa_44") { - ml_dsa_sign_data - } else if test_name.contains("slh_dsa_128s") { - slh_dsa_sign_data - } else { - // Default to ML-DSA data - ml_dsa_sign_data - }; - - hex_decode(hex_data).expect("Invalid hex data") - } - _ => { - // Fallback for other sizes (e.g., 127 for error condition tests) - // This still uses random data since it's typically for error cases - let mut bytes = vec![0u8; size]; - rng().fill_bytes(&mut bytes); - bytes - } - } -} - -#[test] -fn test_key_sizes() { - // Verify the key and signature sizes are as expected - assert_eq!(public_key_size(Algorithm::ML_DSA_44), 1312); - assert_eq!(secret_key_size(Algorithm::ML_DSA_44), 2560); - assert_eq!(signature_size(Algorithm::ML_DSA_44), 2420); - - assert_eq!(public_key_size(Algorithm::SLH_DSA_128S), 32); - assert_eq!(secret_key_size(Algorithm::SLH_DSA_128S), 64); - assert_eq!(signature_size(Algorithm::SLH_DSA_128S), 7856); -} - -#[test] -fn test_ml_dsa_44_keygen_sign_verify() { - println!("Starting ML-DSA-44 test"); - let random_data = get_random_bytes(128); - println!("Generated random data of size {}", random_data.len()); - - let keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data) - .expect("Failed to generate ML-DSA-44 keypair"); - - println!("Key generation successful"); - - // Verify the key sizes match expected values - assert_eq!( - keypair.public_key.bytes.len(), - public_key_size(Algorithm::ML_DSA_44) - ); - println!("Public key size: {}", keypair.public_key.bytes.len()); - - assert_eq!( - keypair.secret_key.bytes.len(), - secret_key_size(Algorithm::ML_DSA_44) - ); - println!("Secret key size: {}", keypair.secret_key.bytes.len()); - - // Test signing and verification - let message = b"ML-DSA-44 Test Message"; - println!("Message to sign: {message:?}"); - - let signature = sign(&keypair.secret_key, message).expect("Failed to sign with ML-DSA-44"); - - println!( - "Signature created successfully, size: {}", - signature.bytes.len() - ); - println!( - "Signature prefix: {:02x?}", - &signature.bytes[..8.min(signature.bytes.len())] - ); - - // Verify the signature - println!("Verifying signature..."); - let result = verify(&keypair.public_key, message, &signature); - println!("Verification result: {result:?}"); - - assert!(result.is_ok(), "ML-DSA-44 signature verification failed"); - - // Try to verify with a modified message - should fail - let modified_message = b"ML-DSA-44 Modified Message"; - println!("Modified message: {modified_message:?}"); - - let result = verify(&keypair.public_key, modified_message, &signature); - println!("Verification with modified message result: {result:?}"); - - assert!( - result.is_err(), - "ML-DSA-44 verification should fail with modified message" - ); -} - -#[test] -fn test_slh_dsa_128s_keygen_sign_verify() { - println!("Starting SLH-DSA-128S test"); - let random_data = get_random_bytes(128); - println!("Generated random data of size {}", random_data.len()); - - let keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data) - .expect("Failed to generate SLH-DSA-128S keypair"); - - println!("Key generation successful"); - - // Verify the key sizes match expected values - assert_eq!( - keypair.public_key.bytes.len(), - public_key_size(Algorithm::SLH_DSA_128S) - ); - println!("Public key size: {}", keypair.public_key.bytes.len()); - - assert_eq!( - keypair.secret_key.bytes.len(), - secret_key_size(Algorithm::SLH_DSA_128S) - ); - println!("Secret key size: {}", keypair.secret_key.bytes.len()); - - // Test signing and verification - let message = b"SLH-DSA-128S Test Message"; - println!("Message to sign: {message:?}"); - - let signature = sign(&keypair.secret_key, message).expect("Failed to sign with SLH-DSA-128S"); - - println!( - "Signature created successfully, size: {}", - signature.bytes.len() - ); - println!( - "Signature prefix: {:02x?}", - &signature.bytes[..8.min(signature.bytes.len())] - ); - - // Verify the signature - println!("Verifying signature..."); - let result = verify(&keypair.public_key, message, &signature); - println!("Verification result: {result:?}"); - - assert!(result.is_ok(), "SLH-DSA-128S signature verification failed"); - - // Try to verify with a modified message - should fail - let modified_message = b"SLH-DSA-128S Modified Message"; - println!("Modified message: {modified_message:?}"); - - let result = verify(&keypair.public_key, modified_message, &signature); - println!("Verification with modified message result: {result:?}"); - - assert!( - result.is_err(), - "SLH-DSA-128S verification should fail with modified message" - ); -} - -#[test] -fn test_deterministic_signing() { - // Test ML-DSA-44 deterministic signing - let random_data = get_random_bytes(128); - let keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data) - .expect("Failed to generate ML-DSA-44 keypair"); - let message = b"Test message for deterministic signing"; - - // Generate first signature - let signature1 = sign(&keypair.secret_key, message).expect("Failed to create first signature"); - // Generate second signature (should be identical with deterministic signing) - let signature2 = sign(&keypair.secret_key, message).expect("Failed to create second signature"); - - // Verify both signatures - assert!( - verify(&keypair.public_key, message, &signature1).is_ok(), - "First ML-DSA-44 signature should be valid" - ); - assert!( - verify(&keypair.public_key, message, &signature2).is_ok(), - "Second ML-DSA-44 signature should be valid" - ); - - // Test SLH-DSA-128S deterministic signing - let random_data = get_random_bytes(128); - let keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data) - .expect("Failed to generate SLH-DSA-128S keypair"); - let message = b"Test message for deterministic signing"; - - // Generate first signature - let signature1 = sign(&keypair.secret_key, message).expect("Failed to create first signature"); - // Generate second signature (should be identical with deterministic signing) - let signature2 = sign(&keypair.secret_key, message).expect("Failed to create second signature"); - - // Verify both signatures - assert!( - verify(&keypair.public_key, message, &signature1).is_ok(), - "First SLH-DSA-128S signature should be valid" - ); - assert!( - verify(&keypair.public_key, message, &signature2).is_ok(), - "Second SLH-DSA-128S signature should be valid" - ); -} - -#[test] -fn test_error_conditions() { - // Test with insufficient random data for key generation for all algorithms - let short_random = get_random_bytes(127); // Need at least 128 bytes - - // Test ML-DSA-44 - let result = generate_keypair(Algorithm::ML_DSA_44, &short_random); - assert!( - result.is_err(), - "ML-DSA-44 should fail with insufficient random data" - ); - - // Test SLH-DSA-128S - let result = generate_keypair(Algorithm::SLH_DSA_128S, &short_random); - assert!( - result.is_err(), - "SLH-DSA-128S should fail with insufficient random data" - ); - - // Create valid keypairs for ML-DSA and SLH-DSA - let random_data = get_random_bytes(128); - let ml_keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data) - .expect("Failed to generate ML-DSA-44 keypair"); - let slh_keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data) - .expect("Failed to generate SLH-DSA-128S keypair"); - - // Create message for testing - let message = b"Test message"; - - // Create signatures - let ml_sig = sign(&ml_keypair.secret_key, message).expect("Failed to sign with ML-DSA-44"); - let slh_sig = sign(&slh_keypair.secret_key, message).expect("Failed to sign with SLH-DSA-128S"); - - // Try to verify with mismatched algorithms - let result = verify(&slh_keypair.public_key, message, &ml_sig); - assert!( - result.is_err(), - "Verification should fail with ML-DSA-44 signature and SLH-DSA-128S key" - ); - - let result = verify(&ml_keypair.public_key, message, &slh_sig); - assert!( - result.is_err(), - "Verification should fail with SLH-DSA-128S signature and ML-DSA-44 key" - ); -} diff --git a/tests/serialization_tests.rs b/tests/serialization_tests.rs deleted file mode 100644 index cc14377509b1..000000000000 --- a/tests/serialization_tests.rs +++ /dev/null @@ -1,447 +0,0 @@ -use hex::{decode as hex_decode, encode as hex_encode}; -use rand::{rng, RngCore}; - -use bitcoinpqc::{generate_keypair, sign, verify, Algorithm, PublicKey, SecretKey, Signature}; - -// Original random data generation function (commented out for deterministic tests) -fn _get_random_bytes_original(size: usize) -> Vec { - let mut bytes = vec![0u8; size]; - rng().fill_bytes(&mut bytes); - bytes -} - -// Function to return fixed test data based on predefined hex strings -// This ensures deterministic test results -fn get_random_bytes(size: usize) -> Vec { - match size { - 128 => { - // Single common test vector for all tests (128 bytes) - let random_data = "f47e7324fb639d867a35eea3558a54224e7ca5e357c588c136d2d514facd5fc0d93a31a624a7c3d9ba02f8a73bd2e9dac7b2e3a0dcf1900b2c3b8e56c6efec7ef2aa654567e42988f6c1b71ae817db8f7dbf25c5e7f3ddc87f39b8fc9b3c44caacb6fe8f9df68e895f6ae603e1c4db3c6a0e1ba9d52ac34a63426f9be2e2ac16"; - hex_decode(random_data).expect("Invalid hex data") - } - 64 => { - // Fixed test vector for signing (64 bytes) - let sign_data = "7b8681d6e06fa65ef3b77243e7670c10e7c983cbe07f09cb1ddd10e9c4bc8ae6409a756b5bc35a352ab7dcf08395ce6994f4aafa581a843db147db47cf2e6fbd"; - hex_decode(sign_data).expect("Invalid hex data") - } - _ => { - // Fallback for other sizes - let mut bytes = vec![0u8; size]; - rng().fill_bytes(&mut bytes); - bytes - } - } -} - -#[test] -fn test_public_key_serialization() { - // Generate a keypair with deterministic data - let random_data = get_random_bytes(128); - let keypair = - generate_keypair(Algorithm::ML_DSA_44, &random_data).expect("Failed to generate keypair"); - - // Print public key prefix for informational purposes - let pk_prefix = hex_encode(&keypair.public_key.bytes[0..16]); - println!("ML-DSA-44 Public key prefix: {pk_prefix}"); - - // Check the public key has the expected length - assert_eq!( - keypair.public_key.bytes.len(), - 1312, - "Public key should have the correct length" - ); - - // Check the public key has a non-empty prefix - assert!( - !pk_prefix.is_empty(), - "Public key should have a non-empty prefix" - ); - - // Extract the public key bytes - let pk_bytes = keypair.public_key.bytes.clone(); - - // Create a new PublicKey from the bytes - let reconstructed_pk = PublicKey { - algorithm: Algorithm::ML_DSA_44, - bytes: pk_bytes, - }; - - // Sign a message using the original key - let message = b"Serialization test message"; - let signature = sign(&keypair.secret_key, message).expect("Failed to sign message"); - - // Print signature for informational purposes - println!( - "ML-DSA-44 Signature prefix: {}", - hex_encode(&signature.bytes[0..16]) - ); - - // Verify the signature using the reconstructed public key - let result = verify(&reconstructed_pk, message, &signature); - assert!( - result.is_ok(), - "Verification with reconstructed public key failed" - ); -} - -#[test] -fn test_secret_key_serialization() { - // Generate a keypair with deterministic data - let random_data = get_random_bytes(128); - let keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data) - .expect("Failed to generate keypair"); - - // Print key prefixes for diagnostic purposes - let sk_prefix = hex_encode(&keypair.secret_key.bytes[0..16]); - let pk_prefix = hex_encode(&keypair.public_key.bytes[0..16]); - println!("SLH-DSA-128S Secret key prefix: {sk_prefix}"); - println!("SLH-DSA-128S Public key prefix: {pk_prefix}"); - - // Extract the secret key bytes - let sk_bytes = keypair.secret_key.bytes.clone(); - - // Create a new SecretKey from the bytes - let reconstructed_sk = SecretKey { - algorithm: Algorithm::SLH_DSA_128S, - bytes: sk_bytes, - }; - - // Sign a message using the reconstructed secret key - let message = b"Secret key serialization test message"; - let signature = - sign(&reconstructed_sk, message).expect("Failed to sign with reconstructed key"); - - // Print signature for informational purposes - println!( - "SLH-DSA-128S Signature prefix: {}", - hex_encode(&signature.bytes[0..16]) - ); - - // Verify the signature using the original public key - let result = verify(&keypair.public_key, message, &signature); - assert!( - result.is_ok(), - "Verification of signature from reconstructed secret key failed" - ); -} - -#[test] -fn test_signature_serialization() { - // Generate a keypair with deterministic data - let random_data = get_random_bytes(128); - let keypair = - generate_keypair(Algorithm::ML_DSA_44, &random_data).expect("Failed to generate keypair"); - - // Sign a message - let message = b"Signature serialization test"; - let signature = sign(&keypair.secret_key, message).expect("Failed to sign message"); - - // Print signature for informational purposes - println!( - "ML-DSA-44 Signature prefix: {}", - hex_encode(&signature.bytes[0..16]) - ); - - // Create a new Signature from the bytes - let reconstructed_sig = Signature { - algorithm: Algorithm::ML_DSA_44, - bytes: signature.bytes.clone(), - }; - - // Verify that the reconstructed signature bytes match - assert_eq!( - signature.bytes, reconstructed_sig.bytes, - "Reconstructed signature bytes should match original" - ); - - // Verify the reconstructed signature - let result = verify(&keypair.public_key, message, &reconstructed_sig); - assert!( - result.is_ok(), - "Verification with reconstructed signature failed" - ); -} - -#[test] -fn test_cross_algorithm_serialization_failure() { - // Generate keypairs for different algorithms with deterministic data - let random_data = get_random_bytes(128); - let keypair_ml_dsa = generate_keypair(Algorithm::ML_DSA_44, &random_data) - .expect("Failed to generate ML-DSA keypair"); - let keypair_slh_dsa = generate_keypair(Algorithm::SLH_DSA_128S, &random_data) - .expect("Failed to generate SLH-DSA keypair"); - - // Sign with ML-DSA - let message = b"Cross algorithm test"; - let signature = sign(&keypair_ml_dsa.secret_key, message).expect("Failed to sign message"); - - // Print signature for informational purposes - println!( - "ML-DSA signature prefix: {}", - hex_encode(&signature.bytes[0..16]) - ); - - // Attempt to verify ML-DSA signature with SLH-DSA public key - // This should fail because the algorithms don't match - let result = verify(&keypair_slh_dsa.public_key, message, &signature); - assert!( - result.is_err(), - "Verification should fail when using public key from different algorithm" - ); - - // Create an invalid signature by changing the algorithm but keeping the bytes - let invalid_sig = Signature { - algorithm: Algorithm::SLH_DSA_128S, // Wrong algorithm - bytes: signature.bytes.clone(), - }; - - // This should fail because the signature was generated with ML-DSA but claimed to be SLH-DSA - let result = verify(&keypair_slh_dsa.public_key, message, &invalid_sig); - assert!( - result.is_err(), - "Verification should fail with mismatched algorithm" - ); - - // Also verify that the library correctly checks algorithm consistency - let result = verify(&keypair_ml_dsa.public_key, message, &invalid_sig); - assert!( - result.is_err(), - "Verification should fail when signature algorithm doesn't match public key algorithm" - ); -} - -// Add new test for serialization consistency -#[test] -fn test_serialization_consistency() { - // Generate keypairs for each algorithm using deterministic data - let random_data = get_random_bytes(128); - - // ML-DSA-44 - let ml_keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data) - .expect("Failed to generate ML-DSA keypair"); - - // Expected ML-DSA key serialization (from test output) - let expected_ml_pk_prefix = "b3f22d3e1f93e3122063898b98eb89e6"; - let expected_ml_sk_prefix = "b3f22d3e1f93e3122063898b98eb89e6"; - - // Print and verify ML-DSA public key - let actual_ml_pk_prefix = hex_encode(&ml_keypair.public_key.bytes[0..16]); - println!("ML-DSA-44 public key prefix: {actual_ml_pk_prefix}"); - - assert_eq!( - actual_ml_pk_prefix, expected_ml_pk_prefix, - "ML-DSA-44 public key serialization should be deterministic" - ); - - // Print and verify ML-DSA secret key - let actual_ml_sk_prefix = hex_encode(&ml_keypair.secret_key.bytes[0..16]); - println!("ML-DSA-44 secret key prefix: {actual_ml_sk_prefix}"); - - assert_eq!( - actual_ml_sk_prefix, expected_ml_sk_prefix, - "ML-DSA-44 secret key serialization should be deterministic" - ); - - // SLH-DSA-128S - Just print for informational purposes - let slh_keypair = generate_keypair(Algorithm::SLH_DSA_128S, &random_data) - .expect("Failed to generate SLH-DSA keypair"); - - println!( - "SLH-DSA-128S public key prefix: {}", - hex_encode(&slh_keypair.public_key.bytes[0..16]) - ); - println!( - "SLH-DSA-128S secret key prefix: {}", - hex_encode(&slh_keypair.secret_key.bytes[0..16]) - ); - - // Test serialization/deserialization consistency - let message = b"Serialization consistency test"; - - // ML-DSA-44 signature consistency - let ml_sig = sign(&ml_keypair.secret_key, message).expect("Failed to sign with ML-DSA-44"); - - // Print ML-DSA signature for informational purposes - println!( - "ML-DSA-44 signature prefix: {}", - hex_encode(&ml_sig.bytes[0..16]) - ); - - // Verify keys generated with the same random data are consistent - let new_ml_keypair = generate_keypair(Algorithm::ML_DSA_44, &random_data) - .expect("Failed to generate second ML-DSA-44 keypair"); - - assert_eq!( - hex_encode(&ml_keypair.public_key.bytes), - hex_encode(&new_ml_keypair.public_key.bytes), - "ML-DSA-44 public key generation should be deterministic" - ); - - assert_eq!( - hex_encode(&ml_keypair.secret_key.bytes), - hex_encode(&new_ml_keypair.secret_key.bytes), - "ML-DSA-44 secret key generation should be deterministic" - ); -} - -// // Add new test for serde roundtrip serialization/deserialization -// #[cfg(feature = "serde")] -// #[test] -// fn test_serde_roundtrip() { -// // Use deterministic random data -// let random_data = get_random_bytes(128); -// let message = b"Serde roundtrip test message"; - -// // Test each algorithm -// for algorithm in [Algorithm::ML_DSA_44, Algorithm::SLH_DSA_128S].iter() { -// // Generate keypair -// let keypair = generate_keypair(*algorithm, &random_data) -// .unwrap_or_else(|_| panic!("Failed to generate keypair for {algorithm:?}")); - -// // Sign message -// let signature = sign(&keypair.secret_key, message) -// .unwrap_or_else(|_| panic!("Failed to sign message for {algorithm:?}")); - -// // --- PublicKey Test --- -// let pk_json = serde_json::to_string_pretty(&keypair.public_key) -// .expect("Failed to serialize PublicKey"); // Use pretty print for readability - -// // Define the expected fixture (UPDATE THIS STRING) -// let expected_pk_json = match *algorithm { -// Algorithm::ML_DSA_44 => { -// r#"{ -// "algorithm": "ML_DSA_44", -// "bytes": "b3f22d3e1f93e3122063898b98eb89e65278d56bd6e81478d0f45dbd94640febdec294921bd45b3bea23bc1d0158e1e34daf4c82e734524d505d10fa6113285e726ac719246cc34d032fd1e16c85821597acd5452af5a87e5fc84d8c5f332c839c0cd9d48b1dfa47352976ad7835e36577fdb30126c28ce2d214584ee2dbc2ca8a40499c02442015268800312090890b331250b40ccc8869031210910411d1c4501b24121b060a8b126cc80265e0364294184d99c464cc2866d2326998486601894880b06d984891a0142119491104106c5384450a05625c100a2421508c021049944192b22da422681aa2049c002202478810134618113224983081c20c1a1500212191db984d0b488164868d61308804298421a630d4340a984449c0426002a690c04249031721821802901091843820d2b41010c529e02405e3342823164111099192800123161220c925029785181728e1c6891b883181c6655c488249b64009a07082802dc042692422310b804411142264203111456c1c308104220a4b16801b432401a169032832d98209531489e4123198c001449631a2486119924c1c258444008d4232860316642147060c272821b70021266ae3c67122b760102170109808a444294b900823b1704a8040d4188611b0091c24001218669a82419b0060d3c04cd9400dca4471221724003846981461c9962dd038401022851345729b304622b8044a0461d186651895805936698aa27091802c928000cc8811c94885003389098021994680a3a251942652c9426c9ac669d38890910661cb9270211300c41884e190400a1062e11841d2245160308e59064a94908899b83123956454c28801c060c4868d5a948850806004463199880852960c60208021b94519366d0189051b086624328d89c26da11865203428d8a45041b8896498711c450e621468024290c194301a990c5916711a05304112280027210b2741c4c289d39465c3365240c850e0c04114444a64203109884114a13154902844c88001c26493807193a49101c6082003266146529c28110c12024c4088c9b00d1ac08153464013a88010426c08890823271290b62091228a6418458ba0641c272acc8630e0486d0ca371d3868da0168e48a23062800580142189b268a2884d0c373214038090c4711b477258002e64026a1aa12d00c8245b98684844019a004149026d10a08d82840012b45102435221a32d5b908c648290939250023986081711212905dcc2619d5be95a339c1bc29c0538fe02924c096b7c7063deb34148fc2ac4297d5f2e85aea1ef57e1236204f75c6264559eb6f933df5b55302d09d6c6cb889fd44508a2122accc2b3cc2a0699147ec848a846c37c33f55dad55aff5de196966d3d01f71aca8fbb72c9d9018e0830a5eb3424bccae6288c13558faf85f1b8f095365a6c7d3b699f9a6332a377b12498df39a595fe1265eb04f10c81b826aed2a266bab5d2ce07020395961fd6358cbabde2264c6083cda237f13db7481d6100b46480bef4652c786871196fec4564a96ab056f8c15586b351391a6d808c9e7f4359a1499f8f07d99aad4e589a25be4e617ab70b39ba9eed53aaec3a4bc400e294d7eed7583489cd5cf6ae450fafe2db09098fd0a8ccc68e4d2b77064874501daf62757daf653365acfaca2df2280520f8374ac8d5e84b6a43f98f4afae4f84413c030ec7f21cf0e8a7d23b5d12654f7364460c5d8b4c75f790e3ba538c2e3f776b2769b794f45d1e1aac14febcb24eb335afac4154a73dd4435ebb9d5326d74dfaf349e44d88703c08748d6c850d4107990f0a18fecf2beebb88123894d489cbfe0c26fb88ca76a89ab233fec7a5cbb8566145c0a4a3a0d86f9e9689e5450f90d3a099870cea373243793ca3e5a92ff916f935fabacda0bf6bd8977b1bcf36f52f7812645e615f26e7df37c7278da16e8024d9027673f942fd7b8d738b525a629f1ba6ac66779db0bd8c90ab3903f7e9047f66b21dac94a9c335fe6aa78c6927663c0a74c89550bdc9d8201127984aa89ee2b80728be9b3f0d54a73172ba2ea4d1f7c4804af6998f8cd081d2e04b5448d2952749e09dae4354b893f26d355635d20764055e30459c613bb32fdb4ae074f545deafb3c532aac9559c8d3674cd132e4f854f1d9aab8c23bc94a0269a61b0f3d0b5ac3afb1ea35a45aca151ec63ec5bcc02ca647f2982c205549a2c8a5382ddd0c9e06ce545a18718a1bcea27623814bd3a8ce3b8ff8494f89cc32e05bd5749daa63b894685ce6906dfbfc411c2917d4b35fed903d8dc22a3056c28438c772c592d850a4d58becf2a286ed2e72f4ec13835236b3734367ea0b0f2eb38eff07c87d69fc4c7e86dd135459da3c96aa34400ca2db9eac2018a6a9c8d1339b6752023df35e1bb97b44555d194bae18232f68d2206fc35ba3754a33c91e82819c62ef864166910c7e40ed375647069d98fe7805e75e285a160a7950348304791208d4d82c5410ea019c39076ec36e8ed9a4d3eb87dac7eb3067b5776535301d2c622e7fa67a13d70cc4450c3093c5a47689e90a1b4178ccde8719baed1d3a2630078740a502977474b7025abdcb7998ec442d5aea31d6a8533aacff0111f935de36dfc6e266701d7c3778e7f4ebfa6f7ff9e6b1fab8962f30e5276b2a76f20acbf7087bd2d092dbf642843fa980f8a4b80ce730902c0e637f6c480f1f441ee731c9fa4d33258d00ff47be9b413eb176ac1cbc0c06edf67a59f9a996f9175327de3b829d1d830a638bf6056a87ec4150b440440a2ef9e5bafcdcedf4753ff11b1f2b00e52070f4984af34cefd224f36e6d04358418b05e52ed089dac28aac67c0e4d0ab79e4ee82377c9c4ceda877dcdc2fad48a88ae1fe4cc2582f1e41b5d557897902435a27a9bffc63357135c7e6e60516f56dccbd412afb250f117cbfa234619d75f199e397c587c523e4942728cd7d4d59aca9b52fa9364a7b81d9fd7c23e688b04bdaa986e21d7dbfcbfa634b8fcdfa2619d9b6904e3d8e3205bbf5a3d526c4bf9017723fa8944a0b08595e5252e361c5a353ae737177f043e9c2460f48a8aadbd342d773ad6e034191763d87e8c33a3a443cba0174f0bc49385b5a6ca75bb7c000888dcef43bc22252eac9710afb4a6c7a63b363d08e083e691aa848cad7bec731067a1a90a7803328aed4c987eb586461a523ab8fbda4829511f7a427940b94351966c8cb37dc22dd34a81c0542adeb97fff1f1460e72c575c9d18c571ae7175a9ce269fc570c0945484e6e5fca628b5bf0904bad7027e691f1fc8d740ed172fe8816b06b7a672d67faffa91affad41828204d5dbc10c68edbe911131c6f8993c054a2165675794bf6dd1b617a9e5fca0a1a884b21d236163c559be4daf02d5ed54034f735fb031bc17e95066ab3ac9120fd24e238e6255f5ae72fe81c0f9fb69979c746b893421842aa7641d50ff2b2506d078b0aeee703f08223be66255e62fa568a244ef8642eda22ca33472c07e3d8398fe12dae1dcb37dab68aca08a8aa439c4f2257910a0f46af5bcbdad3f987c17ac6c52703a04705ed920c69526fc748f366974706d19143cef2c3441ffa01e06" -// }"# -// } -// Algorithm::SLH_DSA_128S => { -// r#"{ -// "algorithm": "SLH_DSA_128S", -// "bytes": "f47e7324fb639d867a35eea3558a54224e7ca5e357c588c136d2d514facd5fc0d93a31a624a7c3d9ba02f8a73bd2e9dad0261c237a3fa1df610b30f2a06bc750" -// }"# -// } -// _ => panic!("Fixture missing for algorithm {algorithm:?}"), -// }; - -// println!("Algorithm: {algorithm:?}, Generated PublicKey JSON:\n{pk_json}"); // Print generated JSON to help update fixtures -// assert_eq!( -// pk_json, -// serde_json::to_string_pretty( -// &serde_json::from_str::(expected_pk_json).unwrap() -// ) -// .unwrap(), // Compare pretty formats -// "PublicKey JSON does not match fixture for {algorithm:?}" -// ); - -// // Roundtrip check (still useful) -// let reconstructed_pk: PublicKey = -// serde_json::from_str(&pk_json).expect("Failed to deserialize PublicKey"); -// assert_eq!( -// keypair.public_key, reconstructed_pk, -// "PublicKey roundtrip failed for {algorithm:?}" -// ); - -// // --- SecretKey Test --- -// let sk_json = serde_json::to_string_pretty(&keypair.secret_key) -// .expect("Failed to serialize SecretKey"); - -// // Define the expected fixture (UPDATE THIS STRING) -// let expected_sk_json = match *algorithm { -// Algorithm::ML_DSA_44 => { -// r#"{ -// "algorithm": "ML_DSA_44", -// "bytes": "b3f22d3e1f93e3122063898b98eb89e65278d56bd6e81478d0f45dbd94640febdec294921bd45b3bea23bc1d0158e1e34daf4c82e734524d505d10fa6113285e726ac719246cc34d032fd1e16c85821597acd5452af5a87e5fc84d8c5f332c839c0cd9d48b1dfa47352976ad7835e36577fdb30126c28ce2d214584ee2dbc2ca8a40499c02442015268800312090890b331250b40ccc8869031210910411d1c4501b24121b060a8b126cc80265e0364294184d99c464cc2866d2326998486601894880b06d984891a0142119491104106c5384450a05625c100a2421508c021049944192b22da422681aa2049c002202478810134618113224983081c20c1a1500212191db984d0b488164868d61308804298421a630d4340a984449c0426002a690c04249031721821802901091843820d2b41010c529e02405e3342823164111099192800123161220c925029785181728e1c6891b883181c6655c488249b64009a07082802dc042692422310b804411142264203111456c1c308104220a4b16801b432401a169032832d98209531489e4123198c001449631a2486119924c1c258444008d4232860316642147060c272821b70021266ae3c67122b760102170109808a444294b900823b1704a8040d4188611b0091c24001218669a82419b0060d3c04cd9400dca4471221724003846981461c9962dd038401022851345729b304622b8044a0461d186651895805936698aa27091802c928000cc8811c94885003389098021994680a3a251942652c9426c9ac669d38890910661cb9270211300c41884e190400a1062e11841d2245160308e59064a94908899b83123956454c28801c060c4868d5a948850806004463199880852960c60208021b94519366d0189051b086624328d89c26da11865203428d8a45041b8896498711c450e621468024290c194301a990c5916711a05304112280027210b2741c4c289d39465c3365240c850e0c04114444a64203109884114a13154902844c88001c26493807193a49101c6082003266146529c28110c12024c4088c9b00d1ac08153464013a88010426c08890823271290b62091228a6418458ba0641c272acc8630e0486d0ca371d3868da0168e48a23062800580142189b268a2884d0c373214038090c4711b477258002e64026a1aa12d00c8245b98684844019a004149026d10a08d82840012b45102435221a32d5b908c648290939250023986081711212905dcc2619d5be95a339c1bc29c0538fe02924c096b7c7063deb34148fc2ac4297d5f2e85aea1ef57e1236204f75c6264559eb6f933df5b55302d09d6c6cb889fd44508a2122accc2b3cc2a0699147ec848a846c37c33f55dad55aff5de196966d3d01f71aca8fbb72c9d9018e0830a5eb3424bccae6288c13558faf85f1b8f095365a6c7d3b699f9a6332a377b12498df39a595fe1265eb04f10c81b826aed2a266bab5d2ce07020395961fd6358cbabde2264c6083cda237f13db7481d6100b46480bef4652c786871196fec4564a96ab056f8c15586b351391a6d808c9e7f4359a1499f8f07d99aad4e589a25be4e617ab70b39ba9eed53aaec3a4bc400e294d7eed7583489cd5cf6ae450fafe2db09098fd0a8ccc68e4d2b77064874501daf62757daf653365acfaca2df2280520f8374ac8d5e84b6a43f98f4afae4f84413c030ec7f21cf0e8a7d23b5d12654f7364460c5d8b4c75f790e3ba538c2e3f776b2769b794f45d1e1aac14febcb24eb335afac4154a73dd4435ebb9d5326d74dfaf349e44d88703c08748d6c850d4107990f0a18fecf2beebb88123894d489cbfe0c26fb88ca76a89ab233fec7a5cbb8566145c0a4a3a0d86f9e9689e5450f90d3a099870cea373243793ca3e5a92ff916f935fabacda0bf6bd8977b1bcf36f52f7812645e615f26e7df37c7278da16e8024d9027673f942fd7b8d738b525a629f1ba6ac66779db0bd8c90ab3903f7e9047f66b21dac94a9c335fe6aa78c6927663c0a74c89550bdc9d8201127984aa89ee2b80728be9b3f0d54a73172ba2ea4d1f7c4804af6998f8cd081d2e04b5448d2952749e09dae4354b893f26d355635d20764055e30459c613bb32fdb4ae074f545deafb3c532aac9559c8d3674cd132e4f854f1d9aab8c23bc94a0269a61b0f3d0b5ac3afb1ea35a45aca151ec63ec5bcc02ca647f2982c205549a2c8a5382ddd0c9e06ce545a18718a1bcea27623814bd3a8ce3b8ff8494f89cc32e05bd5749daa63b894685ce6906dfbfc411c2917d4b35fed903d8dc22a3056c28438c772c592d850a4d58becf2a286ed2e72f4ec13835236b3734367ea0b0f2eb38eff07c87d69fc4c7e86dd135459da3c96aa34400ca2db9eac2018a6a9c8d1339b6752023df35e1bb97b44555d194bae18232f68d2206fc35ba3754a33c91e82819c62ef864166910c7e40ed375647069d98fe7805e75e285a160a7950348304791208d4d82c5410ea019c39076ec36e8ed9a4d3eb87dac7eb3067b5776535301d2c622e7fa67a13d70cc4450c3093c5a47689e90a1b4178ccde8719baed1d3a2630078740a502977474b7025abdcb7998ec442d5aea31d6a8533aacff0111f935de36dfc6e266701d7c3778e7f4ebfa6f7ff9e6b1fab8962f30e5276b2a76f20acbf7087bd2d092dbf642843fa980f8a4b80ce730902c0e637f6c480f1f441ee731c9fa4d33258d00ff47be9b413eb176ac1cbc0c06edf67a59f9a996f9175327de3b829d1d830a638bf6056a87ec4150b440440a2ef9e5bafcdcedf4753ff11b1f2b00e52070f4984af34cefd224f36e6d04358418b05e52ed089dac28aac67c0e4d0ab79e4ee82377c9c4ceda877dcdc2fad48a88ae1fe4cc2582f1e41b5d557897902435a27a9bffc63357135c7e6e60516f56dccbd412afb250f117cbfa234619d75f199e397c587c523e4942728cd7d4d59aca9b52fa9364a7b81d9fd7c23e688b04bdaa986e21d7dbfcbfa634b8fcdfa2619d9b6904e3d8e3205bbf5a3d526c4bf9017723fa8944a0b08595e5252e361c5a353ae737177f043e9c2460f48a8aadbd342d773ad6e034191763d87e8c33a3a443cba0174f0bc49385b5a6ca75bb7c000888dcef43bc22252eac9710afb4a6c7a63b363d08e083e691aa848cad7bec731067a1a90a7803328aed4c987eb586461a523ab8fbda4829511f7a427940b94351966c8cb37dc22dd34a81c0542adeb97fff1f1460e72c575c9d18c571ae7175a9ce269fc570c0945484e6e5fca628b5bf0904bad7027e691f1fc8d740ed172fe8816b06b7a672d67faffa91affad41828204d5dbc10c68edbe911131c6f8993c054a2165675794bf6dd1b617a9e5fca0a1a884b21d236163c559be4daf02d5ed54034f735fb031bc17e95066ab3ac9120fd24e238e6255f5ae72fe81c0f9fb69979c746b893421842aa7641d50ff2b2506d078b0aeee703f08223be66255e62fa568a244ef8642eda22ca33472c07e3d8398fe12dae1dcb37dab68aca08a8aa439c4f2257910a0f46af5bcbdad3f987c17ac6c52703a04705ed920c69526fc748f366974706d19143cef2c3441ffa01e06" -// }"# -// } -// Algorithm::SLH_DSA_128S => { -// r#"{ -// "algorithm": "SLH_DSA_128S", -// "bytes": "f47e7324fb639d867a35eea3558a54224e7ca5e357c588c136d2d514facd5fc0d93a31a624a7c3d9ba02f8a73bd2e9dad0261c237a3fa1df610b30f2a06bc750" -// }"# -// } -// _ => panic!("Fixture missing for algorithm {algorithm:?}"), -// }; - -// println!("Algorithm: {algorithm:?}, Generated SecretKey JSON:\n{sk_json}"); -// assert_eq!( -// sk_json, -// serde_json::to_string_pretty( -// &serde_json::from_str::(expected_sk_json).unwrap() -// ) -// .unwrap(), -// "SecretKey JSON does not match fixture for {algorithm:?}" -// ); - -// // Roundtrip check -// let reconstructed_sk: SecretKey = -// serde_json::from_str(&sk_json).expect("Failed to deserialize SecretKey"); -// assert_eq!( -// keypair.secret_key, reconstructed_sk, -// "SecretKey roundtrip failed for {algorithm:?}" -// ); - -// // --- Signature Test --- -// let sig_json = -// serde_json::to_string_pretty(&signature).expect("Failed to serialize Signature"); - -// // Only check fixture for deterministic algorithms -// if *algorithm != Algorithm::SLH_DSA_128S { -// // Define the expected fixture (UPDATE THIS STRING) -// let expected_sig_json = match *algorithm { -// Algorithm::ML_DSA_44 => { -// r#"{ -// "algorithm": "ML_DSA_44", -// "bytes": "d44770409f4dacafbc779f68ef129f8f15138a5befa38a9ced36031ebae7bdcbb09e900350de29cf4b9c2ce04e41bfb40739dd9bd985ed1bbed4c9c7bc96cca6f4d0c921b43b8e4067789b6e7744e7a055a5edc5b4bf0d8fc5ec404c980b5b298e5d930df3375b7ab686177c99ec4be848ce7cc162adb578896d11d4fcc5f0cf1af5f9ad070ea6f3460c06627f937782aaa185304c068748ee86c91fec03853a7ce81a304fcc2afcbb66c2e308af5269cd1c9b45a2ab73d04474d96b1c5890947485dd6c3d6e7bdc7b8e445fb27fb525677b2a3b95954dfd3bb163985d4640a4c1c1102452341e4ad5cbf5b8eb4d30c3323a6572502670e748cddca9d18f12d3a3fffcfec7099f16f6542eb39d3032094023649de67af9ee8e06c9a53cc926388345d6a9412d2de82a4e59c6c11b6f3b259243e45ee57ccd2e4f3a68a8e53b808911b4afe9d72891ca40739e1ab7142ca935e161a19dedf234ed27a7c18ba722780dd53aefc40e921ff0de9ca3ed37ebbe02237f802ea073f11c1b2ef2b703d65739b1d8c060d62a834138d7a2e663854ac794999c95360d849f57b00c37f1cf90a13e0b831df1ada26742097b6465bd2755794e20271077b80ac4d2aa6b5c8e3c77c34ee574dace472eee5eb88b0c59209bb6081a63e3cd9280b4d766e00da79af6d496c90b3ae5800397ecabcaa94d80e765b016a250dddc227d2fd1f6342290cc4ed53d1416fca988cb3d4577e27d76bbd1adcc6b22e80bf9d5901ab5797081012e4fddd320238f5ebf4c4dc5cb17ca57cc76089c8fe54ac7b3bd909ffd37ab4440c4716bb1ea42582c12b195ec38f5654146476bb72bead204fc250671567098ef2fc7c63c111a8cd3abdc5ab6aa4ff47ba5e2998e2aa4950f0725c4c770f974e7e16975068ece9b81e76fe65c84134f31855d910bb2f8ce6de08b59c6020b9292913a6322757176bdb70d2a01428161cc4f858b777d0af656366aaab65bd54cf2ed7820c26f93152cc7e827e403b71a10863409e75dbfb450618c718c3d0ac6b6686f3efc41c07a226547fa21721aeacf09b9707cedca25624f17b52a9fbb80045b62099d31f71dffa551af1d7a7276aed9036939f6c04884d13db33783adfbdd9de05824f6fe2cfbadeecf0e318f1e34bfc03d5a70c4dc8c9cebe1c1b9b605d421144a3d66b7d86710a2b87171680569222480db421b1bd678999d22aa561c55942fd7c2a7900759ee095ed2213d6ed0b5354846a010328f81600b42949be02f48fce7caf64a03dcc97edadc42ef4971f5371ff3e520d2c1de923c0dac6439c3a7e9dd4e55090584f9e2eeea96f29b69417673a8e150efe779166ba498f4ec58b9ecd00aac8b01dff155f29750852fe2e30cb0d6378b1a17ce9d90b93a5c838bbea80cedeb609c600f3bb44314a8c36713c849ec47a3794f3b828b7a8f169f33f3a1eb6867ba5d1fb71e658e1709dd08ac7e874ef3b2077edf570eb3d3989874d729aea331e03caa07ba672bc6b512a7902557bea55ee5466205064193de95ff92d2f5fac41d914e6c7e6fc62cbfe5b9ada3383a502c391782374a1b1241c7368598492f48085aea05f065213f13d9463c4b144e80a426fa5c415e593bef0b541068a8ffa1464e9b8f4ded4da5caad827142778a17d119c3e7121020ff452aefaf816c7ebf190b684d43e2c5547cece9eb7fa4f5312b19fae7f2645ff38c6c9a2514fdfdb74d3ec40e93402027f5af826aaa6c076dc1815b0b7425d5c9f7880f0e82258ff88cc3090e561524bab84bd167840463802df66a18340d7d0ef438a5c99c788ab7f07aaa2ee6e37ae0488967600421e6ddcde2a44dd3ceec3e8914f7fb5a1a42c38e20c1666ccfad1a1ae0364cc85a5612f35e087c77c0c212099c4a60138cb9486a571a59a9993ee00abd77902b684163b50fb02373baa75834ac3638a6c8e6a6038ce2a907c6ba2647cbd3437fb4920b1a5d46fb04b2c36a8aee0f3fcae7709e4508d2c7cfdfb724483dc71881a385eecd8b4dc32f793037be625a8427690ddbd6e0e8d80a15516cbadba4034d6700cb6ec807815f6dd5e8619a336bab503cfe6473cc913a80f9e5897ea68f2866ef145a3f1ef371ebe1151a4a93eceb3059a27fa93a309363b8b23cbf401dff0134a6080805837ae9fcff26a58e86ce37ded0d08f7022a979f0f788e99e7cdf32f16e09282b61d4528c5b79a38feeedf210722a20a428ae5b404c7923d1fa10e790b166b98ab1e44ae6fa3612a723045d7c4b77570345f7e7204227433611644a2c75715184da36f0688fd406c878773c58646bb130146f7ec75f8b03c97eb4329c942d9d6006bd1fcbb4e9f56031191d00334ca77cf71bb895521ea7ba6f9c4d9b67f7c4fd38f4e914cbb9717dac45c802234505de0951f8d897365002feac6dcc8616bab1ec0583de1c3cbbbaab3cbd5db94ff2721c9a22541e6796fca0a217f4eee5e1441398a1286b4638533d4a455f3c83c85d886911072eb45c808306514ef4ad1c31e3e5f7151dab4d2d18ec8ac812e0c03c86d879865281cfa517b955c1842c7e093e35b107eda832356e2992adaa697565e2c4a8e9994767a9a61d717dd2a860695c83ea2c5b5f692493e79f2c184df7db7973dfd79abf00f042ba10ad9ade75ea1b01b62efcebc6a2c7b59a2af01b8691855919b1826799f0bba13509f5db2cb55e3f7c7f72eec95df0da8021ebbbb60d2f063c4129fcd9ed825d8671bb913b4b9cf91e148d941590536a44511b62296be5222a253a19c9293126b5e8b1aebb7a58c4353fced6f23c35f7414730e78024b7ba2f8bfead124bed379d4098a3be2abd3cc10a47fd0fdb40b35ec517fbc66bf2c06e1f6960f8595452705339cdda9a9b5102b8a1a5c1f1f872d0fc564555cc431f95b7ac24fb679188f4d49a94a20f6734c20acc0c7a2463e4eb23350d386198c086818f6ddf32d5842f41d7ef3f1644f76dc401f41e87027aa77671132e3d6faa099f1e28b10d4642fe3364cd82b4950211d741392454d5b395dbf89745cdcf43910add671639829495ceca0b0d6fb2c85a9a3369cc6228ab65d88198167de7519a4857d9f2a5b37b88f4258f9d01780f23174eb9c0b3cbc888e59144c3ccfcef165f6ebe1be85a73976bcb54ba95966299e6eeeeb8fbfc51ce86075a672107e84a56c61a00ebb08e579407da3651fcec5c515ca4a5e49a51fbb07915356b0fc1654a86be032fe6ca14a0ae2526b5c78c04c842ce586a85aa1dd7a80cf355af293be254236c9952f8b1a2f2663613154a74754d0913181d2324272f3d4b577285868999abb5b9bcc5d3dde9f5fbfc050e51595eadf0f1f3273d415e6069799da1b7babfc8c9cdd1d6e7f90a16313345465d7677aeafb5c8ced4ecfb00000000000000001b243748" -// }"# -// } -// // Add cases for other deterministic algorithms like SECP256K1_SCHNORR if needed -// _ => panic!("Fixture check not applicable for algorithm {algorithm:?}"), -// }; - -// println!("Algorithm: {algorithm:?}, Generated Signature JSON:\n{sig_json}"); -// // Compare generated JSON with the pretty-printed version of the parsed fixture -// assert_eq!( -// sig_json, -// serde_json::to_string_pretty( -// &serde_json::from_str::(expected_sig_json).unwrap() -// ) -// .unwrap(), -// "Signature JSON does not match fixture for {algorithm:?}" -// ); -// } else { -// println!("Skipping fixture check for non-deterministic SLH_DSA_128S signature."); -// } - -// // Roundtrip check (always perform this) -// let reconstructed_sig: Signature = -// serde_json::from_str(&sig_json).expect("Failed to deserialize Signature"); -// assert_eq!( -// signature, reconstructed_sig, -// "Signature roundtrip failed for {algorithm:?}" -// ); - -// // --- Verification Tests --- -// // Verify reconstructed signature with reconstructed public key -// let result1 = verify(&reconstructed_pk, message, &reconstructed_sig); -// assert!( -// result1.is_ok(), -// "Verification failed: reconstructed_pk with reconstructed_sig for {algorithm:?}" -// ); - -// // Verify original signature with reconstructed public key -// let result2 = verify(&reconstructed_pk, message, &signature); -// assert!( -// result2.is_ok(), -// "Verification failed: reconstructed_pk with original signature for {algorithm:?}" -// ); - -// // Verify reconstructed signature with original public key -// let result3 = verify(&keypair.public_key, message, &reconstructed_sig); -// assert!( -// result3.is_ok(), -// "Verification failed: original public_key with reconstructed_sig for {algorithm:?}" -// ); - -// println!("Serde roundtrip test passed for {algorithm:?}"); -// } -// } From af3fb1fe4451802bb902e88872414e5f9a822347 Mon Sep 17 00:00:00 2001 From: jbride Date: Wed, 11 Feb 2026 07:29:27 -0700 Subject: [PATCH 3/4] bip360: p2tsh -> p2mr --- src/addresstype.cpp | 16 ++--- src/addresstype.h | 12 ++-- src/key_io.cpp | 14 ++--- src/policy/policy.cpp | 16 ++--- src/policy/policy.h | 8 +-- src/rpc/rawtransaction.cpp | 4 +- src/rpc/util.cpp | 2 +- src/script/descriptor.cpp | 60 +++++++++---------- src/script/interpreter.cpp | 44 +++++++------- src/script/interpreter.h | 12 ++-- src/script/miniscript.h | 4 +- src/script/script_error.cpp | 8 +-- src/script/script_error.h | 6 +- src/script/sign.cpp | 2 +- src/script/solver.cpp | 8 +-- src/script/solver.h | 2 +- src/test/data/script_tests.json | 26 ++++---- src/test/descriptor_tests.cpp | 4 +- src/test/fuzz/script.cpp | 6 +- .../fuzz/script_assets_test_minimizer.cpp | 8 +-- src/test/fuzz/util.cpp | 2 +- src/test/key_io_tests.cpp | 14 ++--- src/test/script_assets_tests.cpp | 22 +++---- src/test/script_standard_tests.cpp | 8 +-- src/test/script_tests.cpp | 4 +- src/test/transaction_tests.cpp | 2 +- src/wallet/rpc/addresses.cpp | 2 +- src/wallet/scriptpubkeyman.cpp | 2 +- 28 files changed, 159 insertions(+), 159 deletions(-) diff --git a/src/addresstype.cpp b/src/addresstype.cpp index e9c0cc83b98c..b8e4a54ae2cd 100644 --- a/src/addresstype.cpp +++ b/src/addresstype.cpp @@ -46,7 +46,7 @@ WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in) CSHA256().Write(in.data(), in.size()).Finalize(begin()); } -WitnessV2P2TSH::WitnessV2P2TSH(const CScript& in) +WitnessV2P2MR::WitnessV2P2MR(const CScript& in) { CSHA256().Write(in.data(), in.size()).Finalize(begin()); } @@ -92,10 +92,10 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet) addressRet = tap; return true; } - case TxoutType::WITNESS_V2_P2TSH: { - WitnessV2P2TSH p2tsh; - std::copy(vSolutions[0].begin(), vSolutions[0].end(), p2tsh.begin()); - addressRet = p2tsh; + case TxoutType::WITNESS_V2_P2MR: { + WitnessV2P2MR p2mr; + std::copy(vSolutions[0].begin(), vSolutions[0].end(), p2mr.begin()); + addressRet = p2mr; return true; } case TxoutType::ANCHOR: { @@ -159,9 +159,9 @@ class CScriptVisitor return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram(); } - CScript operator()(const WitnessV2P2TSH& id) const + CScript operator()(const WitnessV2P2MR& id) const { - // P2TSH is version 2 + // P2MR is version 2 return CScript() << CScript::EncodeOP_N(2) << ToByteVector(id); } }; @@ -177,7 +177,7 @@ class ValidDestinationVisitor bool operator()(const WitnessV0ScriptHash& dest) const { return true; } bool operator()(const WitnessV1Taproot& dest) const { return true; } bool operator()(const WitnessUnknown& dest) const { return true; } - bool operator()(const WitnessV2P2TSH& dest) const { return true; } + bool operator()(const WitnessV2P2MR& dest) const { return true; } }; } // namespace diff --git a/src/addresstype.h b/src/addresstype.h index d6278bf76bfe..95e20efdfbf5 100644 --- a/src/addresstype.h +++ b/src/addresstype.h @@ -91,11 +91,11 @@ struct WitnessV1Taproot : public XOnlyPubKey explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {} }; -struct WitnessV2P2TSH : public BaseHash +struct WitnessV2P2MR : public BaseHash { - WitnessV2P2TSH() : BaseHash() {} - explicit WitnessV2P2TSH(const uint256& hash) : BaseHash(hash) {} - explicit WitnessV2P2TSH(const CScript& script); + WitnessV2P2MR() : BaseHash() {} + explicit WitnessV2P2MR(const uint256& hash) : BaseHash(hash) {} + explicit WitnessV2P2MR(const CScript& script); }; //! CTxDestination subtype to encode any future Witness version @@ -145,10 +145,10 @@ struct PayToAnchor : public WitnessUnknown * * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR address) * * PayToAnchor: TxoutType::ANCHOR destination (P2A address) * * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W??? address) - * * WitnessV2P2TSH: TxoutType::WITNESS_V2_P2TSH destination (P2TSH address) + * * WitnessV2P2MR: TxoutType::WITNESS_V2_P2MR destination (P2MR address) * A CTxDestination is the internal data type encoded in a bitcoin address */ -using CTxDestination = std::variant; +using CTxDestination = std::variant; /** Check whether a CTxDestination corresponds to one with an address. */ bool IsValidDestination(const CTxDestination& dest); diff --git a/src/key_io.cpp b/src/key_io.cpp index 589d267dac40..6989c179a08e 100644 --- a/src/key_io.cpp +++ b/src/key_io.cpp @@ -77,7 +77,7 @@ class DestinationEncoder return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data); } - std::string operator()(const WitnessV2P2TSH& id) const + std::string operator()(const WitnessV2P2MR& id) const { std::vector data = {2}; // Version 2 data.reserve(53); // Reserve space for the hash @@ -189,13 +189,13 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par return tap; } - if (version == 2 && data.size() == WITNESS_V2_P2TSH_SIZE) { - WitnessV2P2TSH tsh; - if (data.size() == tsh.size()) { - std::copy(data.begin(), data.end(), tsh.begin()); - return tsh; + if (version == 2 && data.size() == WITNESS_V2_P2MR_SIZE) { + WitnessV2P2MR tmr; + if (data.size() == tmr.size()) { + std::copy(data.begin(), data.end(), tmr.begin()); + return tmr; } - error_str = strprintf("Invalid P2TSH address program size (%d %s)", data.size(), byte_str); + error_str = strprintf("Invalid P2MR address program size (%d %s)", data.size(), byte_str); return CNoDestination(); } diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index 5247d01e270c..7e9ae8e99a8b 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -91,7 +91,7 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType) return false; if (m < 1 || m > n) return false; - } else if (whichType == TxoutType::WITNESS_V2_P2TSH) { + } else if (whichType == TxoutType::WITNESS_V2_P2MR) { // Accept as standard return true; } @@ -245,7 +245,7 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { return false; } - } else if (whichType == TxoutType::WITNESS_V2_P2TSH) { + } else if (whichType == TxoutType::WITNESS_V2_P2MR) { // Accept as standard continue; } @@ -340,12 +340,12 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) } } - // Check policy limits for P2TSH spends: - // - MAX_STANDARD_P2TSH_STACK_ITEM_SIZE limit for stack item size + // Check policy limits for P2MR spends: + // - MAX_STANDARD_P2MR_STACK_ITEM_SIZE limit for stack item size // - Script path only (no key path spending) // - No annexes - if (witnessversion == 2 && witnessprogram.size() == WITNESS_V2_P2TSH_SIZE) { - // P2TSH spend (non-P2SH-wrapped, version 3, witness program size 32) + if (witnessversion == 2 && witnessprogram.size() == WITNESS_V2_P2MR_SIZE) { + // P2MR spend (non-P2SH-wrapped, version 3, witness program size 32) std::span stack{tx.vin[i].scriptWitness.stack}; if (stack.size() >= 2 && !stack.back().empty() && stack.back()[0] == ANNEX_TAG) { // Annexes are nonstandard as long as no semantics are defined for them. @@ -360,7 +360,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) // Leaf version 0xc0 (aka Tapscript, see BIP 342) for (const auto& item : stack) { // Allow larger items for SLH-DSA signatures (OP_SUCCESS127) - if (item.size() > MAX_STANDARD_P2TSH_STACK_ITEM_SIZE) { + if (item.size() > MAX_STANDARD_P2MR_STACK_ITEM_SIZE) { // Check if this is an SLH-DSA signature by looking at the script // You'd need to parse the script to see if it contains OP_SUCCESS127 // For now, we could allow larger items when OP_SUCCESS127 is present @@ -369,7 +369,7 @@ bool IsWitnessStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) } } } else { - // P2TSH only supports script path spending, no key path spending allowed + // P2MR only supports script path spending, no key path spending allowed return false; } } diff --git a/src/policy/policy.h b/src/policy/policy.h index a8b3022172a0..78a21ef81e7c 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -52,8 +52,8 @@ static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEMS{100}; static constexpr unsigned int MAX_STANDARD_P2WSH_STACK_ITEM_SIZE{80}; /** The maximum size in bytes of each witness stack item in a standard BIP 342 script (Taproot, leaf version 0xc0) */ static constexpr unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE{80}; -/** The maximum size in bytes of each witness stack item in a standard P2TSH script */ -static constexpr unsigned int MAX_STANDARD_P2TSH_STACK_ITEM_SIZE{8000}; +/** The maximum size in bytes of each witness stack item in a standard P2MR script */ +static constexpr unsigned int MAX_STANDARD_P2MR_STACK_ITEM_SIZE{8000}; /** The maximum size in bytes of a standard witnessScript */ static constexpr unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE{3600}; /** The maximum size of a standard ScriptSig */ @@ -107,7 +107,7 @@ static constexpr unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS{SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_TAPROOT | - SCRIPT_VERIFY_P2TSH}; + SCRIPT_VERIFY_P2MR}; /** * Standard script verification flags that standard transactions will comply @@ -129,7 +129,7 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS{MANDATORY_SCRIPT_VERI SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION | SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE | - SCRIPT_VERIFY_P2TSH}; + SCRIPT_VERIFY_P2MR}; /** For convenience, standard but not mandatory verify flags. */ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS{STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS}; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 821ab71dc2b0..9ea965bdcf43 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -547,7 +547,7 @@ static RPCHelpMan decodescript() case TxoutType::SCRIPTHASH: case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: - case TxoutType::WITNESS_V2_P2TSH: + case TxoutType::WITNESS_V2_P2MR: case TxoutType::ANCHOR: // Should not be wrapped return false; @@ -591,7 +591,7 @@ static RPCHelpMan decodescript() case TxoutType::WITNESS_V0_KEYHASH: case TxoutType::WITNESS_V0_SCRIPTHASH: case TxoutType::WITNESS_V1_TAPROOT: - case TxoutType::WITNESS_V2_P2TSH: + case TxoutType::WITNESS_V2_P2MR: case TxoutType::ANCHOR: // Should not be wrapped return false; diff --git a/src/rpc/util.cpp b/src/rpc/util.cpp index 2e52690382d2..f9bca4e58acc 100644 --- a/src/rpc/util.cpp +++ b/src/rpc/util.cpp @@ -346,7 +346,7 @@ class DescribeAddressVisitor return obj; } - UniValue operator()(const WitnessV2P2TSH& id) const + UniValue operator()(const WitnessV2P2MR& id) const { UniValue obj(UniValue::VOBJ); obj.pushKV("isscript", true); diff --git a/src/script/descriptor.cpp b/src/script/descriptor.cpp index cb694f51105a..7e6588b216d0 100644 --- a/src/script/descriptor.cpp +++ b/src/script/descriptor.cpp @@ -1602,7 +1602,7 @@ class RawTRDescriptor final : public DescriptorImpl } }; -class TSHDescriptor final : public DescriptorImpl +class P2MRDescriptor final : public DescriptorImpl { std::vector m_depths; protected: @@ -1622,8 +1622,8 @@ class TSHDescriptor final : public DescriptorImpl if (!builder.IsComplete()) return {}; // Because we are leveraging P2TR TaprootBuilder, create a dummy internal key for finalization - // P2TSH only uses the merkle root - // Subsequently, use NUMS_H as placeholder since P2TSH doesn't use keypath + // P2MR only uses the merkle root + // Subsequently, use NUMS_H as placeholder since P2MR doesn't use keypath XOnlyPubKey dummy_key = XOnlyPubKey::NUMS_H; builder.Finalize(dummy_key); @@ -1658,8 +1658,8 @@ class TSHDescriptor final : public DescriptorImpl return true; } public: - TSHDescriptor(std::vector> descs, std::vector depths) : - DescriptorImpl({}, std::move(descs), "tsh"), m_depths(std::move(depths)) + P2MRDescriptor(std::vector> descs, std::vector depths) : + DescriptorImpl({}, std::move(descs), "tmr"), m_depths(std::move(depths)) { assert(m_subdescriptor_args.size() == m_depths.size()); } @@ -1670,7 +1670,7 @@ class TSHDescriptor final : public DescriptorImpl std::optional ScriptSize() const override { return 1 + 1 + 32; } std::optional MaxSatisfactionWeight(bool) const override { - // P2TSH only supports script path, no keypath + // P2MR only supports script path, no keypath return 1 + 65; // Script path satisfaction } @@ -1684,7 +1684,7 @@ class TSHDescriptor final : public DescriptorImpl std::vector> subdescs; subdescs.reserve(m_subdescriptor_args.size()); std::transform(m_subdescriptor_args.begin(), m_subdescriptor_args.end(), subdescs.begin(), [](const std::unique_ptr& d) { return d->Clone(); }); - return std::make_unique(std::move(subdescs), m_depths); + return std::make_unique(std::move(subdescs), m_depths); } }; @@ -1699,7 +1699,7 @@ enum class ParseScriptContext { P2WSH, //!< Inside wsh() (script becomes v0 witness script) P2TR, //!< Inside tr() (either internal key, or BIP342 script leaf) MUSIG, //!< Inside musig() (implies P2TR, cannot have nested musig()) - P2TSH, //!< Inside tsh() (Bip360 script leaf only) + P2MR, //!< Inside tmr() (Bip360 script leaf only) }; std::optional ParseKeyPathNum(std::span elem, bool& apostrophe, std::string& error, bool& has_hardened) @@ -1853,7 +1853,7 @@ std::vector> ParsePubkeyInner(uint32_t key_exp_i error = "Uncompressed keys are not allowed"; return {}; } - } else if (data.size() == 32 && (ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2TSH)) { + } else if (data.size() == 32 && (ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2MR)) { unsigned char fullkey[33] = {0x02}; std::copy(data.begin(), data.end(), fullkey + 1); pubkey.Set(std::begin(fullkey), std::end(fullkey)); @@ -1870,7 +1870,7 @@ std::vector> ParsePubkeyInner(uint32_t key_exp_i if (permit_uncompressed || key.IsCompressed()) { CPubKey pubkey = key.GetPubKey(); out.keys.emplace(pubkey.GetID(), key); - ret.emplace_back(std::make_unique(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2TSH)); + ret.emplace_back(std::make_unique(key_exp_index, pubkey, ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2MR)); return ret; } else { error = "Uncompressed keys are not allowed"; @@ -2148,7 +2148,7 @@ struct KeyParser { switch (m_script_ctx) { case miniscript::MiniscriptContext::P2WSH: return ParseScriptContext::P2WSH; case miniscript::MiniscriptContext::TAPSCRIPT: return ParseScriptContext::P2TR; - case miniscript::MiniscriptContext::P2TSH: return ParseScriptContext::P2TSH; + case miniscript::MiniscriptContext::P2MR: return ParseScriptContext::P2MR; } assert(false); } @@ -2221,7 +2221,7 @@ struct KeyParser { std::vector> ParseScript(uint32_t& key_exp_index, std::span& sp, ParseScriptContext ctx, FlatSigningProvider& out, std::string& error) { using namespace script; - Assume(ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH || ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2TSH); + Assume(ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH || ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2MR); std::vector> ret; auto expr = Expr(sp); if (Func("pk", expr)) { @@ -2268,7 +2268,7 @@ std::vector> ParseScript(uint32_t& key_exp_index const bool multi_a = !(multi || sortedmulti) && Func("multi_a", expr); const bool sortedmulti_a = !(multi || sortedmulti || multi_a) && Func("sortedmulti_a", expr); if (((ctx == ParseScriptContext::TOP || ctx == ParseScriptContext::P2SH || ctx == ParseScriptContext::P2WSH) && (multi || sortedmulti)) || - ((ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2TSH) && (multi_a || sortedmulti_a))) { + ((ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2MR) && (multi_a || sortedmulti_a))) { auto threshold = Expr(expr); uint32_t thres; std::vector>> providers; // List of multipath expanded pubkeys @@ -2510,8 +2510,8 @@ std::vector> ParseScript(uint32_t& key_exp_index error = "Can only have tr at top level"; return {}; } - if (ctx == ParseScriptContext::TOP && Func("tsh", expr)) { - // P2TSH only supports script path, no internal key + if (ctx == ParseScriptContext::TOP && Func("tmr", expr)) { + // P2MR only supports script path, no internal key std::vector>> subscripts; std::vector depths; @@ -2526,19 +2526,19 @@ std::vector> ParseScript(uint32_t& key_exp_index while (Const("{", expr)) { branches.push_back(false); // new left branch if (branches.size() > TAPROOT_CONTROL_MAX_NODE_COUNT) { - error = strprintf("tsh() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT); + error = strprintf("tmr() supports at most %i nesting levels", TAPROOT_CONTROL_MAX_NODE_COUNT); return {}; } } // Process the actual script expression. auto sarg = Expr(expr); - subscripts.emplace_back(ParseScript(key_exp_index, sarg, ParseScriptContext::P2TSH, out, error)); + subscripts.emplace_back(ParseScript(key_exp_index, sarg, ParseScriptContext::P2MR, out, error)); if (subscripts.back().empty()) return {}; depths.push_back(branches.size()); // Process closing braces; one is expected for every right branch we were in. while (branches.size() && branches.back()) { if (!Const("}", expr)) { - error = strprintf("tsh(): expected '}' after script expression"); + error = strprintf("tmr(): expected '}' after script expression"); return {}; } branches.pop_back(); @@ -2546,7 +2546,7 @@ std::vector> ParseScript(uint32_t& key_exp_index // If after that, we're at the end of a left branch, expect a comma. if (branches.size() && !branches.back()) { if (!Const(",", expr)) { - error = strprintf("tsh(): expected ',' after script expression"); + error = strprintf("tmr(): expected ',' after script expression"); return {}; } branches.back() = true; @@ -2554,7 +2554,7 @@ std::vector> ParseScript(uint32_t& key_exp_index } while (branches.size()); // After we've explored a whole tree, we must be at the end of the expression. if (expr.size()) { - error = strprintf("tsh(): expected ')' after script expression"); + error = strprintf("tmr(): expected ')' after script expression"); return {}; } } @@ -2562,17 +2562,17 @@ std::vector> ParseScript(uint32_t& key_exp_index assert(TaprootBuilder::ValidDepths(depths)); // Build the final descriptors vector - // For tsh(), we create a single descriptor with all subdescriptors + // For tmr(), we create a single descriptor with all subdescriptors std::vector> all_descs; for (auto& subscripts_vec : subscripts) { for (auto& desc : subscripts_vec) { all_descs.push_back(std::move(desc)); } } - ret.emplace_back(std::make_unique(std::move(all_descs), depths)); + ret.emplace_back(std::make_unique(std::move(all_descs), depths)); return ret; - } else if (Func("tsh", expr)) { - error = "Can only have tsh at top level"; + } else if (Func("tmr", expr)) { + error = "Can only have tmr at top level"; return {}; } if (ctx == ParseScriptContext::TOP && Func("rawtr", expr)) { @@ -2611,7 +2611,7 @@ std::vector> ParseScript(uint32_t& key_exp_index // Process miniscript expressions. { const auto script_ctx{ctx == ParseScriptContext::P2WSH ? miniscript::MiniscriptContext::P2WSH : - ctx == ParseScriptContext::P2TSH ? miniscript::MiniscriptContext::P2TSH : + ctx == ParseScriptContext::P2MR ? miniscript::MiniscriptContext::P2MR : miniscript::MiniscriptContext::TAPSCRIPT}; KeyParser parser(/*out = */&out, /* in = */nullptr, /* ctx = */script_ctx, key_exp_index); auto node = miniscript::FromString(std::string(expr.begin(), expr.end()), parser); @@ -2620,8 +2620,8 @@ std::vector> ParseScript(uint32_t& key_exp_index return {}; } if (node) { - if (ctx != ParseScriptContext::P2WSH && ctx != ParseScriptContext::P2TR && ctx != ParseScriptContext::P2TSH) { - error = "Miniscript expressions can only be used in wsh, tr, or tsh."; + if (ctx != ParseScriptContext::P2WSH && ctx != ParseScriptContext::P2TR && ctx != ParseScriptContext::P2MR) { + error = "Miniscript expressions can only be used in wsh, tr, or tmr."; return {}; } if (!node->IsSane() || node->IsNotSatisfiable()) { @@ -2718,7 +2718,7 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo return std::make_unique(InferXOnlyPubkey(key, ctx, provider), true); } - if (ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2TSH) { + if (ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2MR) { auto ret = InferMultiA(script, ctx, provider); if (ret) return ret; } @@ -2825,9 +2825,9 @@ std::unique_ptr InferScript(const CScript& script, ParseScriptCo } } - if (ctx == ParseScriptContext::P2WSH || ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2TSH) { + if (ctx == ParseScriptContext::P2WSH || ctx == ParseScriptContext::P2TR || ctx == ParseScriptContext::P2MR) { const auto script_ctx{ctx == ParseScriptContext::P2WSH ? miniscript::MiniscriptContext::P2WSH : - ctx == ParseScriptContext::P2TSH ? miniscript::MiniscriptContext::P2TSH : + ctx == ParseScriptContext::P2MR ? miniscript::MiniscriptContext::P2MR : miniscript::MiniscriptContext::TAPSCRIPT}; KeyParser parser(/* out = */nullptr, /* in = */&provider, /* ctx = */script_ctx); auto node = miniscript::FromScript(script, parser); diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index 1ec05212cfee..9b88d4a8ab18 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1421,7 +1421,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector&& spent for (size_t inpos = 0; inpos < txTo.vin.size() && !(uses_bip143_segwit && uses_bip341_taproot); ++inpos) { if (!txTo.vin[inpos].scriptWitness.IsNull()) { - // Allow for P2TR and P2TSH + // Allow for P2TR and P2MR if (m_spent_outputs_ready && m_spent_outputs[inpos].scriptPubKey.size() == 2 + WITNESS_V1_TAPROOT_SIZE && ( m_spent_outputs[inpos].scriptPubKey[0] == OP_1 || m_spent_outputs[inpos].scriptPubKey[0] == OP_2)) { // Treat every witness-bearing spend with 34-byte scriptPubKey that starts with OP_1 as a Taproot @@ -1944,10 +1944,10 @@ static bool HandleSLHDSASignature(std::vector& stack, const CScript& ex sig_size = 7856; // Strip the hash type byte LogPrintf("SLH-DSA DEBUG: Stripping hash type byte from signature (7857 -> 7856 bytes)\n"); } else if (exec_script.size() == 70) { - // For P2TSH combined Schnorr+SLH-DSA scripts (70 bytes), use SIGHASH_ALL + // For P2MR combined Schnorr+SLH-DSA scripts (70 bytes), use SIGHASH_ALL // This matches the behavior of the Rust implementation hashtype = SIGHASH_ALL; - LogPrintf("SLH-DSA DEBUG: P2TSH combined script detected, using SIGHASH_ALL (0x%02x)\n", hashtype); + LogPrintf("SLH-DSA DEBUG: P2MR combined script detected, using SIGHASH_ALL (0x%02x)\n", hashtype); } // Create message hash for SLH-DSA verification using the extracted hash type @@ -2240,14 +2240,14 @@ uint256 ComputeTaprootMerkleRoot(std::span control, const u uint256 ComputeTshMerkleRoot(std::span control, const uint256& tapleaf_hash) { - assert(control.size() >= P2TSH_CONTROL_BASE_SIZE); - assert(control.size() <= P2TSH_CONTROL_MAX_SIZE); - assert((control.size() - P2TSH_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE == 0); + assert(control.size() >= P2MR_CONTROL_BASE_SIZE); + assert(control.size() <= P2MR_CONTROL_MAX_SIZE); + assert((control.size() - P2MR_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE == 0); - const int path_len = (control.size() - P2TSH_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE; + const int path_len = (control.size() - P2MR_CONTROL_BASE_SIZE) / TAPROOT_CONTROL_NODE_SIZE; uint256 k = tapleaf_hash; for (int i = 0; i < path_len; ++i) { - std::span node{std::span{control}.subspan(P2TSH_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)}; + std::span node{std::span{control}.subspan(P2MR_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * i, TAPROOT_CONTROL_NODE_SIZE)}; k = ComputeTapbranchHash(k, node); } return k; @@ -2271,7 +2271,7 @@ static bool VerifyScriptInTshMerkleRootPath( const std::vector& control, const std::vector& merkle_root, const CScript& script) { - assert(control.size() >= P2TSH_CONTROL_BASE_SIZE); + assert(control.size() >= P2MR_CONTROL_BASE_SIZE); assert(merkle_root.size() >= uint256::size()); // Compute the tapleaf hash from the script @@ -2358,9 +2358,9 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, } return set_success(serror); } - } else if (witversion == 2 && program.size() == WITNESS_V2_P2TSH_SIZE ) { - // P2TSH: 32-byte witness v2 program (script path only) - // Only apply P2TSH validation for native witness outputs, not P2SH-wrapped ones + } else if (witversion == 2 && program.size() == WITNESS_V2_P2MR_SIZE ) { + // P2MR: 32-byte witness v2 program (script path only) + // Only apply P2MR validation for native witness outputs, not P2SH-wrapped ones if (is_p2sh) { // For P2SH-wrapped witness v2, treat as WITNESS_UNKNOWN to maintain compatibility if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { @@ -2369,9 +2369,9 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, return true; } - // Only apply P2TSH validation if the flag is explicitly set - if (!(flags & SCRIPT_VERIFY_P2TSH)) { - // If P2TSH flag is not set, treat as WITNESS_UNKNOWN + // Only apply P2MR validation if the flag is explicitly set + if (!(flags & SCRIPT_VERIFY_P2MR)) { + // If P2MR flag is not set, treat as WITNESS_UNKNOWN if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) { return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); } @@ -2388,7 +2388,7 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, execdata.m_annex_present = false; } execdata.m_annex_init = true; - // P2TSH only supports script path spending, not key path spending + // P2MR only supports script path spending, not key path spending if (stack.size() == 1) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); } else { @@ -2398,20 +2398,20 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion, const valtype& script = SpanPopBack(stack); const size_t control_size = control.size(); - if (control_size < P2TSH_CONTROL_BASE_SIZE || control_size > P2TSH_CONTROL_MAX_SIZE || ((control_size - P2TSH_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) { - return set_error(serror, SCRIPT_ERR_P2TSH_WRONG_CONTROL_SIZE); + if (control_size < P2MR_CONTROL_BASE_SIZE || control_size > P2MR_CONTROL_MAX_SIZE || ((control_size - P2MR_CONTROL_BASE_SIZE) % TAPROOT_CONTROL_NODE_SIZE) != 0) { + return set_error(serror, SCRIPT_ERR_P2MR_WRONG_CONTROL_SIZE); } execdata.m_tapleaf_hash = ComputeTapleafHash(control[0] & TAPROOT_LEAF_MASK, script); if (!VerifyScriptInTshMerkleRootPath(control, program, CScript(script.begin(), script.end()))) { return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); } execdata.m_tapleaf_hash_init = true; - // Check for P2TSH-specific parity requirement (must be 0xc1 for Tapscript) + // Check for P2MR-specific parity requirement (must be 0xc1 for Tapscript) if ((control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT && - control[0] != P2TSH_LEAF_TAPSCRIPT) { - return set_error(serror, SCRIPT_ERR_P2TSH_WRONG_PARITY_BIT); + control[0] != P2MR_LEAF_TAPSCRIPT) { + return set_error(serror, SCRIPT_ERR_P2MR_WRONG_PARITY_BIT); } - if (control[0] == P2TSH_LEAF_TAPSCRIPT) { + if (control[0] == P2MR_LEAF_TAPSCRIPT) { // Tapscript (leaf version 0xc1 since parity is always 1) exec_script = CScript(script.begin(), script.end()); execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack) + VALIDATION_WEIGHT_OFFSET; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index cb17ae88bf72..6f59f5c8f755 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -133,8 +133,8 @@ enum : uint32_t { // SCRIPT_VERIFY_TAPROOT = (1U << 17), - // P2TSH validation (BIP360) - SCRIPT_VERIFY_P2TSH = (1U << 21), + // P2MR validation (BIP360) + SCRIPT_VERIFY_P2MR = (1U << 21), // Making unknown Taproot leaf versions non-standard // @@ -230,17 +230,17 @@ struct ScriptExecutionData static constexpr size_t WITNESS_V0_SCRIPTHASH_SIZE = 32; static constexpr size_t WITNESS_V0_KEYHASH_SIZE = 20; static constexpr size_t WITNESS_V1_TAPROOT_SIZE = 32; -static constexpr size_t WITNESS_V2_P2TSH_SIZE = 32; +static constexpr size_t WITNESS_V2_P2MR_SIZE = 32; static constexpr uint8_t TAPROOT_LEAF_MASK = 0xfe; static constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT = 0xc0; -static constexpr uint8_t P2TSH_LEAF_TAPSCRIPT = 0xc1; +static constexpr uint8_t P2MR_LEAF_TAPSCRIPT = 0xc1; static constexpr size_t TAPROOT_CONTROL_BASE_SIZE = 33; static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32; static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128; static constexpr size_t TAPROOT_CONTROL_MAX_SIZE = TAPROOT_CONTROL_BASE_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; -static constexpr size_t P2TSH_CONTROL_BASE_SIZE = 1; // no tweaked pubkey -static constexpr size_t P2TSH_CONTROL_MAX_SIZE = TAPROOT_CONTROL_MAX_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; +static constexpr size_t P2MR_CONTROL_BASE_SIZE = 1; // no tweaked pubkey +static constexpr size_t P2MR_CONTROL_MAX_SIZE = TAPROOT_CONTROL_MAX_SIZE + TAPROOT_CONTROL_NODE_SIZE * TAPROOT_CONTROL_MAX_NODE_COUNT; extern const HashWriter HASHER_TAPSIGHASH; //!< Hasher with tag "TapSighash" pre-fed to it. extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fed to it. diff --git a/src/script/miniscript.h b/src/script/miniscript.h index 982be83ed6e6..9c4ae043c612 100644 --- a/src/script/miniscript.h +++ b/src/script/miniscript.h @@ -239,7 +239,7 @@ enum class Availability { enum class MiniscriptContext { P2WSH, TAPSCRIPT, - P2TSH, + P2MR, }; /** Whether the context Tapscript, ensuring the only other possibility is P2WSH. */ @@ -248,7 +248,7 @@ constexpr bool IsTapscript(MiniscriptContext ms_ctx) switch (ms_ctx) { case MiniscriptContext::P2WSH: return false; case MiniscriptContext::TAPSCRIPT: return true; - case MiniscriptContext::P2TSH: return true; + case MiniscriptContext::P2MR: return true; } assert(false); } diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 16a29ffd9cf9..e722b62df9a0 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -121,10 +121,10 @@ std::string ScriptErrorString(const ScriptError serror) return "Using OP_CODESEPARATOR in non-witness script"; case SCRIPT_ERR_SIG_FINDANDDELETE: return "Signature is found in scriptCode"; - case SCRIPT_ERR_P2TSH_WRONG_CONTROL_SIZE: - return "Invalid P2TSH control block size"; - case SCRIPT_ERR_P2TSH_WRONG_PARITY_BIT: - return "P2TSH leaf must use parity bit 1 (0xc1)"; + case SCRIPT_ERR_P2MR_WRONG_CONTROL_SIZE: + return "Invalid P2MR control block size"; + case SCRIPT_ERR_P2MR_WRONG_PARITY_BIT: + return "P2MR leaf must use parity bit 1 (0xc1)"; case SCRIPT_ERR_UNKNOWN_ERROR: case SCRIPT_ERR_ERROR_COUNT: default: break; diff --git a/src/script/script_error.h b/src/script/script_error.h index 43fdbcc95f06..adb8ac6ff719 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -83,9 +83,9 @@ typedef enum ScriptError_t SCRIPT_ERR_SLHDSA_SIG, SCRIPT_ERR_SCHNORR_SIG_IN_COMBINED, - /* P2TSH */ - SCRIPT_ERR_P2TSH_WRONG_CONTROL_SIZE, - SCRIPT_ERR_P2TSH_WRONG_PARITY_BIT, + /* P2MR */ + SCRIPT_ERR_P2MR_WRONG_CONTROL_SIZE, + SCRIPT_ERR_P2MR_WRONG_PARITY_BIT, /* Constant scriptCode */ SCRIPT_ERR_OP_CODESEPARATOR, diff --git a/src/script/sign.cpp b/src/script/sign.cpp index 6880c10d503c..9765ea03052e 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -412,7 +412,7 @@ static bool SignStep(const SigningProvider& provider, const BaseSignatureCreator case TxoutType::NONSTANDARD: case TxoutType::NULL_DATA: case TxoutType::WITNESS_UNKNOWN: - case TxoutType::WITNESS_V2_P2TSH: + case TxoutType::WITNESS_V2_P2MR: return false; case TxoutType::PUBKEY: if (!CreateSig(creator, sigdata, provider, sig, CPubKey(vSolutions[0]), scriptPubKey, sigversion)) return false; diff --git a/src/script/solver.cpp b/src/script/solver.cpp index 275d83472bc2..ea417a8999e2 100644 --- a/src/script/solver.cpp +++ b/src/script/solver.cpp @@ -28,7 +28,7 @@ std::string GetTxnOutputType(TxoutType t) case TxoutType::WITNESS_V0_KEYHASH: return "witness_v0_keyhash"; case TxoutType::WITNESS_V0_SCRIPTHASH: return "witness_v0_scripthash"; case TxoutType::WITNESS_V1_TAPROOT: return "witness_v1_taproot"; - case TxoutType::WITNESS_V2_P2TSH: return "witness_v2_p2tsh"; + case TxoutType::WITNESS_V2_P2MR: return "witness_v2_p2mr"; case TxoutType::WITNESS_UNKNOWN: return "witness_unknown"; } // no default case, so the compiler can warn about missing cases assert(false); @@ -167,8 +167,8 @@ TxoutType Solver(const CScript& scriptPubKey, std::vector{(unsigned char)witnessversion}); diff --git a/src/script/solver.h b/src/script/solver.h index 40a15a6d5c5f..321e825c62da 100644 --- a/src/script/solver.h +++ b/src/script/solver.h @@ -31,7 +31,7 @@ enum class TxoutType { WITNESS_V0_SCRIPTHASH, WITNESS_V0_KEYHASH, WITNESS_V1_TAPROOT, - WITNESS_V2_P2TSH, + WITNESS_V2_P2MR, WITNESS_UNKNOWN, //!< Only for Witness versions not already defined above }; diff --git a/src/test/data/script_tests.json b/src/test/data/script_tests.json index 215c5f010215..d89ff623260a 100644 --- a/src/test/data/script_tests.json +++ b/src/test/data/script_tests.json @@ -2668,7 +2668,7 @@ "TAPSCRIPT Test that DROP operations do not execute inside of a false IF conditional" ], -["P2TSH tests"], +["P2MR tests"], [ [ "aa", @@ -2681,7 +2681,7 @@ "0x52 0x20 0x7e04991706edb31549f786fa7113bb857ceb26174f7d08e9efa91decf13324a0", "P2SH,WITNESS,TAPROOT", "OK", - "P2TSH: Simple negative OP_EQUAL test pre-activation" + "P2MR: Simple negative OP_EQUAL test pre-activation" ], [ [ @@ -2693,9 +2693,9 @@ ], "", "0x52 0x20 0x7e04991706edb31549f786fa7113bb857ceb26174f7d08e9efa91decf13324a0", - "P2SH,WITNESS,TAPROOT,P2TSH", + "P2SH,WITNESS,TAPROOT,P2MR", "EVAL_FALSE", - "P2TSH: Simple negative OP_EQUAL test post-activation" + "P2MR: Simple negative OP_EQUAL test post-activation" ], [ [ @@ -2707,9 +2707,9 @@ ], "", "0x52 0x20 0x7e04991706edb31549f786fa7113bb857ceb26174f7d08e9efa91decf13324a0", - "P2SH,WITNESS,TAPROOT,P2TSH", + "P2SH,WITNESS,TAPROOT,P2MR", "OK", - "P2TSH: Simple positive OP_EQUAL test post-activation" + "P2MR: Simple positive OP_EQUAL test post-activation" ], [ [ @@ -2718,9 +2718,9 @@ ], "", "0x52 0x20 0x7e04991706edb31549f786fa7113bb857ceb26174f7d08e9efa91decf13324a0", - "P2SH,WITNESS,TAPROOT,P2TSH", + "P2SH,WITNESS,TAPROOT,P2MR", "WITNESS_PROGRAM_MISMATCH", - "P2TSH: Key path spending not supported" + "P2MR: Key path spending not supported" ], [ [ @@ -2730,9 +2730,9 @@ ], "", "0x52 0x20 0x7e04991706edb31549f786fa7113bb857ceb26174f7d08e9efa91decf13324a0", - "P2SH,WITNESS,TAPROOT,P2TSH", + "P2SH,WITNESS,TAPROOT,P2MR", "WITNESS_PROGRAM_MISMATCH", - "P2TSH: Witness program mismatch" + "P2MR: Witness program mismatch" ], [ [ @@ -2744,9 +2744,9 @@ ], "", "0x52 0x20 0x7e04991706edb31549f786fa7113bb857ceb26174f7d08e9efa91decf13324a0", - "P2SH,WITNESS,TAPROOT,P2TSH", - "P2TSH_WRONG_PARITY_BIT", - "P2TSH: Wrong parity bit" + "P2SH,WITNESS,TAPROOT,P2MR", + "P2MR_WRONG_PARITY_BIT", + "P2MR: Wrong parity bit" ], ["NULLFAIL should cover all signatures and signatures only"], diff --git a/src/test/descriptor_tests.cpp b/src/test/descriptor_tests.cpp index 90deae5f533e..558045d74382 100644 --- a/src/test/descriptor_tests.cpp +++ b/src/test/descriptor_tests.cpp @@ -1066,9 +1066,9 @@ BOOST_AUTO_TEST_CASE(descriptor_test) // Invalid checksum CheckUnparsable("wsh(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))#abcdef12", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))#abcdef12", "Provided checksum 'abcdef12' does not match computed checksum 'tyzp6a7p'"); // Only p2wsh or tr contexts are valid - CheckUnparsable("sh(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh, tr, or tsh."); + CheckUnparsable("sh(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh, tr, or tmr."); CheckUnparsable("tr(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "tr(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "tr(): key 'and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10))' is not valid"); - CheckUnparsable("raw(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh, tr, or tsh."); + CheckUnparsable("raw(and_v(vc:andor(pk(L4gM1FBdyHNpkzsFh9ipnofLhpZRp2mwobpeULy1a6dBTvw8Ywtd),pk_k(Kx9HCDjGiwFcgVNhTrS5z5NeZdD6veeam61eDxLDCkGWujvL4Gnn),and_v(v:older(1),pk_k(L4o2kDvXXDRH2VS9uBnouScLduWt4dZnM25se7kvEjJeQ285en2A))),after(10)))", "sh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(02aa27e5eb2c185e87cd1dbc3e0efc9cb1175235e0259df1713424941c3cb40402))),after(10)))", "Miniscript expressions can only be used in wsh, tr, or tmr."); CheckUnparsable("", "tr(034D2224bbbbbbbbbbcbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb40,{{{{{{{{{{{{{{{{{{{{{{multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008')", "'multi(1,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/967808'/9,xprvA1RpRA33e1JQ7ifknakTFNpgXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc/968/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/585/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/2/0/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/5/8/5/8/24/5/58/52/5/8/5/2/8/24/5/58/588/246/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/5/4/5/58/55/58/2/5/8/55/2/5/8/58/555/58/2/5/8/4//2/5/58/5w/2/5/8/5/2/4/5/58/5558'/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/8/2/5/8/5/5/8/58/2/5/58/58/2/5/8/9/588/2/58/2/5/8/5/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8/5/2/5/58/58/2/5/5/58/588/2/58/2/5/8/5/2/82/5/8/5/5/58/52/6/8/5/2/8/{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}{{{{{{{{{DDD2/5/8/5/2/5/58/58/2/5/58/58/588/2/58/2/8/5/8/5/4/5/58/588/2/6/8/5/2/8/2/5/8588/246/8/5/2DLDDDDDDDbbD3DDDD/8/2/5/8/5/2/5/58/58/2/5/5/5/58/588/2/6/8/5/2/8/2/5/8/2/58/2/5/8/5/2/8/5/8/3/4/5/58/55/2/5/58/58/2/5/5/5/8/5/2/8/5/85/2/8/2/5/8D)/5/2/5/58/58/2/5/58/58/58/588/2/58/2/5/8/5/25/58/58/2/5/58/58/2/5/8/9/588/2/58/2/6780,xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFW/8/5/2/5/58678008'' is not a valid descriptor function"); // No uncompressed keys allowed CheckUnparsable("", "wsh(and_v(vc:andor(pk(03cdabb7f2dce7bfbd8a0b9570c6fd1e712e5d64045e9d6b517b3d5072251dc204),pk_k(032707170c71d8f75e4ca4e3fce870b9409dcaf12b051d3bcadff74747fa7619c0),and_v(v:older(1),pk_k(049228de6902abb4f541791f6d7f925b10e2078ccb1298856e5ea5cc5fd667f930eac37a00cc07f9a91ef3c2d17bf7a17db04552ff90ac312a5b8b4caca6c97aa4))),after(10)))", "Uncompressed keys are not allowed"); diff --git a/src/test/fuzz/script.cpp b/src/test/fuzz/script.cpp index d9a0272379e0..5d07c9c6043a 100644 --- a/src/test/fuzz/script.cpp +++ b/src/test/fuzz/script.cpp @@ -158,8 +158,8 @@ FUZZ_TARGET(script, .init = initialize_script) // Only try to round trip non-pubkey destinations since PubKeyDestination has no encoding Assert(dest.empty() != valid); - // TODO: Temporary workaround: Skip round-trip test for P2TSH during transition - if (!std::get_if(&tx_destination_1)) { + // TODO: Temporary workaround: Skip round-trip test for P2MR during transition + if (!std::get_if(&tx_destination_1)) { // Add debugging to see what type of destination is failing if (std::get_if(&tx_destination_1)) { // Skip WitnessUnknown as well during transition @@ -170,7 +170,7 @@ FUZZ_TARGET(script, .init = initialize_script) } // TODO: Temporary workaround: Skip validity check for problematic destination types - if (!std::get_if(&tx_destination_1) && + if (!std::get_if(&tx_destination_1) && !std::get_if(&tx_destination_1)) { Assert(valid == IsValidDestinationString(encoded_dest)); } diff --git a/src/test/fuzz/script_assets_test_minimizer.cpp b/src/test/fuzz/script_assets_test_minimizer.cpp index 519b5313c203..b96de8d1f37d 100644 --- a/src/test/fuzz/script_assets_test_minimizer.cpp +++ b/src/test/fuzz/script_assets_test_minimizer.cpp @@ -98,7 +98,7 @@ const std::map FLAG_NAMES = { {std::string("CHECKSEQUENCEVERIFY"), (unsigned int)SCRIPT_VERIFY_CHECKSEQUENCEVERIFY}, {std::string("WITNESS"), (unsigned int)SCRIPT_VERIFY_WITNESS}, {std::string("TAPROOT"), (unsigned int)SCRIPT_VERIFY_TAPROOT}, - {std::string("P2TSH"), (unsigned int)SCRIPT_VERIFY_P2TSH}, + {std::string("P2MR"), (unsigned int)SCRIPT_VERIFY_P2MR}, }; std::vector AllFlags() @@ -114,14 +114,14 @@ std::vector AllFlags() if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; if (i & 32) flag |= SCRIPT_VERIFY_WITNESS; if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT; - if (i & 128) flag |= SCRIPT_VERIFY_P2TSH; + if (i & 128) flag |= SCRIPT_VERIFY_P2MR; // SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue; // SCRIPT_VERIFY_TAPROOT requires SCRIPT_VERIFY_WITNESS if (flag & SCRIPT_VERIFY_TAPROOT && !(flag & SCRIPT_VERIFY_WITNESS)) continue; - // SCRIPT_VERIFY_P2TSH requires SCRIPT_VERIFY_WITNESS - if (flag & SCRIPT_VERIFY_P2TSH && !(flag & SCRIPT_VERIFY_WITNESS)) continue; + // SCRIPT_VERIFY_P2MR requires SCRIPT_VERIFY_WITNESS + if (flag & SCRIPT_VERIFY_P2MR && !(flag & SCRIPT_VERIFY_WITNESS)) continue; ret.push_back(flag); } diff --git a/src/test/fuzz/util.cpp b/src/test/fuzz/util.cpp index 1bddf12caa30..e66eb408d393 100644 --- a/src/test/fuzz/util.cpp +++ b/src/test/fuzz/util.cpp @@ -214,7 +214,7 @@ CTxDestination ConsumeTxDestination(FuzzedDataProvider& fuzzed_data_provider) no tx_destination = WitnessV1Taproot{XOnlyPubKey{ConsumeUInt256(fuzzed_data_provider)}}; }, [&] { - tx_destination = WitnessV2P2TSH{ConsumeUInt256(fuzzed_data_provider)}; + tx_destination = WitnessV2P2MR{ConsumeUInt256(fuzzed_data_provider)}; }, [&] { tx_destination = PayToAnchor{}; diff --git a/src/test/key_io_tests.cpp b/src/test/key_io_tests.cpp index b071bc14a7ab..dbe7a29b7930 100644 --- a/src/test/key_io_tests.cpp +++ b/src/test/key_io_tests.cpp @@ -57,14 +57,14 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) destination = DecodeDestination(exp_base58string); CScript script = GetScriptForDestination(destination); - // Check if this is a witness version 2 address (P2TSH or other v2 types) - bool is_p2tsh = false; + // Check if this is a witness version 2 address (P2MR or other v2 types) + bool is_p2mr = false; if (exp_payload.size() >= 2 && static_cast(exp_payload[0]) == 0x52) { - is_p2tsh = true; + is_p2mr = true; } - if (is_p2tsh) { - // TODO: Add P2TSH-specific validation here + if (is_p2mr) { + // TODO: Add P2MR-specific validation here } else { BOOST_CHECK_MESSAGE(IsValidDestination(destination), "!IsValid:" + strTest); BOOST_CHECK_EQUAL(HexStr(script), HexStr(exp_payload)); @@ -80,8 +80,8 @@ BOOST_AUTO_TEST_CASE(key_io_valid_parse) } destination = DecodeDestination(exp_base58string); - if (is_p2tsh) { - // TODO: Add P2TSH-specific case flip validation here + if (is_p2mr) { + // TODO: Add P2MR-specific case flip validation here } else { BOOST_CHECK_MESSAGE(IsValidDestination(destination) == try_case_flip, "!IsValid case flipped:" + strTest); if (IsValidDestination(destination)) { diff --git a/src/test/script_assets_tests.cpp b/src/test/script_assets_tests.cpp index 9c89cfac5dad..69e1e74641a6 100644 --- a/src/test/script_assets_tests.cpp +++ b/src/test/script_assets_tests.cpp @@ -84,14 +84,14 @@ static std::vector AllConsensusFlags() if (i & 16) flag |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY; if (i & 32) flag |= SCRIPT_VERIFY_WITNESS; if (i & 64) flag |= SCRIPT_VERIFY_TAPROOT; - if (i & 128) flag |= SCRIPT_VERIFY_P2TSH; + if (i & 128) flag |= SCRIPT_VERIFY_P2MR; // SCRIPT_VERIFY_WITNESS requires SCRIPT_VERIFY_P2SH if (flag & SCRIPT_VERIFY_WITNESS && !(flag & SCRIPT_VERIFY_P2SH)) continue; // SCRIPT_VERIFY_TAPROOT requires SCRIPT_VERIFY_WITNESS if (flag & SCRIPT_VERIFY_TAPROOT && !(flag & SCRIPT_VERIFY_WITNESS)) continue; - // SCRIPT_VERIFY_P2TSH requires SCRIPT_VERIFY_WITNESS - if (flag & SCRIPT_VERIFY_P2TSH && !(flag & SCRIPT_VERIFY_WITNESS)) continue; + // SCRIPT_VERIFY_P2MR requires SCRIPT_VERIFY_WITNESS + if (flag & SCRIPT_VERIFY_P2MR && !(flag & SCRIPT_VERIFY_WITNESS)) continue; ret.push_back(flag); } @@ -125,18 +125,18 @@ static void AssetTest(const UniValue& test, SignatureCache& signature_cache) // "final": true tests are valid for all flags. Others are only valid with flags that are // a subset of test_flags. if (fin || ((flags & test_flags) == flags)) { - // Check if this is a P2TSH script (witness version 2, 32-byte program) - bool is_p2tsh_script = false; + // Check if this is a P2MR script (witness version 2, 32-byte program) + bool is_p2mr_script = false; if (prevouts[idx].scriptPubKey.size() >= 2 && prevouts[idx].scriptPubKey[0] == 0x53 && // witness version 2 prevouts[idx].scriptPubKey[1] == 0x20 && // 32-byte program - tx.vin[idx].scriptSig.empty()) { // P2TSH should have empty ScriptSig - is_p2tsh_script = true; + tx.vin[idx].scriptSig.empty()) { // P2MR should have empty ScriptSig + is_p2mr_script = true; } - // For P2TSH scripts, only run with P2TSH flags, not Taproot flags - if (is_p2tsh_script && (flags & SCRIPT_VERIFY_TAPROOT)) { - continue; // Skip Taproot validation for P2TSH scripts + // For P2MR scripts, only run with P2MR flags, not Taproot flags + if (is_p2mr_script && (flags & SCRIPT_VERIFY_TAPROOT)) { + continue; // Skip Taproot validation for P2MR scripts } bool ret = VerifyScript(tx.vin[idx].scriptSig, prevouts[idx].scriptPubKey, &tx.vin[idx].scriptWitness, flags, txcheck, nullptr); @@ -147,7 +147,7 @@ static void AssetTest(const UniValue& test, SignatureCache& signature_cache) std::cout << "Current Flags: " << flags << std::endl; std::cout << "All flags: " << test_flags << std::endl; std::cout << "Witness size: " << tx.vin[idx].scriptWitness.stack.size() << std::endl; - std::cout << "Is P2TSH: " << (is_p2tsh_script ? "true" : "false") << std::endl; + std::cout << "Is P2MR: " << (is_p2mr_script ? "true" : "false") << std::endl; } BOOST_CHECK(ret); } diff --git a/src/test/script_standard_tests.cpp b/src/test/script_standard_tests.cpp index 7bbd7db3a99d..031e62268762 100644 --- a/src/test/script_standard_tests.cpp +++ b/src/test/script_standard_tests.cpp @@ -301,14 +301,14 @@ BOOST_AUTO_TEST_CASE(script_standard_ExtractDestination) s << OP_2 << ToByteVector(xpk); BOOST_CHECK(ExtractDestination(s, address)); - // P2TSH as witness version 2, expect WitnessV2P2TSH - // Create a uint256 from the xpk bytes and construct WitnessV2P2TSH properly + // P2MR as witness version 2, expect WitnessV2P2MR + // Create a uint256 from the xpk bytes and construct WitnessV2P2MR properly uint256 hash; auto xpk_bytes = ToByteVector(xpk); assert(xpk_bytes.size() == 32); // Ensure it's exactly 32 bytes std::copy(xpk_bytes.begin(), xpk_bytes.end(), hash.begin()); - WitnessV2P2TSH p2tsh(hash); - BOOST_CHECK(std::get(address) == p2tsh); + WitnessV2P2MR p2mr(hash); + BOOST_CHECK(std::get(address) == p2mr); } BOOST_AUTO_TEST_CASE(script_standard_GetScriptFor_) diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp index 9489bd29fb39..17ccb87912e9 100644 --- a/src/test/script_tests.cpp +++ b/src/test/script_tests.cpp @@ -93,8 +93,8 @@ static ScriptErrorDesc script_errors[]={ {SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"}, {SCRIPT_ERR_OP_CODESEPARATOR, "OP_CODESEPARATOR"}, {SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"}, - {SCRIPT_ERR_P2TSH_WRONG_CONTROL_SIZE, "P2TSH_WRONG_CONTROL_SIZE"}, - {SCRIPT_ERR_P2TSH_WRONG_PARITY_BIT, "P2TSH_WRONG_PARITY_BIT"}, + {SCRIPT_ERR_P2MR_WRONG_CONTROL_SIZE, "P2MR_WRONG_CONTROL_SIZE"}, + {SCRIPT_ERR_P2MR_WRONG_PARITY_BIT, "P2MR_WRONG_PARITY_BIT"}, }; static std::string FormatScriptError(ScriptError_t err) diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp index 7d5cacf4e2a2..b6d0b6375df3 100644 --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -71,7 +71,7 @@ static std::map mapFlagNames = { {std::string("DISCOURAGE_UPGRADABLE_PUBKEYTYPE"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE}, {std::string("DISCOURAGE_OP_SUCCESS"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS}, {std::string("DISCOURAGE_UPGRADABLE_TAPROOT_VERSION"), (unsigned int)SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION}, - {std::string("P2TSH"), (unsigned int)SCRIPT_VERIFY_P2TSH}, + {std::string("P2MR"), (unsigned int)SCRIPT_VERIFY_P2MR}, }; unsigned int ParseScriptFlags(std::string strFlags) diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index c7c39a0140f9..f28081c208a1 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -351,7 +351,7 @@ class DescribeWalletAddressVisitor UniValue operator()(const WitnessV1Taproot& id) const { return UniValue(UniValue::VOBJ); } UniValue operator()(const PayToAnchor& id) const { return UniValue(UniValue::VOBJ); } UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); } - UniValue operator()(const WitnessV2P2TSH& id) const { return UniValue(UniValue::VOBJ); } + UniValue operator()(const WitnessV2P2MR& id) const { return UniValue(UniValue::VOBJ); } }; static UniValue DescribeWalletAddress(const CWallet& wallet, const CTxDestination& dest) diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp index 2a6193de0603..536ce64b87ef 100644 --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -94,7 +94,7 @@ IsMineResult LegacyWalletIsMineInnerDONOTUSE(const LegacyDataSPKM& keystore, con case TxoutType::NULL_DATA: case TxoutType::WITNESS_UNKNOWN: case TxoutType::WITNESS_V1_TAPROOT: - case TxoutType::WITNESS_V2_P2TSH: + case TxoutType::WITNESS_V2_P2MR: case TxoutType::ANCHOR: break; case TxoutType::PUBKEY: From 71e4215acb8ffaccf43def4478647390304c4cf8 Mon Sep 17 00:00:00 2001 From: Hennadii Stepanov <32963518+hebasto@users.noreply.github.com> Date: Wed, 8 Oct 2025 18:22:42 +0100 Subject: [PATCH 4/4] qt: Modernize custom filtering In `QSortFilterProxyModel`, `invalidateFilter()` is scheduled for deprecation in Qt 6.13. `beginFilterChange()` was introduced in Qt 6.9. `endFilterChange()` was introduced in Qt 6.10. --- src/qt/transactionfilterproxy.cpp | 46 +++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index 1ad77fd767fd..89099260a9c0 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -52,32 +52,78 @@ bool TransactionFilterProxy::filterAcceptsRow(int sourceRow, const QModelIndex & void TransactionFilterProxy::setDateRange(const std::optional& from, const std::optional& to) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + dateFrom = from; dateTo = to; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setSearchString(const QString &search_string) { if (m_search_string == search_string) return; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + m_search_string = search_string; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setTypeFilter(quint32 modes) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + this->typeFilter = modes; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setMinAmount(const CAmount& minimum) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + this->minAmount = minimum; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif } void TransactionFilterProxy::setShowInactive(bool _showInactive) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + beginFilterChange(); +#endif + this->showInactive = _showInactive; + +#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0) + endFilterChange(QSortFilterProxyModel::Direction::Rows); +#else invalidateFilter(); +#endif }