UNPKG

dilithium-crystals-js

Version:

Dilithium post-quantum cryptography implementation for Node.js and browsers

195 lines (170 loc) 5.53 kB
const DILITHIUM_PARAMS = [ { CRYPTO_PUBLICKEYBYTES: 896, CRYPTO_SECRETKEYBYTES: 2096, CRYPTO_BYTES: 1387, }, { CRYPTO_PUBLICKEYBYTES: 1184, CRYPTO_SECRETKEYBYTES: 2800, CRYPTO_BYTES: 2044, }, { CRYPTO_PUBLICKEYBYTES: 1472, CRYPTO_SECRETKEYBYTES: 3504, CRYPTO_BYTES: 2701, }, { CRYPTO_PUBLICKEYBYTES: 1760, CRYPTO_SECRETKEYBYTES: 3856, CRYPTO_BYTES: 3366, }, ]; function generateKeys(dilithium, kind, seed) { if (kind < 0 || kind > 3) { return -1; } const seedSize = seed ? seed.length : 0; const seedPtr = seed ? dilithium._malloc(seedSize) : 0; if (seed) { dilithium.HEAPU8.set(new Uint8Array(seed), seedPtr); } const privateKeySize = DILITHIUM_PARAMS[kind].CRYPTO_SECRETKEYBYTES; const publicKeySize = DILITHIUM_PARAMS[kind].CRYPTO_PUBLICKEYBYTES; const publicKeyPtr = dilithium._malloc(publicKeySize); const privateKeyPtr = dilithium._malloc(privateKeySize); const result = dilithium.ccall( "dilithium_keygen", "number", ["number", "number", "number", "number", "number"], [publicKeyPtr, privateKeyPtr, kind, seedPtr, seedSize] ); let publicKey, privateKey; if (result === 0) { publicKey = new Uint8Array( dilithium.HEAPU8.subarray(publicKeyPtr, publicKeyPtr + publicKeySize) ); privateKey = new Uint8Array( dilithium.HEAPU8.subarray(privateKeyPtr, privateKeyPtr + privateKeySize) ); } if (seedPtr) dilithium._free(seedPtr); dilithium._free(publicKeyPtr); dilithium._free(privateKeyPtr); return { result, publicKey, privateKey }; } function sign(dilithium, message, privateKey, kind) { if (kind < 0 || kind > 3) { throw new Error("Invalid Dilithium kind"); } const params = DILITHIUM_PARAMS[kind]; const cryptoBytes = params.CRYPTO_BYTES; // Allocate memory for inputs const messageLength = message.length; const messagePtr = dilithium._malloc(messageLength); dilithium.HEAPU8.set(new Uint8Array(message), messagePtr); const privateKeySize = privateKey.length; if (privateKeySize !== params.CRYPTO_SECRETKEYBYTES) { throw new Error( `Invalid private key size. Expected: ${params.CRYPTO_SECRETKEYBYTES}, Provided: ${privateKeySize}` ); } const privateKeyPtr = dilithium._malloc(privateKeySize); dilithium.HEAPU8.set(new Uint8Array(privateKey), privateKeyPtr); // Allocate memory for outputs const maxSignatureLength = cryptoBytes + messageLength; const signaturePtr = dilithium._malloc(maxSignatureLength); const signatureLengthPtr = dilithium._malloc(4); // size_t is 4 bytes dilithium.setValue(signatureLengthPtr, maxSignatureLength, "i32"); // Call the C function const result = dilithium.ccall( "dilithium_sign", "number", ["number", "number", "number", "number", "number", "number", "number"], [ signaturePtr, signatureLengthPtr, messagePtr, messageLength, privateKeyPtr, privateKeySize, kind, ] ); // Get the actual signature length const actualSignatureLength = dilithium.getValue(signatureLengthPtr, "i32"); // Copy the signature data const signatureData = new Uint8Array( dilithium.HEAPU8.buffer, signaturePtr, actualSignatureLength ); const signature = new Uint8Array(signatureData); // Free allocated memory dilithium._free(messagePtr); dilithium._free(privateKeyPtr); dilithium._free(signaturePtr); dilithium._free(signatureLengthPtr); return { result, signature, signatureLength: actualSignatureLength }; } function verify(dilithium, signature, message, publicKey, kind) { // Determine the expected sizes based on the Dilithium kind const params = DILITHIUM_PARAMS[kind]; const expectedSignatureSize = params.CRYPTO_BYTES + message.length; const expectedPublicKeySize = params.CRYPTO_PUBLICKEYBYTES; // Validate input sizes if (signature.length !== expectedSignatureSize) { throw new Error( `Invalid signature size. Expected ${expectedSignatureSize}, got ${signature.length}` ); } if (publicKey.length !== expectedPublicKeySize) { throw new Error( `Invalid public key size. Expected ${expectedPublicKeySize}, got ${publicKey.length}` ); } // Allocate memory for the signature, message, and public key const signaturePtr = dilithium._malloc(expectedSignatureSize); const messagePtr = dilithium._malloc(message.length); const publicKeyPtr = dilithium._malloc(expectedPublicKeySize); // Copy the data to the allocated memory dilithium.HEAPU8.set(new Uint8Array(signature), signaturePtr); dilithium.HEAPU8.set(new Uint8Array(message), messagePtr); dilithium.HEAPU8.set(new Uint8Array(publicKey), publicKeyPtr); try { const result = dilithium.ccall( "dilithium_verify", "number", ["number", "number", "number", "bigint", "number", "number", "number"], [ signaturePtr, expectedSignatureSize, messagePtr, BigInt(message.length), publicKeyPtr, expectedPublicKeySize, kind, ] ); return { result, signatureLength: signature.length, expectedSignatureSize, messageLength: message.length, publicKeyLength: publicKey.length, expectedPublicKeySize, kind, }; } finally { // Free the allocated memory dilithium._free(signaturePtr); dilithium._free(messagePtr); dilithium._free(publicKeyPtr); } } module.exports = { DILITHIUM_PARAMS, generateKeys, sign, verify, };