UNPKG

@bsv/sdk

Version:

BSV Blockchain Software Development Kit

188 lines 8.08 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ProtoWallet = void 0; const CachedKeyDeriver_js_1 = __importDefault(require("./CachedKeyDeriver.js")); const index_js_1 = require("../primitives/index.js"); /** * A ProtoWallet is precursor to a full wallet, capable of performing all foundational cryptographic operations. * It can derive keys, create signatures, facilitate encryption and HMAC operations, and reveal key linkages. * * However, ProtoWallet does not create transactions, manage outputs, interact with the blockchain, * enable the management of identity certificates, or store any data. It is also not concerned with privileged keys. */ class ProtoWallet { constructor(rootKeyOrKeyDeriver) { if (typeof rootKeyOrKeyDeriver.identityKey !== 'string') { rootKeyOrKeyDeriver = new CachedKeyDeriver_js_1.default(rootKeyOrKeyDeriver); } this.keyDeriver = rootKeyOrKeyDeriver; } async getPublicKey(args) { if (args.identityKey) { if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } return { publicKey: this.keyDeriver.rootKey.toPublicKey().toString() }; } else { if (args.protocolID == null || args.keyID == null || args.keyID === '') { throw new Error('protocolID and keyID are required if identityKey is false or undefined.'); } const keyDeriver = this.keyDeriver ?? (() => { throw new Error('keyDeriver is undefined'); })(); return { publicKey: keyDeriver .derivePublicKey(args.protocolID, args.keyID, args.counterparty ?? 'self', args.forSelf) .toString() }; } } async revealCounterpartyKeyLinkage(args) { const { publicKey: identityKey } = await this.getPublicKey({ identityKey: true }); if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } const linkage = this.keyDeriver.revealCounterpartySecret(args.counterparty); const linkageProof = new index_js_1.Schnorr().generateProof(this.keyDeriver.rootKey, this.keyDeriver.rootKey.toPublicKey(), index_js_1.PublicKey.fromString(args.counterparty), index_js_1.Point.fromDER(linkage)); const linkageProofBin = [ ...linkageProof.R.encode(true), ...linkageProof.SPrime.encode(true), ...linkageProof.z.toArray() ]; const revelationTime = new Date().toISOString(); const { ciphertext: encryptedLinkage } = await this.encrypt({ plaintext: linkage, protocolID: [2, 'counterparty linkage revelation'], keyID: revelationTime, counterparty: args.verifier }); const { ciphertext: encryptedLinkageProof } = await this.encrypt({ plaintext: linkageProofBin, protocolID: [2, 'counterparty linkage revelation'], keyID: revelationTime, counterparty: args.verifier }); return { prover: identityKey, verifier: args.verifier, counterparty: args.counterparty, revelationTime, encryptedLinkage, encryptedLinkageProof }; } async revealSpecificKeyLinkage(args) { const { publicKey: identityKey } = await this.getPublicKey({ identityKey: true }); if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } const linkage = this.keyDeriver.revealSpecificSecret(args.counterparty, args.protocolID, args.keyID); const { ciphertext: encryptedLinkage } = await this.encrypt({ plaintext: linkage, protocolID: [ 2, `specific linkage revelation ${args.protocolID[0]} ${args.protocolID[1]}` ], keyID: args.keyID, counterparty: args.verifier }); const { ciphertext: encryptedLinkageProof } = await this.encrypt({ plaintext: [0], protocolID: [ 2, `specific linkage revelation ${args.protocolID[0]} ${args.protocolID[1]}` ], keyID: args.keyID, counterparty: args.verifier }); return { prover: identityKey, verifier: args.verifier, counterparty: args.counterparty, protocolID: args.protocolID, keyID: args.keyID, encryptedLinkage, encryptedLinkageProof, proofType: 0 }; } async encrypt(args) { if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } const key = this.keyDeriver.deriveSymmetricKey(args.protocolID, args.keyID, args.counterparty ?? 'self'); return { ciphertext: key.encrypt(args.plaintext) }; } async decrypt(args) { if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } const key = this.keyDeriver.deriveSymmetricKey(args.protocolID, args.keyID, args.counterparty ?? 'self'); return { plaintext: key.decrypt(args.ciphertext) }; } async createHmac(args) { if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } const key = this.keyDeriver.deriveSymmetricKey(args.protocolID, args.keyID, args.counterparty ?? 'self'); return { hmac: index_js_1.Hash.sha256hmac(key.toArray(), args.data) }; } async verifyHmac(args) { if (this.keyDeriver == null) { throw new Error('keyDeriver is undefined'); } const key = this.keyDeriver.deriveSymmetricKey(args.protocolID, args.keyID, args.counterparty ?? 'self'); const valid = index_js_1.Hash.sha256hmac(key.toArray(), args.data).toString() === args.hmac.toString(); if (!valid) { const e = new Error('HMAC is not valid'); e.code = 'ERR_INVALID_HMAC'; throw e; } return { valid }; } async createSignature(args) { if ((args.hashToDirectlySign == null) && (args.data == null)) { throw new Error('args.data or args.hashToDirectlySign must be valid'); } const hash = args.hashToDirectlySign ?? index_js_1.Hash.sha256(args.data ?? []); const keyDeriver = this.keyDeriver ?? (() => { throw new Error('keyDeriver is undefined'); })(); const key = keyDeriver.derivePrivateKey(args.protocolID, args.keyID, args.counterparty ?? 'anyone'); return { signature: index_js_1.ECDSA.sign(new index_js_1.BigNumber(hash), key, true).toDER() }; } async verifySignature(args) { if ((args.hashToDirectlyVerify == null) && (args.data == null)) { throw new Error('args.data or args.hashToDirectlyVerify must be valid'); } const hash = args.hashToDirectlyVerify ?? index_js_1.Hash.sha256(args.data ?? []); const keyDeriver = this.keyDeriver ?? (() => { throw new Error('keyDeriver is undefined'); })(); const key = keyDeriver.derivePublicKey(args.protocolID, args.keyID, args.counterparty ?? 'self', args.forSelf); const valid = index_js_1.ECDSA.verify(new index_js_1.BigNumber(hash), index_js_1.Signature.fromDER(args.signature), key); if (!valid) { const e = new Error('Signature is not valid'); e.code = 'ERR_INVALID_SIGNATURE'; throw e; } return { valid }; } } exports.ProtoWallet = ProtoWallet; exports.default = ProtoWallet; //# sourceMappingURL=ProtoWallet.js.map