@ocap/wallet
Version:
Utility function to create and use an forge compatible crypto wallet
143 lines (141 loc) • 5.09 kB
JavaScript
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 };