slh-dsa
v0.0.5
Published
Lightweight wrapper for SLH-DSA or SPHINCS+
Maintainers
Readme
SLH-DSA/Sphincs+
A lightweight wrapper around @noble/post-quantum providing a simplified interface for SLH-DSA (SPHINCS+) stateless hash-based signatures.
Features
🔐 Simple API: Just
keygen(),sign(), andverify()🪶 Lightweight: Minimal abstraction over noble's implementation
📦 Zero dependencies: Only requires
@noble/hashes⚡ Multiple security levels: SLH-DSA-SHA2/SHAKE-128s, 128f, 192s, 192f, 256s
Installation
npm install slh-dsaQuick Start
import { slh_dsa_sha2_128s } from 'sslh-dsa';
// Generate keypair
const { publicKey, privateKey } = slh_dsa_sha2_128s.keygen();
// Sign a message
const message = new TextEncoder().encode('Hello quantum world!');
const signature = slh_dsa_sha2_128s.sign(message, privateKey);
// Verify the signature
const isValid = slh_dsa_sha2_128s.verify(signature, message, publicKey);
console.log('Signature valid:', isValid); // trueAPI
SphincsSigner
Created a new SLH-DSA instance with the specified algorithm.
Supported algorithms:
// Standard configuration
import {
slh_dsa_sha2_128f as sph,
slh_dsa_sha2_128s,
slh_dsa_sha2_192f,
slh_dsa_sha2_192s,
slh_dsa_sha2_256f,
slh_dsa_sha2_256s,
slh_dsa_shake_128f,
slh_dsa_shake_128s,
slh_dsa_shake_192f,
slh_dsa_shake_192s,
slh_dsa_shake_256f,
slh_dsa_shake_256s,
} from 'slh-dsa';
/* Special in this library */
// custom parameter
import { customSphincs } from 'slh-dsa'
const slh = customSphincs({ /* custom options */ }, /* hash function (sha256/sha512/shake) */)
// progress sign callback
const signature = slh.sign(message, secretKey, {
onProgress: (progress) => console.log(progress) // progress 0-100
})keygen()
Generates a new keypair. Returns:
{
publicKey: Uint8Array;
secretKey: Uint8Array;
}sign(message, privateKey)
Signs a message using the private key.
privateKey:Uint8Array- The private key fromgenerateKeys()message:Uint8Array- The message to sign
Returns: Uint8Array - The signature
verify(signature, message, publicKey)
Verifies a signature.
publicKey:Uint8Array- The public key fromgenerateKeys()message:Uint8Array- The original messagesignature:Uint8Array- The signature to verify
Returns: boolean - true if valid, false otherwise
Key Sizes
| algorithm | sig size | keygen | sign | verify | | --------- | -------- | ------ | ------ | ------ | | sha2_128f | 18088 | 4ms | 90ms | 6ms | | sha2_192f | 35664 | 6ms | 160ms | 9ms | | sha2_256f | 49856 | 15ms | 340ms | 9ms | | sha2_128s | 7856 | 260ms | 2000ms | 2ms | | sha2_192s | 16224 | 380ms | 3800ms | 3ms | | sha2_256s | 29792 | 250ms | 3400ms | 4ms | | shake_192f | 35664 | 21ms | 553ms | 29ms | | shake_192s | 16224 | 260ms | 2635ms | 2ms |
Examples
Example.js
// example.js - Complete Usage Example
import { slh_dsa_sha2_128s } from 'slh-dsa';
async function example() {
console.log('🔐 SLH-DSA SHA2-128s Example\n');
const start = Date.now();
// Generate keys
console.log('📋 Generating keypair...');
const { publicKey, secretKey } = slh_dsa_sha2_128s.keygen();
console.log(` Public key:`, publicKey.slice(0, 32), publicKey.length);
console.log(` Private key:`, secretKey.slice(0, 32), secretKey.length);
console.log(` Time: ${Date.now() - start}ms\n`);
// Original message
const message = crypto.getRandomValues(new Uint8Array(32));
console.log(`📝 Original message:"`, message);
// Sign
const signStart = Date.now();
const signature = slh_dsa_sha2_128s.sign(message, secretKey);
console.log(`\n✍️ Signing...`);
console.log(` Signature:`, signature);
console.log(` Signature size:`, signature.length);
console.log(` Time: ${Date.now() - signStart}ms`);
// Verify original
const verifyStart = Date.now();
const valid = slh_dsa_sha2_128s.verify(signature, message, publicKey);
console.log(`\n✅ Verifying original message...`);
console.log(` Result: ${valid ? 'VALID ✓' : 'INVALID ✗'}`);
console.log(` Time: ${Date.now() - verifyStart}ms`);
// Try wrong message
const wrongMessage = crypto.getRandomValues(new Uint8Array(32));
const validWrong = slh_dsa_sha2_128s.verify(signature, wrongMessage, publicKey);
console.log(`\n❌ Verifying WRONG message...`);
console.log(` Message: "${wrongMessage}"`);
console.log(` Result: ${validWrong ? 'VALID ✓ (SHOULD FAIL!)' : 'INVALID ✗ (GOOD!)'}`);
// Try tampered signature
const tamperedSig = Uint8Array.from(signature);
tamperedSig[0] = 255
const validTampered = slh_dsa_sha2_128s.verify(tamperedSig, message, publicKey);
console.log(`\n🔧 Verifying TAMPERED signature...`);
console.log(` Result: ${validTampered ? 'VALID ✓ (SHOULD FAIL!)' : 'INVALID ✗ (GOOD!)'}`);
// Try wrong public key
const keys2 = slh_dsa_sha2_128s.keygen();
const validWrongKey = slh_dsa_sha2_128s.verify(signature, message, keys2.publicKey);
console.log(`\n🔑 Verifying with WRONG public key...`);
console.log(` Result: ${validWrongKey ? 'VALID ✓ (SHOULD FAIL!)' : 'INVALID ✗ (GOOD!)'}`);
// Summary
console.log('\n' + '='.repeat(50));
console.log('📊 SUMMARY');
console.log('='.repeat(50));
console.log(`Algorithm: SLH-DSA-SHA2-128s`);
console.log(`Security level: 128-bit post-quantum`);
console.log(`Public key size: 32 bytes`);
console.log(`Private key size: 64 bytes`);
console.log(`Signature size: 7856 bytes (~7.8 KB)`);
console.log('='.repeat(50));
}
example().catch(console.error);License
MIT © nbrthx
Security
This is a thin wrapper around the well-audited @noble/post-quantum library. Please refer to their security documentation for details about the cryptographic implementation.
