[CHORE] Enable signature canonicalization.

This commit is contained in:
Stefan Thomas
2014-03-20 05:09:34 -07:00
parent 2267e599c0
commit 9d6ccdcab1
6 changed files with 65 additions and 11 deletions

View File

@@ -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"
],

View File

@@ -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;

View File

@@ -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');
}

View File

@@ -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 = {

View 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));
};

View 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