@scintilla-network/signatures
Version:
Enhanced signature and key exchange functions for blockchain and crypto applications, including post-quantum algorithms
134 lines (125 loc) • 4.71 kB
JavaScript
/**
* @typedef {import('../types.js').Bytes} Bytes
* @typedef {import('../types.js').PublicKey} PublicKey
* @typedef {import('../types.js').PrivateKey} PrivateKey
* @typedef {import('../types.js').Signature} Signature
* @typedef {import('../types.js').Signing} Signing
*/
import { bls12_381 as bls } from '@noble/curves/bls12-381';
import { isUint8Array } from '../utils/types.js';
import { formatMessage } from '../utils/format.js';
// Export ProjectivePoint for external use
/**
* BLS signatures on BLS12-381 curve (Boneh-Lynn-Shacham)
* Implements the {@link Signing} interface
* @namespace bls12_381
*/
export const bls12_381 = {
/**
* Generate a new private key
* @param {Bytes} [seed] - Optional 32-byte seed for deterministic key generation
* @returns {PrivateKey} 32-byte private key
* @throws {Error} If seed is invalid
*/
generatePrivateKey(seed) {
if (seed !== undefined) {
if (!isUint8Array(seed)) {
throw new Error('seed must be a Uint8Array');
}
if (seed.length !== 32) {
throw new Error('seed must be 32 bytes');
}
return seed;
}
return bls.utils.randomPrivateKey();
},
/**
* Generate a new key pair
* @param {Bytes} [seed] - Optional 32-byte seed for deterministic key generation
* @returns {{ publicKey: PublicKey; privateKey: PrivateKey }} Generated key pair
* @throws {Error} If seed is invalid
*/
generateKeyPair(seed) {
const privateKey = this.generatePrivateKey(seed);
const publicKey = this.getPublicKey(privateKey);
return { publicKey, privateKey };
},
/**
* Derive public key from private key
* @param {PrivateKey} privateKey - 32-byte private key
* @returns {PublicKey} 48-byte public key
* @throws {Error} If private key is invalid
*/
getPublicKey(privateKey) {
if (!isUint8Array(privateKey)) {
throw new Error('privateKey must be a Uint8Array');
}
return bls.getPublicKey(privateKey);
},
/**
* Sign a message
* @param {Bytes} message - Message to sign
* @param {PrivateKey} privateKey - 32-byte private key
* @returns {Signature} 96-byte signature
* @throws {Error} If inputs are invalid
*/
sign(message, privateKey) {
if (!isUint8Array(message)) {
throw new Error('message must be a Uint8Array, use utils.formatMessage() for automatic conversion');
}
if (!isUint8Array(privateKey)) {
throw new Error('privateKey must be a Uint8Array');
}
return bls.sign(formatMessage(message), privateKey);
},
/**
* Verify a signature
* @param {Signature} signature - 96-byte signature to verify
* @param {Bytes} message - Original message
* @param {PublicKey} publicKey - 48-byte public key
* @returns {boolean} True if signature is valid
* @throws {Error} If inputs are invalid
*/
verify(signature, message, publicKey) {
if (!isUint8Array(message)) {
throw new Error('message must be a Uint8Array, use utils.formatMessage() for automatic conversion');
}
if (!isUint8Array(signature)) {
throw new Error('signature must be a Uint8Array');
}
if (!isUint8Array(publicKey)) {
throw new Error('publicKey must be a Uint8Array');
}
return bls.verify(signature, formatMessage(message), publicKey);
},
/**
* Aggregate signatures
* @param {Signature[]} signatures - Array of 96-byte signatures to aggregate
* @returns {Signature} 96-byte aggregated signature
* @throws {Error} If inputs are invalid
*/
aggregateSignatures(signatures) {
if (!Array.isArray(signatures)) {
throw new Error('signatures must be an array');
}
if (signatures.some(sig => !isUint8Array(sig))) {
throw new Error('all signatures must be Uint8Array');
}
return bls.aggregateSignatures(signatures);
},
/**
* Aggregate public keys
* @param {PublicKey[]} publicKeys - Array of 48-byte public keys to aggregate
* @returns {PublicKey} 48-byte aggregated public key
* @throws {Error} If inputs are invalid
*/
aggregatePublicKeys(publicKeys) {
if (!Array.isArray(publicKeys)) {
throw new Error('publicKeys must be an array');
}
if (publicKeys.some(key => !isUint8Array(key))) {
throw new Error('all public keys must be Uint8Array');
}
return bls.aggregatePublicKeys(publicKeys);
}
};