@okxweb3/crypto-lib
Version:
A base package for @okxweb3/coin-*
300 lines • 11.2 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fromSeed = exports.fromPublicKey = exports.fromPrivateKey = exports.fromBase58 = exports.tinySecp256k1Interface = void 0;
const base = __importStar(require("../base"));
const base_1 = require("@scure/base");
const hash_1 = require("../base/hash");
const bytesCoder = (0, base_1.base58check)(hash_1.sha256);
const api = require('./api');
const typeforce = require('typeforce');
const wif = require('wif');
function createApi(secp256k1) {
return {
isPoint: (p) => secp256k1.publicKeyVerify(p),
isPrivate: (d) => secp256k1.privateKeyVerify(d),
pointAddScalar: (p, tweak, compress) => secp256k1.publicKeyTweakAdd(p, tweak, compress),
pointFromScalar: (d, compress) => secp256k1.publicKeyCreate(d, compress),
privateAdd: (d, tweak) => secp256k1.privateKeyTweakAdd(new Uint8Array(d), tweak),
sign: (h, d) => secp256k1.ecdsaSign(h, d),
verify: (h, Q, signature) => secp256k1.ecdsaVerify(signature, h, Q),
};
}
function createTinySecp256k1Interface(secp256k1) {
return {
isPoint: (p) => secp256k1.publicKeyVerify(p),
pointCompress: (p, compressed) => Uint8Array.from(secp256k1.publicKeyConvert(p, compressed != null ? compressed : true)),
isPrivate: (d) => secp256k1.privateKeyVerify(d),
pointFromScalar: (d, compressed) => {
const r = secp256k1.publicKeyCreate(d, compressed != null ? compressed : true);
if (r == null) {
return null;
}
return Uint8Array.from(r);
},
sign: (h, d, e) => Uint8Array.from(secp256k1.ecdsaSign(h, d)),
verify: (h, Q, signature, strict) => secp256k1.ecdsaVerify(signature, h, Q),
};
}
const ecc = createApi(api);
exports.tinySecp256k1Interface = createTinySecp256k1Interface(api);
const UINT256_TYPE = typeforce.BufferN(32);
const NETWORK_TYPE = typeforce.compile({
wif: typeforce.UInt8,
bip32: {
public: typeforce.UInt32,
private: typeforce.UInt32,
},
});
const BITCOIN = {
messagePrefix: '\x18Bitcoin Signed Message:\n',
bech32: 'bc',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4,
},
pubKeyHash: 0x00,
scriptHash: 0x05,
wif: 0x80,
};
const HIGHEST_BIT = 0x80000000;
const UINT31_MAX = Math.pow(2, 31) - 1;
function BIP32Path(value) {
return (typeforce.String(value) && value.match(/^(m\/)?(\d+'?\/)*\d+'?$/) !== null);
}
function UInt31(value) {
return typeforce.UInt32(value) && value <= UINT31_MAX;
}
class BIP32 {
constructor(__D, __Q, chainCode, network, __DEPTH = 0, __INDEX = 0, __PARENT_FINGERPRINT = 0x00000000) {
this.__D = __D;
this.__Q = __Q;
this.chainCode = chainCode;
this.network = network;
this.__DEPTH = __DEPTH;
this.__INDEX = __INDEX;
this.__PARENT_FINGERPRINT = __PARENT_FINGERPRINT;
typeforce(NETWORK_TYPE, network);
this.lowR = false;
}
get depth() {
return this.__DEPTH;
}
get index() {
return this.__INDEX;
}
get parentFingerprint() {
return this.__PARENT_FINGERPRINT;
}
get publicKey() {
if (this.__Q === undefined)
this.__Q = Buffer.from(ecc.pointFromScalar(this.__D, true));
return this.__Q;
}
get privateKey() {
return this.__D;
}
get identifier() {
return Buffer.from(base.hash160(this.publicKey));
}
get fingerprint() {
return this.identifier.slice(0, 4);
}
get compressed() {
return true;
}
isNeutered() {
return this.__D === undefined;
}
neutered() {
return fromPublicKeyLocal(this.publicKey, this.chainCode, this.network, this.depth, this.index, this.parentFingerprint);
}
toBase58() {
const network = this.network;
const version = !this.isNeutered()
? network.bip32.private
: network.bip32.public;
const buffer = Buffer.allocUnsafe(78);
buffer.writeUInt32BE(version, 0);
buffer.writeUInt8(this.depth, 4);
buffer.writeUInt32BE(this.parentFingerprint, 5);
buffer.writeUInt32BE(this.index, 9);
this.chainCode.copy(buffer, 13);
if (!this.isNeutered()) {
buffer.writeUInt8(0, 45);
this.privateKey.copy(buffer, 46);
}
else {
this.publicKey.copy(buffer, 45);
}
return bytesCoder.encode(buffer);
}
toWIF() {
if (!this.privateKey)
throw new TypeError('Missing private key');
return wif.encode(this.network.wif, this.privateKey, true);
}
derive(index) {
typeforce(typeforce.UInt32, index);
const isHardened = index >= HIGHEST_BIT;
const data = Buffer.allocUnsafe(37);
if (isHardened) {
if (this.isNeutered())
throw new TypeError('Missing private key for hardened child key');
data[0] = 0x00;
this.privateKey.copy(data, 1);
data.writeUInt32BE(index, 33);
}
else {
this.publicKey.copy(data, 0);
data.writeUInt32BE(index, 33);
}
const I = base.hmacSHA512(this.chainCode, data);
const IL = I.slice(0, 32);
const IR = I.slice(32);
if (!ecc.isPrivate(IL))
return this.derive(index + 1);
let hd;
if (!this.isNeutered()) {
const ki = ecc.privateAdd(this.privateKey, IL);
if (ki == null)
return this.derive(index + 1);
hd = fromPrivateKeyLocal(ki, IR, this.network, this.depth + 1, index, this.fingerprint.readUInt32BE(0));
}
else {
const Ki = ecc.pointAddScalar(this.publicKey, IL, true);
if (Ki === null)
return this.derive(index + 1);
hd = fromPublicKeyLocal(Ki, IR, this.network, this.depth + 1, index, this.fingerprint.readUInt32BE(0));
}
return hd;
}
deriveHardened(index) {
typeforce(UInt31, index);
return this.derive(index + HIGHEST_BIT);
}
derivePath(path) {
typeforce(BIP32Path, path);
let splitPath = path.split('/');
if (splitPath[0] === 'm') {
if (this.parentFingerprint)
throw new TypeError('Expected master, got child');
splitPath = splitPath.slice(1);
}
return splitPath.reduce((prevHd, indexStr) => {
let index;
if (indexStr.slice(-1) === `'`) {
index = parseInt(indexStr.slice(0, -1), 10);
return prevHd.deriveHardened(index);
}
else {
index = parseInt(indexStr, 10);
return prevHd.derive(index);
}
}, this);
}
sign(hash) {
if (!this.privateKey)
throw new Error('Missing private key');
return ecc.sign(hash, this.privateKey);
}
verify(hash, signature) {
return ecc.verify(hash, this.publicKey, signature);
}
}
function fromBase58(inString, network) {
const buffer = Buffer.from(bytesCoder.decode(inString));
if (buffer.length !== 78)
throw new TypeError('Invalid buffer length');
network = network || BITCOIN;
const version = buffer.readUInt32BE(0);
if (version !== network.bip32.private && version !== network.bip32.public)
throw new TypeError('Invalid network version');
const depth = buffer[4];
const parentFingerprint = buffer.readUInt32BE(5);
if (depth === 0) {
if (parentFingerprint !== 0x00000000)
throw new TypeError('Invalid parent fingerprint');
}
const index = buffer.readUInt32BE(9);
if (depth === 0 && index !== 0)
throw new TypeError('Invalid index');
const chainCode = buffer.slice(13, 45);
let hd;
if (version === network.bip32.private) {
if (buffer.readUInt8(45) !== 0x00)
throw new TypeError('Invalid private key');
const k = buffer.slice(46, 78);
hd = fromPrivateKeyLocal(k, chainCode, network, depth, index, parentFingerprint);
}
else {
const X = buffer.slice(45, 78);
hd = fromPublicKeyLocal(X, chainCode, network, depth, index, parentFingerprint);
}
return hd;
}
exports.fromBase58 = fromBase58;
function fromPrivateKey(privateKey, chainCode, network) {
return fromPrivateKeyLocal(privateKey, chainCode, network);
}
exports.fromPrivateKey = fromPrivateKey;
function fromPrivateKeyLocal(privateKey, chainCode, network, depth, index, parentFingerprint) {
typeforce({
privateKey: UINT256_TYPE,
chainCode: UINT256_TYPE,
}, { privateKey, chainCode });
network = network || BITCOIN;
if (!ecc.isPrivate(privateKey))
throw new TypeError('Private key not in range [1, n)');
return new BIP32(privateKey, undefined, chainCode, network, depth, index, parentFingerprint);
}
function fromPublicKey(publicKey, chainCode, network) {
return fromPublicKeyLocal(publicKey, chainCode, network);
}
exports.fromPublicKey = fromPublicKey;
function fromPublicKeyLocal(publicKey, chainCode, network, depth, index, parentFingerprint) {
typeforce({
publicKey: typeforce.BufferN(33),
chainCode: UINT256_TYPE,
}, { publicKey, chainCode });
network = network || BITCOIN;
if (!ecc.isPoint(publicKey))
throw new TypeError('Point is not on the curve');
return new BIP32(undefined, publicKey, chainCode, network, depth, index, parentFingerprint);
}
function fromSeed(seed, network) {
typeforce(typeforce.Buffer, seed);
if (seed.length < 16)
throw new TypeError('Seed should be at least 128 bits');
if (seed.length > 64)
throw new TypeError('Seed should be at most 512 bits');
network = network || BITCOIN;
const I = base.hmacSHA512(Buffer.from('Bitcoin seed', 'utf8'), seed);
const IL = I.slice(0, 32);
const IR = I.slice(32);
return fromPrivateKey(IL, IR, network);
}
exports.fromSeed = fromSeed;
//# sourceMappingURL=bip32.js.map