mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Most fields aren't supported yet and there aren't any nice external APIs, but my test script successfully serializes and signs an XRP Payment, so this seems like a good time to make a commit.
130 lines
3.0 KiB
JavaScript
130 lines
3.0 KiB
JavaScript
//
|
|
// Seed support
|
|
//
|
|
|
|
var sjcl = require('../../build/sjcl');
|
|
var utils = require('./utils');
|
|
var jsbn = require('./jsbn');
|
|
|
|
var BigInteger = jsbn.BigInteger;
|
|
|
|
var Base = require('./base').Base,
|
|
UInt256 = require('./uint256').UInt256;
|
|
|
|
var Seed = function () {
|
|
// Internal form: NaN or BigInteger
|
|
this._value = NaN;
|
|
};
|
|
|
|
Seed.json_rewrite = function (j) {
|
|
return Seed.from_json(j).to_json();
|
|
};
|
|
|
|
// Return a new Seed from j.
|
|
Seed.from_json = function (j) {
|
|
return (j instanceof Seed)
|
|
? j.clone()
|
|
: (new Seed()).parse_json(j);
|
|
};
|
|
|
|
Seed.is_valid = function (j) {
|
|
return Seed.from_json(j).is_valid();
|
|
};
|
|
|
|
Seed.prototype.clone = function () {
|
|
return this.copyTo(new Seed());
|
|
};
|
|
|
|
// Returns copy.
|
|
Seed.prototype.copyTo = function (d) {
|
|
d._value = this._value;
|
|
|
|
return d;
|
|
};
|
|
|
|
Seed.prototype.equals = function (d) {
|
|
return this._value instanceof BigInteger && d._value instanceof BigInteger && this._value.equals(d._value);
|
|
};
|
|
|
|
Seed.prototype.is_valid = function () {
|
|
return this._value instanceof BigInteger;
|
|
};
|
|
|
|
// value = NaN on error.
|
|
// One day this will support rfc1751 too.
|
|
Seed.prototype.parse_json = function (j) {
|
|
if ('string' !== typeof j) {
|
|
this._value = NaN;
|
|
}
|
|
else if (j[0] === "s") {
|
|
this._value = Base.decode_check(Base.VER_FAMILY_SEED, j);
|
|
}
|
|
else if (16 === j.length) {
|
|
this._value = new BigInteger(utils.stringToArray(j), 128);
|
|
}
|
|
else {
|
|
this._value = NaN;
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
// Convert from internal form.
|
|
Seed.prototype.to_json = function () {
|
|
if (!(this._value instanceof BigInteger))
|
|
return NaN;
|
|
|
|
var bytes = this._value.toByteArray().map(function (b) { return b ? b < 0 ? 256+b : b : 0; });
|
|
var target = 20;
|
|
|
|
// XXX Make sure only trim off leading zeros.
|
|
var array = bytes.length < target
|
|
? bytes.length
|
|
? [].concat(utils.arraySet(target - bytes.length, 0), bytes)
|
|
: utils.arraySet(target, 0)
|
|
: bytes.slice(target - bytes.length);
|
|
var output = Base.encode_check(Base.VER_FAMILY_SEED, array);
|
|
|
|
return output;
|
|
};
|
|
|
|
function append_int(a, i) {
|
|
return [].concat(a, i >> 24, (i >> 16) & 0xff, (i >> 8) & 0xff, i & 0xff);
|
|
}
|
|
|
|
function firstHalfOfSHA512(bytes) {
|
|
return sjcl.bitArray.bitSlice(
|
|
sjcl.hash.sha512.hash(sjcl.codec.bytes.toBits(bytes)),
|
|
0, 256
|
|
);
|
|
}
|
|
|
|
function SHA256_RIPEMD160(bits) {
|
|
return sjcl.hash.ripemd160.hash(sjcl.hash.sha256.hash(bits));
|
|
}
|
|
|
|
Seed.prototype.generate_private = function (account_id) {
|
|
// XXX If account_id is given, should loop over keys until we find the right one
|
|
|
|
var seq = 0;
|
|
|
|
var private_gen, public_gen, i = 0;
|
|
do {
|
|
private_gen = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(this.seed, i)));
|
|
i++;
|
|
} while (!sjcl.ecc.curves.c256.r.greaterEquals(private_gen));
|
|
|
|
public_gen = sjcl.ecc.curves.c256.G.mult(private_gen);
|
|
|
|
var sec;
|
|
i = 0;
|
|
do {
|
|
sec = sjcl.bn.fromBits(firstHalfOfSHA512(append_int(append_int(public_gen.toBytesCompressed(), seq), i)));
|
|
i++;
|
|
} while (!sjcl.ecc.curves.c256.r.greaterEquals(sec));
|
|
|
|
return UInt256.from_bn(sec);
|
|
};
|
|
|
|
exports.Seed = Seed;
|