mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-20 12:15:51 +00:00
[CHORE] Enable signature canonicalization.
This commit is contained in:
@@ -41,6 +41,7 @@ module.exports = function(grunt) {
|
||||
"src/js/sjcl-custom/sjcl-extramath.js",
|
||||
"src/js/sjcl-custom/sjcl-montgomery.js",
|
||||
"src/js/sjcl-custom/sjcl-validecc.js",
|
||||
"src/js/sjcl-custom/sjcl-ecdsa-canonical.js",
|
||||
"src/js/sjcl-custom/sjcl-ecdsa-der.js",
|
||||
"src/js/sjcl-custom/sjcl-jacobi.js"
|
||||
],
|
||||
|
||||
@@ -89,8 +89,10 @@ KeyPair.prototype.get_address = function () {
|
||||
};
|
||||
|
||||
KeyPair.prototype.sign = function (hash) {
|
||||
var hash = UInt256.from_json(hash);
|
||||
return this._secret.signDER(hash.to_bits(), 0);
|
||||
hash = UInt256.from_json(hash);
|
||||
var sig = this._secret.sign(hash.to_bits(), 0);
|
||||
sig = this._secret.canonicalizeSignature(sig);
|
||||
return this._secret.encodeDER(sig);
|
||||
};
|
||||
|
||||
exports.KeyPair = KeyPair;
|
||||
|
||||
@@ -120,6 +120,8 @@ SerializedType.prototype.parse_varint = function (so) {
|
||||
* The result is appended to the serialized object ('so').
|
||||
*/
|
||||
function append_byte_array(so, val, bytes) {
|
||||
val = val >>> 0;
|
||||
|
||||
if (!isNumber(val)) {
|
||||
throw new Error('Value is not a number');
|
||||
}
|
||||
|
||||
@@ -62,7 +62,9 @@ function Transaction(remote) {
|
||||
this.remote = remote;
|
||||
|
||||
// Transaction data
|
||||
this.tx_json = { Flags: 0 };
|
||||
this.tx_json = {
|
||||
Flags: Transaction.defaultFlags
|
||||
};
|
||||
|
||||
this._secret = void(0);
|
||||
this._build_path = false;
|
||||
@@ -80,15 +82,10 @@ function Transaction(remote) {
|
||||
this.submittedIDs = [ ]
|
||||
|
||||
function finalize(message) {
|
||||
if (self.result) {
|
||||
self.result.ledger_index = message.ledger_index;
|
||||
self.result.ledger_hash = message.ledger_hash;
|
||||
} else {
|
||||
self.result = message;
|
||||
self.result.tx_json = self.tx_json;
|
||||
if (!self.finalized) {
|
||||
self.finalized = true;
|
||||
self.emit('cleanup', message);
|
||||
}
|
||||
|
||||
self.emit('cleanup', message);
|
||||
};
|
||||
|
||||
this.once('success', function(message) {
|
||||
@@ -120,6 +117,11 @@ Transaction.fee_units = {
|
||||
};
|
||||
|
||||
Transaction.flags = {
|
||||
// Universal flags can apply to any transaction type
|
||||
Universal: {
|
||||
FullyCanonicalSig: 0x80000000
|
||||
},
|
||||
|
||||
AccountSet: {
|
||||
RequireDestTag: 0x00010000,
|
||||
OptionalDestTag: 0x00020000,
|
||||
@@ -149,6 +151,8 @@ Transaction.flags = {
|
||||
}
|
||||
};
|
||||
|
||||
Transaction.defaultFlags = 0 | Transaction.flags.Universal.FullyCanonicalSig;
|
||||
|
||||
Transaction.formats = require('./binformat').tx;
|
||||
|
||||
Transaction.prototype.consts = {
|
||||
|
||||
17
src/js/sjcl-custom/sjcl-ecdsa-canonical.js
Normal file
17
src/js/sjcl-custom/sjcl-ecdsa-canonical.js
Normal file
@@ -0,0 +1,17 @@
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.canonicalizeSignature = function(rs) {
|
||||
var w = sjcl.bitArray,
|
||||
R = this._curve.r,
|
||||
l = R.bitLength();
|
||||
|
||||
var r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
|
||||
s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l));
|
||||
|
||||
// For a canonical signature we want the lower of two possible values for s
|
||||
// 0 < s <= n/2
|
||||
if (!R.copy().halveM().greaterEquals(s)) {
|
||||
s = R.sub(s);
|
||||
}
|
||||
|
||||
return w.concat(r.toBits(l), s.toBits(l));
|
||||
};
|
||||
|
||||
28
test/sjcl-ecdsa-canonical-test.js
Normal file
28
test/sjcl-ecdsa-canonical-test.js
Normal file
@@ -0,0 +1,28 @@
|
||||
var assert = require('assert');
|
||||
var utils = require('./testutils');
|
||||
var sjcl = require('../build/sjcl');
|
||||
var Seed = require('../src/js/ripple/seed').Seed;
|
||||
|
||||
describe('SJCL ECDSA Canonicalization', function() {
|
||||
describe('canonicalizeSignature', function() {
|
||||
it('should canonicalize non-canonical signatures', function () {
|
||||
var seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
|
||||
var key = seed.get_key('rBZ4j6MsoctipM6GEyHSjQKzXG3yambDnZ');
|
||||
|
||||
var rs = sjcl.codec.hex.toBits("27ce1b914045ba7e8c11a2f2882cb6e07a19d4017513f12e3e363d71dc3fff0fb0a0747ecc7b4ca46e45b3b32b6b2a066aa0249c027ef11e5bce93dab756549c");
|
||||
rs = sjcl.ecc.ecdsa.secretKey.prototype.canonicalizeSignature.call(key._secret, rs);
|
||||
assert.strictEqual(sjcl.codec.hex.fromBits(rs), "27ce1b914045ba7e8c11a2f2882cb6e07a19d4017513f12e3e363d71dc3fff0f4f5f8b813384b35b91ba4c4cd494d5f8500eb84aacc9af1d6403cab218dfeca5");
|
||||
});
|
||||
|
||||
it('should not touch canonical signatures', function () {
|
||||
var seed = Seed.from_json('saESc82Vun7Ta5EJRzGJbrXb5HNYk');
|
||||
var key = seed.get_key('rBZ4j6MsoctipM6GEyHSjQKzXG3yambDnZ');
|
||||
|
||||
var rs = sjcl.codec.hex.toBits("5c32bc2b4d34e27af9fb66eeea0f47f6afb3d433658af0f649ebae7b872471ab7d23860688aaf9d8131f84cfffa6c56bf9c32fd8b315b2ef9d6bcb243f7a686c");
|
||||
rs = sjcl.ecc.ecdsa.secretKey.prototype.canonicalizeSignature.call(key._secret, rs);
|
||||
assert.strictEqual(sjcl.codec.hex.fromBits(rs), "5c32bc2b4d34e27af9fb66eeea0f47f6afb3d433658af0f649ebae7b872471ab7d23860688aaf9d8131f84cfffa6c56bf9c32fd8b315b2ef9d6bcb243f7a686c");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// vim:sw=2:sts=2:ts=8:et
|
||||
Reference in New Issue
Block a user