Files
rippled/src/js/seed.js
Stefan Thomas 6820c6823d Add transaction signing basics.
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.
2013-02-01 22:44:04 +01:00

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;