UNPKG

iso-signatures

Version:
122 lines (106 loc) 2.94 kB
import { getPublicKey, signAsync, utils } from '@noble/secp256k1' import { base64pad, base64url } from 'iso-base/rfc4648' import { u8 } from 'iso-base/utils' import { tag, untag } from 'iso-base/varint' import { DID } from 'iso-did' import { DIDKey } from 'iso-did/key' import { didKeyOrVerifiableDID } from '../utils.js' /** * @typedef {import('../types.js').ISigner<string>} ISigner */ /** * @param {import('iso-did/types').VerifiableDID} did */ function checkDid(did) { if (did.verifiableDid.type !== 'secp256k1') { throw new TypeError(`Unsupported key type ${did.verifiableDid.type}`) } } /** * ES256K signer (secp256k1 and SHA-256) * * @implements {ISigner} */ export class ES256KSigner extends DID { /** * Multibase code for secp256k1 private key * @see https://github.com/multiformats/multicodec/blob/3bc7f4c20afe28e10d9d539e2a565578de6dd71c/table.csv#L182 * @type {number} */ static code = 0x1301 /** @type {import('../types.js').SignatureType} */ signatureType /** @type {Uint8Array} */ #privateKey /** * * @param {import('iso-did/types').VerifiableDID} did * @param {Uint8Array} privateKey */ constructor(did, privateKey) { checkDid(did) super(did) this.#privateKey = privateKey this.signatureType = 'ES256K' } /** * Generate a new signer * * @param {Uint8Array} [bytes] */ static generate(bytes) { const privateKey = bytes || utils.randomPrivateKey() const publicKey = getPublicKey(privateKey) return new ES256KSigner( DIDKey.fromPublicKey('secp256k1', publicKey), privateKey ) } /** * Import a signer from a JWK * * @param {import('iso-did/types').ECJWKPrivate} jwk * @param {import('iso-did/types').VerifiableDID} [did] - Optional DID to verify the JWK */ static importJwk(jwk, did) { const privateKey = base64url.decode(jwk.d) const publicKey = getPublicKey(privateKey) return new ES256KSigner( didKeyOrVerifiableDID('secp256k1', publicKey, did), privateKey ) } /** * Import a signer from a encoded string * * @param {string} encoded * @param {import('iso-did/types').VerifiableDID} [did] */ static import(encoded, did) { const privateKey = untag(ES256KSigner.code, base64pad.decode(encoded)) const publicKey = getPublicKey(privateKey) return new ES256KSigner( didKeyOrVerifiableDID('secp256k1', publicKey, did), privateKey ) } /** * Sign a message * * @param {Uint8Array} message */ async sign(message) { const hash = await globalThis.crypto.subtle.digest('SHA-256', message) const sig = await signAsync(u8(hash), this.#privateKey) return sig.toCompactRawBytes() } /** * Export the signer as a encoded string */ export() { return base64pad.encode(tag(ES256KSigner.code, this.#privateKey)) } toString() { return this.didObject.didUrl } }