bitcoinjs-lib/ts_src/ecpair.ts

133 lines
3.5 KiB
TypeScript
Raw Normal View History

2019-03-03 23:07:49 +09:00
import { Network } from './networks';
import * as NETWORKS from './networks';
import * as types from './types';
const ecc = require('tiny-secp256k1');
const randomBytes = require('randombytes');
const typeforce = require('typeforce');
const wif = require('wif');
const isOptions = typeforce.maybe(
typeforce.compile({
compressed: types.maybe(types.Boolean),
network: types.maybe(types.Network),
}),
);
2015-08-19 15:12:55 +10:00
2018-12-28 11:56:03 +09:00
interface ECPairOptions {
2019-03-03 23:07:49 +09:00
compressed?: boolean;
network?: Network;
rng?(arg0: Buffer): Buffer;
}
2015-08-11 17:01:47 +10:00
2018-12-28 11:56:03 +09:00
export interface ECPairInterface {
2019-03-03 23:07:49 +09:00
compressed: boolean;
network: Network;
privateKey?: Buffer;
publicKey?: Buffer;
toWIF(): string;
sign(hash: Buffer): Buffer;
verify(hash: Buffer, signature: Buffer): Buffer;
getPublicKey?(): Buffer;
2018-12-28 11:56:03 +09:00
}
class ECPair implements ECPairInterface {
2019-03-03 23:07:49 +09:00
compressed: boolean;
network: Network;
2019-03-07 12:06:12 +09:00
private __D?: Buffer;
2019-03-03 23:07:49 +09:00
private __Q?: Buffer;
constructor(d?: Buffer, Q?: Buffer, options?: ECPairOptions) {
if (options === undefined) options = {};
this.compressed =
options.compressed === undefined ? true : options.compressed;
this.network = options.network || NETWORKS.bitcoin;
2019-03-07 12:06:12 +09:00
this.__D = undefined;
2019-03-03 23:07:49 +09:00
this.__Q = undefined;
2019-03-07 12:06:12 +09:00
if (d !== undefined) this.__D = d;
2019-03-03 23:07:49 +09:00
if (Q !== undefined) this.__Q = ecc.pointCompress(Q, this.compressed);
2018-12-28 10:35:28 +09:00
}
2014-10-17 13:31:01 +11:00
2019-03-03 23:07:49 +09:00
get privateKey(): Buffer | undefined {
2019-03-07 12:06:12 +09:00
return this.__D;
2018-12-28 10:35:28 +09:00
}
2015-03-19 13:25:41 +11:00
2019-03-03 23:07:49 +09:00
get publicKey(): Buffer | undefined {
2019-03-07 12:06:12 +09:00
if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed);
2019-03-03 23:07:49 +09:00
return this.__Q;
2018-12-28 10:35:28 +09:00
}
2015-03-19 13:25:41 +11:00
2019-03-03 23:07:49 +09:00
toWIF(): string {
2019-03-07 12:06:12 +09:00
if (!this.__D) throw new Error('Missing private key');
return wif.encode(this.network.wif, this.__D, this.compressed);
2018-12-28 10:35:28 +09:00
}
2014-10-17 13:31:01 +11:00
2019-03-03 23:07:49 +09:00
sign(hash: Buffer): Buffer {
2019-03-07 12:06:12 +09:00
if (!this.__D) throw new Error('Missing private key');
return ecc.sign(hash, this.__D);
2018-12-28 10:35:28 +09:00
}
2019-03-03 23:07:49 +09:00
verify(hash: Buffer, signature: Buffer): Buffer {
return ecc.verify(hash, this.publicKey, signature);
2018-12-28 10:35:28 +09:00
}
2014-10-17 13:31:01 +11:00
}
2019-03-03 23:07:49 +09:00
function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair {
typeforce(types.Buffer256bit, buffer);
if (!ecc.isPrivate(buffer))
throw new TypeError('Private key not in range [1, n)');
typeforce(isOptions, options);
2019-03-07 12:06:12 +09:00
return new ECPair(buffer, undefined, options as ECPairOptions);
}
2019-03-03 23:07:49 +09:00
function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair {
typeforce(ecc.isPoint, buffer);
typeforce(isOptions, options);
2019-03-07 12:06:12 +09:00
return new ECPair(undefined, buffer, options as ECPairOptions);
}
2019-03-07 12:06:12 +09:00
function fromWIF(wifString: string, network?: Network | Network[]): ECPair {
const decoded = wif.decode(wifString);
2019-03-03 23:07:49 +09:00
const version = decoded.version;
2014-10-17 13:31:01 +11:00
// list of networks?
if (types.Array(network)) {
2019-03-07 12:06:12 +09:00
network = (network as Network[])
.filter((x: Network) => {
2019-03-03 23:07:49 +09:00
return version === x.wif;
})
2019-03-07 12:06:12 +09:00
.pop() as Network;
2019-03-03 23:07:49 +09:00
if (!network) throw new Error('Unknown network version');
2019-03-03 23:07:49 +09:00
// otherwise, assume a network object (or default to bitcoin)
} else {
2019-03-03 23:07:49 +09:00
network = network || NETWORKS.bitcoin;
2019-03-07 12:06:12 +09:00
if (version !== (network as Network).wif)
2019-03-03 23:07:49 +09:00
throw new Error('Invalid network version');
2015-07-28 16:42:57 +10:00
}
return fromPrivateKey(decoded.privateKey, {
compressed: decoded.compressed,
2019-03-07 12:06:12 +09:00
network: network as Network,
2019-03-03 23:07:49 +09:00
});
2014-10-17 13:31:01 +11:00
}
2019-03-03 23:07:49 +09:00
function makeRandom(options?: ECPairOptions): ECPair {
typeforce(isOptions, options);
if (options === undefined) options = {};
const rng = options.rng || randomBytes;
2014-10-17 13:31:01 +11:00
2019-03-03 23:07:49 +09:00
let d;
2015-08-21 16:46:18 +10:00
do {
2019-03-03 23:07:49 +09:00
d = rng(32);
typeforce(types.Buffer256bit, d);
} while (!ecc.isPrivate(d));
2014-10-17 13:31:01 +11:00
2019-03-03 23:07:49 +09:00
return fromPrivateKey(d, options);
2015-09-21 17:37:21 +10:00
}
2019-03-03 23:07:49 +09:00
export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF };