handle low S values in signatures.

This commit is contained in:
Christopher Jeffrey 2016-01-12 19:10:32 -08:00
parent de455fa3e9
commit a71da261ad
3 changed files with 58 additions and 3 deletions

View File

@ -31,5 +31,6 @@ bcoin.protocol.network.set(process.env.BCOIN_NETWORK || 'main');
bcoin.bn = bn;
bcoin.elliptic = elliptic;
bcoin.signature = require('elliptic/lib/elliptic/ec/signature');
bcoin.hash = hash;
bcoin.async = async;

View File

@ -237,9 +237,12 @@ script.subscript = function subscript(s, lastSep) {
return res;
};
script.checksig = function checksig(hash, sig, pub) {
script.checksig = function checksig(msg, sig, pub) {
var k;
if (pub.getPublic)
pub = pub.getPublic();
try {
k = bcoin.ecdsa.keyPair({ pub: pub });
} catch (e) {
@ -255,7 +258,7 @@ script.checksig = function checksig(hash, sig, pub) {
// Use a try catch in case there are
// any uncaught errors for bad inputs in verify().
try {
return bcoin.ecdsa.verify(hash, sig, pub);
return bcoin.ecdsa.verify(msg, sig, pub);
} catch (e) {
return false;
}
@ -1542,6 +1545,54 @@ script.isValidSignature = function isValidSignature(sig, allowZero) {
return true;
};
script.isLowDER = function isLowDER(sig, type) {
var half = bcoin.ecdsa.n.ushrn(1);
if (!sig.s) {
assert(utils.isBuffer(sig));
if (sig[sig.length - 1] === type)
sig = sig.slice(0, -1);
try {
sig = new bcoin.signature(sig);
} catch (e) {
return false;
}
}
// Technically a negative S value is low,
// but we don't want to ever use negative
// S values in bitcoin.
if (sig.s.cmpn(0) <= 0)
return false;
// If S is greater than half the order,
// it's too high.
if (sig.s.cmp(half) > 0)
return false;
return true;
};
script.sign = function sign(msg, key) {
var half = bcoin.ecdsa.n.ushrn(1);
var sig = bcoin.ecdsa.sign(msg, key.priv);
// Elliptic shouldn't be generating
// negative S values.
assert(sig.s.cmpn(0) > 0);
// S value is already low.
if (sig.s.cmp(half) <= 0)
return sig.toDER();
// Subtract from the `n` order to make it smaller.
sig.s = bcoin.ecdsa.n.sub(sig.s);
return sig.toDER();
};
script.format = function format(input, output) {
var scripts = [];
var prev, redeem;

View File

@ -251,7 +251,10 @@ TX.prototype.signInput = function signInput(index, key, type) {
hash = this.signatureHash(index, redeem, type);
// Sign the transaction with our one input
signature = bcoin.ecdsa.sign(hash, key.priv).toDER();
signature = bcoin.script.sign(hash, key);
// Something is broken if this doesn't work:
assert(bcoin.script.checksig(hash, signature, key));
// Add the sighash as a single byte to the signature
signature = signature.concat(type);