saepenatus
Version:
Web3-Onboard makes it simple to connect Ethereum hardware and software wallets to your dapp. Features standardised spec compliant web3 providers for all supported wallets, framework agnostic modern javascript UI with code splitting, CSS customization, mul
104 lines (78 loc) • 3.58 kB
text/typescript
;
import { EC } from "./elliptic";
import { arrayify, BytesLike, hexlify, hexZeroPad, Signature, SignatureLike, splitSignature } from "@ethersproject/bytes";
import { defineReadOnly } from "@ethersproject/properties";
import { Logger } from "@ethersproject/logger";
import { version } from "./_version";
const logger = new Logger(version);
let _curve: EC = null
function getCurve() {
if (!_curve) {
_curve = new EC("secp256k1");
}
return _curve;
}
export class SigningKey {
readonly curve: string;
readonly privateKey: string;
readonly publicKey: string;
readonly compressedPublicKey: string;
//readonly address: string;
readonly _isSigningKey: boolean;
constructor(privateKey: BytesLike) {
defineReadOnly(this, "curve", "secp256k1");
defineReadOnly(this, "privateKey", hexlify(privateKey));
const keyPair = getCurve().keyFromPrivate(arrayify(this.privateKey));
defineReadOnly(this, "publicKey", "0x" + keyPair.getPublic(false, "hex"));
defineReadOnly(this, "compressedPublicKey", "0x" + keyPair.getPublic(true, "hex"));
defineReadOnly(this, "_isSigningKey", true);
}
_addPoint(other: BytesLike): string {
const p0 = getCurve().keyFromPublic(arrayify(this.publicKey));
const p1 = getCurve().keyFromPublic(arrayify(other));
return "0x" + p0.pub.add(p1.pub).encodeCompressed("hex");
}
signDigest(digest: BytesLike): Signature {
const keyPair = getCurve().keyFromPrivate(arrayify(this.privateKey));
const digestBytes = arrayify(digest);
if (digestBytes.length !== 32) {
logger.throwArgumentError("bad digest length", "digest", digest);
}
const signature = keyPair.sign(digestBytes, { canonical: true });
return splitSignature({
recoveryParam: signature.recoveryParam,
r: hexZeroPad("0x" + signature.r.toString(16), 32),
s: hexZeroPad("0x" + signature.s.toString(16), 32),
})
}
computeSharedSecret(otherKey: BytesLike): string {
const keyPair = getCurve().keyFromPrivate(arrayify(this.privateKey));
const otherKeyPair = getCurve().keyFromPublic(arrayify(computePublicKey(otherKey)));
return hexZeroPad("0x" + keyPair.derive(otherKeyPair.getPublic()).toString(16), 32);
}
static isSigningKey(value: any): value is SigningKey {
return !!(value && value._isSigningKey);
}
}
export function recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
const sig = splitSignature(signature);
const rs = { r: arrayify(sig.r), s: arrayify(sig.s) };
return "0x" + getCurve().recoverPubKey(arrayify(digest), rs, sig.recoveryParam).encode("hex", false);
}
export function computePublicKey(key: BytesLike, compressed?: boolean): string {
const bytes = arrayify(key);
if (bytes.length === 32) {
const signingKey = new SigningKey(bytes);
if (compressed) {
return "0x" + getCurve().keyFromPrivate(bytes).getPublic(true, "hex");
}
return signingKey.publicKey;
} else if (bytes.length === 33) {
if (compressed) { return hexlify(bytes); }
return "0x" + getCurve().keyFromPublic(bytes).getPublic(false, "hex");
} else if (bytes.length === 65) {
if (!compressed) { return hexlify(bytes); }
return "0x" + getCurve().keyFromPublic(bytes).getPublic(true, "hex");
}
return logger.throwArgumentError("invalid public or private key", "key", "[REDACTED]");
}