pzp-keypair/lib/curves/ed25519.js

102 lines
2.8 KiB
JavaScript

// @ts-ignore
const sodium = require('sodium-universal')
const base58 = require('bs58')
/**
* @typedef {import('.').Keypair} Keypair
*
* @typedef {import('.').KeypairPublicSlice} KeypairPublicSlice
*
* @typedef {import('.').KeypairPrivateSlice} KeypairPrivateSlice
*/
const SEEDBYTES = sodium.crypto_sign_SEEDBYTES
const PUBLICKEYBYTES = sodium.crypto_sign_PUBLICKEYBYTES
const SECRETKEYBYTES = sodium.crypto_sign_SECRETKEYBYTES
const ed25519 = {
/**
* @param {(string | Buffer)=} seed
* @returns {Keypair}
*/
generate(seed) {
let seedBuf
if (seed) {
if (Buffer.isBuffer(seed)) {
// prettier-ignore
if (seed.length !== SEEDBYTES) throw new Error(`seed must be ${SEEDBYTES} bytes`)
seedBuf = seed
} else if (typeof seed === 'string') {
seedBuf = Buffer.alloc(SEEDBYTES)
const slice = seed.substring(0, SEEDBYTES)
Buffer.from(slice, 'utf-8').copy(seedBuf)
}
}
const publicKeyBuf = Buffer.alloc(PUBLICKEYBYTES)
const secretKeyBuf = Buffer.alloc(SECRETKEYBYTES)
if (seedBuf) {
sodium.crypto_sign_seed_keypair(publicKeyBuf, secretKeyBuf, seedBuf)
} else {
sodium.crypto_sign_keypair(publicKeyBuf, secretKeyBuf)
}
return {
curve: 'ed25519',
public: base58.encode(publicKeyBuf),
private: base58.encode(secretKeyBuf),
_public: publicKeyBuf,
_private: secretKeyBuf,
}
},
/**
* @param {Keypair} keypair
* @param {{indented?: boolean}=} opts
*/
toJSON(keypair, opts) {
const stringifiable = {
curve: keypair.curve,
public: keypair.public,
private: keypair.private,
}
if (opts?.indented) {
return JSON.stringify(stringifiable, null, 2)
} else {
return JSON.stringify(stringifiable)
}
},
/**
* @param {KeypairPrivateSlice} keypair
* @param {Buffer} message
* @returns {string}
*/
sign(keypair, message) {
if (!keypair._private && !keypair.private) {
throw new Error(`invalid ed25519 keypair with missing private key`)
}
keypair._private ??= Buffer.from(base58.decode(keypair.private))
const sig = Buffer.alloc(sodium.crypto_sign_BYTES)
sodium.crypto_sign_detached(sig, message, keypair._private)
return base58.encode(sig)
},
/**
* @param {KeypairPublicSlice} keypair
* @param {string} sig
* @param {Buffer} message
* @returns {boolean}
*/
verify(keypair, sig, message) {
if (!keypair._public && !keypair.public) {
throw new Error(`invalid ed25519 keypair with missing public key`)
}
keypair._public ??= Buffer.from(base58.decode(keypair.public))
const sigBuf = Buffer.from(base58.decode(sig))
return sodium.crypto_sign_verify_detached(sigBuf, message, keypair._public)
},
}
module.exports = ed25519