@steemit/steem-js
Version:
JavaScript library for the Steem blockchain
159 lines (147 loc) • 4.84 kB
JavaScript
;
var ecurve = require('ecurve');
var Point = ecurve.Point;
var secp256k1 = ecurve.getCurveByName('secp256k1');
var BigInteger = require('bigi');
var base58 = require('bs58');
var assert = require('assert');
var hash = require('./hash');
var PublicKey = require('./key_public');
var G = secp256k1.G;
var n = secp256k1.n;
class PrivateKey {
/**
@private see static functions
@param {BigInteger}
*/
constructor(d) {
this.d = d;
}
static fromBuffer(buf) {
if (!Buffer.isBuffer(buf)) {
throw new Error("Expecting parameter to be a Buffer type");
}
if (32 !== buf.length) {
console.log(`WARN: Expecting 32 bytes, instead got ${buf.length}, stack trace:`, new Error().stack);
}
if (buf.length === 0) {
throw new Error("Empty buffer");
}
return new PrivateKey(BigInteger.fromBuffer(buf));
}
/** @arg {string} seed - any length string. This is private, the same seed produces the same private key every time. */
static fromSeed(seed) {
// generate_private_key
if (!(typeof seed === 'string')) {
throw new Error('seed must be of type string');
}
return PrivateKey.fromBuffer(hash.sha256(seed));
}
static isWif(text) {
try {
this.fromWif(text);
return true;
} catch (e) {
return false;
}
}
/**
@throws {AssertError|Error} parsing key
@return {string} Wallet Import Format (still a secret, Not encrypted)
*/
static fromWif(_private_wif) {
var private_wif = new Buffer.from(base58.decode(_private_wif));
var version = private_wif.readUInt8(0);
assert.equal(0x80, version, `Expected version ${0x80}, instead got ${version}`);
// checksum includes the version
var private_key = private_wif.slice(0, -4);
var checksum = private_wif.slice(-4);
var new_checksum = hash.sha256(private_key);
new_checksum = hash.sha256(new_checksum);
new_checksum = new_checksum.slice(0, 4);
if (checksum.toString() !== new_checksum.toString()) throw new Error('Invalid WIF key (checksum miss-match)');
private_key = private_key.slice(1);
return PrivateKey.fromBuffer(private_key);
}
toWif() {
var private_key = this.toBuffer();
// checksum includes the version
private_key = Buffer.concat([new Buffer.from([0x80]), private_key]);
var checksum = hash.sha256(private_key);
checksum = hash.sha256(checksum);
checksum = checksum.slice(0, 4);
var private_wif = Buffer.concat([private_key, checksum]);
return base58.encode(private_wif);
}
/** Alias for {@link toWif} */
toString() {
return this.toWif();
}
/**
@return {Point}
*/
toPublicKeyPoint() {
var Q;
return Q = secp256k1.G.multiply(this.d);
}
toPublic() {
if (this.public_key) {
return this.public_key;
}
return this.public_key = PublicKey.fromPoint(this.toPublicKeyPoint());
}
toBuffer() {
return this.d.toBuffer(32);
}
/** ECIES */
get_shared_secret(public_key) {
public_key = toPublic(public_key);
let KB = public_key.toUncompressed().toBuffer();
let KBP = Point.fromAffine(secp256k1, BigInteger.fromBuffer(KB.slice(1, 33)),
// x
BigInteger.fromBuffer(KB.slice(33, 65)) // y
);
let r = this.toBuffer();
let P = KBP.multiply(BigInteger.fromBuffer(r));
let S = P.affineX.toBuffer({
size: 32
});
// SHA512 used in ECIES
return hash.sha512(S);
}
// /** ECIES (does not always match the Point.fromAffine version above) */
// get_shared_secret(public_key){
// public_key = toPublic(public_key)
// var P = public_key.Q.multiply( this.d );
// var S = P.affineX.toBuffer({size: 32});
// // ECIES, adds an extra sha512
// return hash.sha512(S);
// }
/** @throws {Error} - overflow of the key could not be derived */
child(offset) {
offset = Buffer.concat([this.toPublicKey().toBuffer(), offset]);
offset = hash.sha256(offset);
let c = BigInteger.fromBuffer(offset);
if (c.compareTo(n) >= 0) throw new Error("Child offset went out of bounds, try again");
let derived = this.d.add(c); //.mod(n)
if (derived.signum() === 0) throw new Error("Child offset derived to an invalid key, try again");
return new PrivateKey(derived);
}
// toByteBuffer() {
// var b = new ByteBuffer(ByteBuffer.DEFAULT_CAPACITY, ByteBuffer.LITTLE_ENDIAN);
// this.appendByteBuffer(b);
// return b.copy(0, b.offset);
// }
static fromHex(hex) {
return PrivateKey.fromBuffer(new Buffer.from(hex, 'hex'));
}
toHex() {
return this.toBuffer().toString('hex');
}
toPublicKey() {
return this.toPublic();
}
/* </helper_functions> */
}
module.exports = PrivateKey;
const toPublic = data => data == null ? data : data.Q ? data : PublicKey.fromStringOrThrow(data);