mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-11-21 04:35:49 +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-extramath.js",
|
||||||
"src/js/sjcl-custom/sjcl-montgomery.js",
|
"src/js/sjcl-custom/sjcl-montgomery.js",
|
||||||
"src/js/sjcl-custom/sjcl-validecc.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-ecdsa-der.js",
|
||||||
"src/js/sjcl-custom/sjcl-jacobi.js"
|
"src/js/sjcl-custom/sjcl-jacobi.js"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -89,8 +89,10 @@ KeyPair.prototype.get_address = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
KeyPair.prototype.sign = function (hash) {
|
KeyPair.prototype.sign = function (hash) {
|
||||||
var hash = UInt256.from_json(hash);
|
hash = UInt256.from_json(hash);
|
||||||
return this._secret.signDER(hash.to_bits(), 0);
|
var sig = this._secret.sign(hash.to_bits(), 0);
|
||||||
|
sig = this._secret.canonicalizeSignature(sig);
|
||||||
|
return this._secret.encodeDER(sig);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.KeyPair = KeyPair;
|
exports.KeyPair = KeyPair;
|
||||||
|
|||||||
@@ -120,6 +120,8 @@ SerializedType.prototype.parse_varint = function (so) {
|
|||||||
* The result is appended to the serialized object ('so').
|
* The result is appended to the serialized object ('so').
|
||||||
*/
|
*/
|
||||||
function append_byte_array(so, val, bytes) {
|
function append_byte_array(so, val, bytes) {
|
||||||
|
val = val >>> 0;
|
||||||
|
|
||||||
if (!isNumber(val)) {
|
if (!isNumber(val)) {
|
||||||
throw new Error('Value is not a number');
|
throw new Error('Value is not a number');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,9 @@ function Transaction(remote) {
|
|||||||
this.remote = remote;
|
this.remote = remote;
|
||||||
|
|
||||||
// Transaction data
|
// Transaction data
|
||||||
this.tx_json = { Flags: 0 };
|
this.tx_json = {
|
||||||
|
Flags: Transaction.defaultFlags
|
||||||
|
};
|
||||||
|
|
||||||
this._secret = void(0);
|
this._secret = void(0);
|
||||||
this._build_path = false;
|
this._build_path = false;
|
||||||
@@ -80,15 +82,10 @@ function Transaction(remote) {
|
|||||||
this.submittedIDs = [ ]
|
this.submittedIDs = [ ]
|
||||||
|
|
||||||
function finalize(message) {
|
function finalize(message) {
|
||||||
if (self.result) {
|
if (!self.finalized) {
|
||||||
self.result.ledger_index = message.ledger_index;
|
self.finalized = true;
|
||||||
self.result.ledger_hash = message.ledger_hash;
|
self.emit('cleanup', message);
|
||||||
} else {
|
|
||||||
self.result = message;
|
|
||||||
self.result.tx_json = self.tx_json;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.emit('cleanup', message);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.once('success', function(message) {
|
this.once('success', function(message) {
|
||||||
@@ -120,6 +117,11 @@ Transaction.fee_units = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Transaction.flags = {
|
Transaction.flags = {
|
||||||
|
// Universal flags can apply to any transaction type
|
||||||
|
Universal: {
|
||||||
|
FullyCanonicalSig: 0x80000000
|
||||||
|
},
|
||||||
|
|
||||||
AccountSet: {
|
AccountSet: {
|
||||||
RequireDestTag: 0x00010000,
|
RequireDestTag: 0x00010000,
|
||||||
OptionalDestTag: 0x00020000,
|
OptionalDestTag: 0x00020000,
|
||||||
@@ -149,6 +151,8 @@ Transaction.flags = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Transaction.defaultFlags = 0 | Transaction.flags.Universal.FullyCanonicalSig;
|
||||||
|
|
||||||
Transaction.formats = require('./binformat').tx;
|
Transaction.formats = require('./binformat').tx;
|
||||||
|
|
||||||
Transaction.prototype.consts = {
|
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