Skip to content

Bitcore signatures do not comply with RFC 6979 #1269

@matiu

Description

@matiu

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')); //TODO

pybitcoin 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:", sig

Patch 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions