mirror of https://codeberg.org/pzp/pzp-keypair.git
102 lines
2.8 KiB
JavaScript
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
|