@libp2p/crypto
Version:
Crypto primitives for libp2p
98 lines • 3.88 kB
JavaScript
import crypto from 'crypto';
import { ed25519 as ed } from '@noble/curves/ed25519.js';
import { concat as uint8arrayConcat } from 'uint8arrays/concat';
import { fromString as uint8arrayFromString } from 'uint8arrays/from-string';
import { toString as uint8arrayToString } from 'uint8arrays/to-string';
const keypair = crypto.generateKeyPairSync;
const PUBLIC_KEY_BYTE_LENGTH = 32;
const PRIVATE_KEY_BYTE_LENGTH = 64; // private key is actually 32 bytes but for historical reasons we concat private and public keys
const KEYS_BYTE_LENGTH = 32;
const SIGNATURE_BYTE_LENGTH = 64;
export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength };
export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength };
function derivePublicKey(privateKey) {
return ed.getPublicKey(privateKey);
}
export function generateKey() {
const key = keypair('ed25519', {
publicKeyEncoding: { type: 'spki', format: 'jwk' },
privateKeyEncoding: { type: 'pkcs8', format: 'jwk' }
});
// @ts-expect-error node types are missing jwk as a format
const privateKeyRaw = uint8arrayFromString(key.privateKey.d, 'base64url');
// @ts-expect-error node types are missing jwk as a format
const publicKeyRaw = uint8arrayFromString(key.publicKey.x, 'base64url');
return {
privateKey: uint8arrayConcat([privateKeyRaw, publicKeyRaw], privateKeyRaw.byteLength + publicKeyRaw.byteLength),
publicKey: publicKeyRaw
};
}
/**
* Generate keypair from a 32 byte uint8array
*/
export function generateKeyFromSeed(seed) {
if (seed.length !== KEYS_BYTE_LENGTH) {
throw new TypeError('"seed" must be 32 bytes in length.');
}
else if (!(seed instanceof Uint8Array)) {
throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.');
}
// based on node forges algorithm, the seed is used directly as private key
const publicKeyRaw = derivePublicKey(seed);
return {
privateKey: uint8arrayConcat([seed, publicKeyRaw], seed.byteLength + publicKeyRaw.byteLength),
publicKey: publicKeyRaw
};
}
export function hashAndSign(key, msg) {
if (!(key instanceof Uint8Array)) {
throw new TypeError('"key" must be a node.js Buffer, or Uint8Array.');
}
let privateKey;
let publicKey;
if (key.byteLength === PRIVATE_KEY_BYTE_LENGTH) {
privateKey = key.subarray(0, 32);
publicKey = key.subarray(32);
}
else if (key.byteLength === KEYS_BYTE_LENGTH) {
privateKey = key.subarray(0, 32);
publicKey = derivePublicKey(privateKey);
}
else {
throw new TypeError('"key" must be 64 or 32 bytes in length.');
}
const obj = crypto.createPrivateKey({
format: 'jwk',
key: {
crv: 'Ed25519',
d: uint8arrayToString(privateKey, 'base64url'),
x: uint8arrayToString(publicKey, 'base64url'),
kty: 'OKP'
}
});
return crypto.sign(null, msg instanceof Uint8Array ? msg : msg.subarray(), obj);
}
export function hashAndVerify(key, sig, msg) {
if (key.byteLength !== PUBLIC_KEY_BYTE_LENGTH) {
throw new TypeError('"key" must be 32 bytes in length.');
}
else if (!(key instanceof Uint8Array)) {
throw new TypeError('"key" must be a node.js Buffer, or Uint8Array.');
}
if (sig.byteLength !== SIGNATURE_BYTE_LENGTH) {
throw new TypeError('"sig" must be 64 bytes in length.');
}
else if (!(sig instanceof Uint8Array)) {
throw new TypeError('"sig" must be a node.js Buffer, or Uint8Array.');
}
const obj = crypto.createPublicKey({
format: 'jwk',
key: {
crv: 'Ed25519',
x: uint8arrayToString(key, 'base64url'),
kty: 'OKP'
}
});
return crypto.verify(null, msg instanceof Uint8Array ? msg : msg.subarray(), obj, sig);
}
//# sourceMappingURL=index.js.map