UNPKG

@ocap/wallet

Version:

Utility function to create and use an forge compatible crypto wallet

143 lines (141 loc) 5.09 kB
import { DidType, fromPublicKey as fromPublicKey$1, toAddress, toTypeInfo } from "@arcblock/did"; import * as JWT from "@arcblock/jwt"; import { getHasher, getSigner } from "@ocap/mcrypto"; import { toHex } from "@ocap/util"; //#region src/index.ts const WalletType = DidType; /** * Generate an wallet instance that can be used to sign a message or verify a signature */ function Wallet(keyPair, t = "default") { const type = DidType(t); const signer = getSigner(type.pk); const hasher = getHasher(type.hash); return { type, secretKey: keyPair.sk, publicKey: keyPair.pk, address: keyPair.pk ? fromPublicKey$1(keyPair.pk, type) : keyPair.address, hash(data, round = 1, encoding = "hex") { return hasher(data, round, encoding); }, async sign(data, hashBeforeSign = true, encoding = "hex") { if (!keyPair.sk) throw new Error("Cannot sign data without a secretKey"); if (hashBeforeSign) { const hash = hasher(data, 1); return signer.sign(hash, keyPair.sk, encoding); } return signer.sign(data, keyPair.sk, encoding); }, async verify(data, signature, hashBeforeVerify = true, extra) { if (!keyPair.pk) throw new Error("Cannot verify data without a publicKey"); const hash = hashBeforeVerify ? hasher(data, 1) : data; return signer.verify(hash, signature, keyPair.pk, extra); }, ethHash(data) { if (typeof signer.ethHash !== "function") throw new Error("ethHash is not supported by signer"); return signer.ethHash(data); }, async signETH(data, hashBeforeSign = true) { if (!keyPair.sk) throw new Error("Cannot sign data without a secretKey"); if (typeof signer.ethHash !== "function" || typeof signer.ethSign !== "function") throw new Error("ethSign is not supported by signer"); if (hashBeforeSign) return signer.ethSign(signer.ethHash(data), toHex(keyPair.sk)); return signer.ethSign(data, toHex(keyPair.sk)); }, ethSign(data, hashBeforeSign = true) { return this.signETH(data, hashBeforeSign); }, async ethVerify(data, signature, hashBeforeVerify = true) { if (typeof signer.ethHash !== "function" || typeof signer.ethRecover !== "function") throw new Error("ethVerify is not supported by signer"); const hash = hashBeforeVerify ? signer.ethHash(data) : data; return signer.ethRecover(hash, signature) === this.address; }, async signJWT(payload = {}, doSign = true, version = "1.0.0") { if (!keyPair.sk) throw new Error("Cannot sign JWT without a secretKey"); return JWT.sign(this.address, keyPair.sk, payload, doSign, version); }, toAddress() { return keyPair.pk ? fromPublicKey$1(keyPair.pk, type) : keyPair.address; }, toJSON() { return { type: DidType.toJSON(type), sk: keyPair.sk ? toHex(keyPair.sk) : "", pk: keyPair.pk ? toHex(keyPair.pk) : "", address: this.address }; } }; } /** * Generate a wallet from secretKey * * @example * const assert = require('assert'); * const { fromSecretKey } = require('@ocap/wallet'); * * const sk = * '0xD67C071B6F51D2B61180B9B1AA9BE0DD0704619F0E30453AB4A592B036EDE644E4852B7091317E3622068E62A5127D1FB0D4AE2FC50213295E10652D2F0ABFC7'; * const sig = * '0x08a102851c38c072e42756c1cc70938b5499c8e9358dfe5f383823f56cdb282ffda60fcd581a02c6c673069e5afc0bf09abbe3639b61b84d64fd58ef9f083003'; * * const wallet = fromSecretKey(sk, type); * const message = 'data to sign'; * const signature = wallet.sign(message); * assert.equal(signature, sig, "signature should match"); * assert.ok(wallet.verify(message, signature), "signature should be verified"); */ function fromSecretKey(sk, _type = "default") { const type = DidType(_type); return Wallet({ sk, pk: getSigner(type.pk).getPublicKey(sk) }, type); } /** * Generate a wallet from publicKey */ function fromPublicKey(pk, _type = "default") { return Wallet({ pk }, DidType(_type)); } /** * Generate a wallet from address (did) * * Since we do not know the publicKey and secretKey, this kind of wallet cannot be used for signing and verifying */ function fromAddress(address) { return Wallet({ address: toAddress(address) }, toTypeInfo(address)); } /** * Generate a wallet by generating a random secretKey */ function fromRandom(_type = "default") { const type = DidType(_type); const keyPair = getSigner(type.pk).genKeyPair(); return Wallet({ sk: keyPair.secretKey, pk: keyPair.publicKey }, type); } /** * Generating a wallet from a serialized json presentation of another wallet */ function fromJSON(json) { return Wallet(json, DidType.fromJSON(json.type)); } /** * Check if an object is valid wallet object */ function isValid(wallet, canSign = true) { if (!wallet || typeof wallet !== "object") return false; if (typeof wallet.verify !== "function") return false; if (typeof wallet.toAddress !== "function") return false; if (typeof wallet.toJSON !== "function") return false; if (!wallet.type || !wallet.publicKey) return false; if (canSign) { if (typeof wallet.sign !== "function") return false; } return true; } //#endregion export { Wallet, WalletType, fromAddress, fromJSON, fromPublicKey, fromRandom, fromSecretKey, isValid };