Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nodejs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,5 @@ coverage/
.vscode/
*.swp
*.swo

c_sources
18 changes: 7 additions & 11 deletions nodejs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
}
```

Expand Down Expand Up @@ -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

Expand Down
85 changes: 33 additions & 52 deletions nodejs/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -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/dilithium_ref/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": [
"<!@(node -p \"require('node-addon-api').include\")",
"../include",
"../dilithium/ref",
"../sphincsplus/ref",
"../falcon"
"src/c_sources/include",
"src/c_sources/dilithium_ref",
"src/c_sources/sphincsplus_ref"
],
"dependencies": [
"<!(node -p \"require('node-addon-api').gyp\")"
Expand All @@ -67,7 +52,6 @@
"DILITHIUM_MODE=2",
"CRYPTO_ALGNAME=\"SPHINCS+-shake-128s\"",
"PARAMS=sphincs-shake-128s",
"FALCON_LOGN_512=9",
"CUSTOM_RANDOMBYTES=1"
],
"conditions": [
Expand All @@ -88,9 +72,6 @@
"-Wno-implicit-function-declaration"
]
},
"defines": [
"FALCON_FPEMU=1"
]
}]
]
}
Expand Down
52 changes: 22 additions & 30 deletions nodejs/examples/basic-usage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,45 @@ import {
import crypto from "crypto";

/**
* This example demonstrates basic usage of the bitcoinpqc TypeScript bindings.
* This example demonstrates basic usage of the bitcoinpqc TypeScript bindings
* with SLH-DSA-SHAKE-128S (SPHINCS+).
*
* It shows:
* 1. Getting key and signature sizes
* 1. Getting key and signature sizes for SLH-DSA
* 2. Key generation
* 3. Signing messages
* 4. Verifying signatures
* 5. Error handling
*/

// Print key sizes for all algorithms
console.log("===== Key and Signature Sizes =====");
for (const algo of [
Algorithm.ML_DSA_44,
Algorithm.SLH_DSA_SHAKE_128S,
Algorithm.FN_DSA_512,
]) {
const algoName = Algorithm[algo];
console.log(`${algoName}:`);
console.log(` Public key size: ${publicKeySize(algo)} bytes`);
console.log(` Secret key size: ${secretKeySize(algo)} bytes`);
console.log(` Signature size: ${signatureSize(algo)} bytes`);
console.log();
}
// Print key sizes for SLH-DSA algorithm
console.log("===== SLH-DSA Key and Signature Sizes =====");
const algo = Algorithm.SLH_DSA_SHAKE_128S;
const algoName = Algorithm[algo];
console.log(`${algoName}:`);
console.log(` Public key size: ${publicKeySize(algo)} bytes`);
console.log(` Secret key size: ${secretKeySize(algo)} bytes`);
console.log(` Signature size: ${signatureSize(algo)} bytes`);
console.log();

// Generate a keypair
function generateKeysAndSign(algorithm: Algorithm, message: string): void {
console.log(`===== Working with ${Algorithm[algorithm]} =====`);
// Generate a keypair and demonstrate SLH-DSA functionality
function demonstrateSlhDsa(): void {
console.log(`===== Working with ${Algorithm[Algorithm.SLH_DSA_SHAKE_128S]} =====`);

// Generate random data for key generation
console.log("Generating random data...");
const randomData = crypto.randomBytes(128);

try {
// Generate a keypair
console.log("Generating keypair...");
const keypair = generateKeyPair(algorithm, randomData);
console.log("Generating SLH-DSA keypair...");
const keypair = generateKeyPair(Algorithm.SLH_DSA_SHAKE_128S, randomData);
console.log(
`Generated keypair with public key size ${keypair.publicKey.bytes.length} bytes`
);

// Create a message to sign
const message = "Hello from SLH-DSA-SHAKE-128S (SPHINCS+)!";
const messageBytes = Buffer.from(message, "utf-8");
console.log(`Message to sign: "${message}"`);

Expand All @@ -69,7 +66,7 @@ function generateKeysAndSign(algorithm: Algorithm, message: string): void {
console.error("❌ Signature verification failed:", error);
}

// Try verifying with a different message (should fail with real implementation)
// Try verifying with a different message (should fail)
const badMessage = Buffer.from(message + " (modified)", "utf-8");
console.log(
`\nAttempting to verify with modified message: "${message} (modified)"`
Expand All @@ -83,18 +80,13 @@ function generateKeysAndSign(algorithm: Algorithm, message: string): void {
}
} catch (error) {
console.error(
`❌ Error while working with ${Algorithm[algorithm]}:`,
`❌ Error while working with ${Algorithm[Algorithm.SLH_DSA_SHAKE_128S]}:`,
error
);
}

console.log("\n");
}

// Run examples with working algorithms
generateKeysAndSign(Algorithm.FN_DSA_512, "Hello from FN-DSA-512 (Falcon)!");
generateKeysAndSign(Algorithm.ML_DSA_44, "Hello from ML-DSA-44 (Dilithium)!");
generateKeysAndSign(
Algorithm.SLH_DSA_SHAKE_128S,
"Hello from SLH-DSA-SHAKE-128S (SPHINCS+)!"
);
// Run the SLH-DSA demonstration
demonstrateSlhDsa();
8 changes: 4 additions & 4 deletions nodejs/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 21 additions & 7 deletions nodejs/package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "bitcoinpqc",
"version": "0.1.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": {
"build": "tsc && node-gyp rebuild",
"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",
Expand All @@ -18,11 +19,19 @@
"cryptography",
"signature",
"dilithium",
"falcon",
"sphincs+"
],
"author": "",
"author": "Hunter Beast <hunter@surmount.systems>",
"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",
Expand All @@ -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"
}
}
41 changes: 41 additions & 0 deletions nodejs/scripts/sync-c-sources.sh
Original file line number Diff line number Diff line change
@@ -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!"
Loading
Loading