-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
While the deterministicK (https://github.com/bitpay/bitcore/blob/master/lib/crypto/ecdsa.js#L76)
function seems to be OK and well tested, it is feed with the sighash of the
output reversed, so the produced K does not match RFC 6979. This does not seem as security issue, but it should be corrected to much the standard.
As a side note, bitcore implements BIP62's low S values
(https://github.com/bitpay/bitcore/blob/master/lib/crypto/ecdsa.js#L217). Because of that bitcore's signatures could be different from other's implementation.
After fixing the reversed hash, and removing lowS, I was able to produce the exact same signatures from pybitcointools and bitcore. As a reference, here are the to test scripts:
b = require('./index.js');
m = new b.HDPrivateKey('xprv9s21ZrQH143K37fVgfg5rR5qgkKGoJQVkzYAiMtxqJNTQCsNhJ24Gfjjh6LLdRXpQYFBiLxpCMxRCbEbKqphja1ysWy2SfYfZ8p8YqwqdQK');
node = m.derive("m/45'/2147483647/0/1");
privkey = node.privateKey;
console.log('[kk.js.7:privkey:]', privkey); //TODO
pubkey = privkey.toPublicKey();
console.log('[kk.js.9:pubkey:]', pubkey); //TODO
addr = new b.Address([pubkey], 1);
console.log('[kk.js.12:addr:]', addr); //TODO
rscript = b.Script.buildMultisigOut([pubkey], 1);
console.log('[kk.js.15:rscript:]', rscript); //TODO
script = rscript.toScriptHashOut();
console.log('[kk.js.17:script:]', script.toHex()); //TODO
var utxo = [{
address: "34xfXrCmf8ujvbJv9k1uydyxKSyMvdbTgT",
txid: "3562112b8f29d4240465b6610b537a2affe96ab3f1b44366828640f4bc1fbf22",
vout: 0,
ts: 1433781455,
scriptPubKey: "a91423de02cdb431d55a72acaca33737b89bf6c381da87",
amount: 0.0002,
confirmations: 1,
confirmationsFromCache: false
}];
t = new b.Transaction()
.from(utxo, [pubkey],1)
.to('3QCLipDgrREZfjnN9cMQhCBwrrRnEvfsqZ',10000);
console.log('TX Before:',t); //TODO
t.sign(privkey);
console.log('[kk.js.32]',t); //TODO
var signature = t.getSignatures(privkey)[0];
console.log('[kk.js.41:signatures:]',signature.signature.toDER().toString('hex')); //TODOpybitcoin tools:
from bitcoin import *
m=bip32_master_key('hola')
m45 = bip32_ckd(m, 2**31 + 45)
mshared = bip32_ckd(m45, 2**31 - 1)
node = bip32_ckd(bip32_ckd(mshared,0),1)
privkey = bip32_extract_key(node)
pubkey = privtopub(privkey)
script = mk_multisig_script([pubkey], 1, 1)
addr = scriptaddr(script)
print 'addr', addr
outs = [{'value': 10000, 'address': '3QCLipDgrREZfjnN9cMQhCBwrrRnEvfsqZ'}];
h = [{'output': u'3562112b8f29d4240465b6610b537a2affe96ab3f1b44366828640f4bc1fbf22:0', 'block_height': 360016, 'spend': u'bef9e5000fb5ee3f957f364d9483cd54643f3e087077c7ff52a5abde7b76389a:0', 'value': 20000, 'address': u'34xfXrCmf8ujvbJv9k1uydyxKSyMvdbTgT'}];
print 'history', h
t = mktx(h,outs);
print 'tx Before:', t
sig = multisign(t, 0, script, privkey)
print "sig:", sigPatch to make signatures from bitcore equal to pybitcointools: (reverse hash at deterministicK and comment lowS)
diff --git a/lib/crypto/ecdsa.js b/lib/crypto/ecdsa.js
index 5f2c207..af6a46b 100644
--- a/lib/crypto/ecdsa.js
+++ b/lib/crypto/ecdsa.js
@@ -88,13 +88,20 @@ ECDSA.prototype.deterministicK = function(badrs) {
var x = this.privkey.bn.toBuffer({
size: 32
});
- k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, this.hashbuf]), k);
+ var b2 = BufferUtil.copy(this.hashbuf);
+ var h2 = BufferUtil.reverse(this.hashbuf);
+ k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x00]), x, h2]), k);
v = Hash.sha256hmac(v, k);
- k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, this.hashbuf]), k);
+ k = Hash.sha256hmac(Buffer.concat([v, new Buffer([0x01]), x, h2]), k);
v = Hash.sha256hmac(v, k);
v = Hash.sha256hmac(v, k);
var T = BN.fromBuffer(v);
var N = Point.getN();
// also explained in 3.2, we must ensure T is in the proper range (0, N)
for (var i = 0; i < badrs || !(T.lt(N) && T.gt(BN.Zero)); i++) {
@@ -103,6 +110,7 @@ ECDSA.prototype.deterministicK = function(badrs) {
v = Hash.sha256hmac(v, k);
T = BN.fromBuffer(v);
}
return this;
@@ -208,13 +216,16 @@ ECDSA.prototype._findSignature = function(d, e) {
this.deterministicK(badrs);
}
badrs++;
k = this.k;
Q = G.mul(k);
r = Q.x.mod(N);
s = k.invm(N).mul(e.add(d.mul(r))).mod(N);
} while (r.cmp(BN.Zero) <= 0 || s.cmp(BN.Zero) <= 0);
- s = ECDSA.toLowS(s);
+// s = ECDSA.toLowS(s);
return {
s: s,
r: r