Bitcoin Forum

Bitcoin => Development & Technical Discussion => Topic started by: syriven on September 20, 2013, 03:28:43 AM



Title: Message Signing Issues
Post by: syriven on September 20, 2013, 03:28:43 AM
Hey guys. I'm using message signing/verification in the project I'm working on. The server (php) will verify a message signature to authorize actions from the client (theoretically any language, but right now both JS and python).

All the signing/verify libraries work well together for any message under 253 characters--but when they need to store the message length in more than one byte, things get really hairy. I've tried fixing things myself, but I'm not even sure what to use as a reference anymore. If anyone can point me in the right direction, or just tell me which bit of source code to use as a reference, I'd be very grateful.

Here's how the php sig verification script (from https://github.com/scintill/php-bitcoin-signature-routines) expects message length to be encoded:

Code:
function numToVarIntString($i) {
if ($i < 0xfd) {
return chr($i);
} else if ($i <= 0xffff) {
return pack('Cv', 0xfd, $i);
} else if ($i <= 0xffffffff) {
return pack('CV', 0xfe, $i);
} else {
throw new InvalidArgumentException('int too large');
}
}

This code only agrees with brainwallet.org's method, again, if the length of the message is less than 253.

Here's how the JS signing library (from https://github.com/bitcoinjs/bitcoinjs-lib) encodes length before signing:

Code:
numToVarInt: function (i)
  {
    if (i < 0xfd) {
      // unsigned char
      return [i];
    } else if (i <= 1<<16) {
      // unsigned short (LE)
      return [0xfd, i >>> 8, i & 255];
    } else if (i <= 1<<32) {
      // unsigned int (LE)
      return [0xfe].concat(Crypto.util.wordsToBytes([i]));
    } else {
      // unsigned long long (LE)
      return [0xff].concat(Crypto.util.wordsToBytes([i >>> 32, i]));
    }
  }

I already know of one bug in the JS code: i<<32 evaluates to 0. I'm not too worried about that at the moment, though, because i'm still trying to get that second case to work.

The python signing library (from https://github.com/vbuterin/pybitcointools) just uses chr(len(message)), which obviously only works when len(message) < 253.

I'm assuming brainwallet.org's implementation is right, but before I try to redesign all of the other tools according to how that tool behaves, I figured I'd come to you guys and make sure I'm on the right track.

I'd be more than happy to fix whichever of these is broken if I only knew for sure which one was right, or if I was pointed to an implementation that was right. I'm just having a lot of trouble getting started, as I'm new to both cryptography and open-source development (it takes me a while to dig through someone else's code and find what I'm looking for).

Alternatively, if there are better-tested libraries out there for these languages (or others!) for signing/verifying Bitcoin messages, I'd love to hear about them.

Thanks in advance for any help you can offer!


Title: Re: Message Signing Issues
Post by: kjj on September 20, 2013, 04:39:38 AM
Your byte order is wrong in the 16 and 32 bit words.  Try Cn and CN.


Title: Re: Message Signing Issues
Post by: fpgaminer on September 20, 2013, 05:00:03 AM
Quote
I've tried fixing things myself, but I'm not even sure what to use as a reference anymore.
You get to choose what to use as a reference.  In my personal opinion, the Bitcoin protocol and Satoshi client should be used as the reference.  That seems like a sane choice.

Variable length integer is defined here: https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer (https://en.bitcoin.it/wiki/Protocol_specification#Variable_length_integer)

Some of the discrepancies you have found are due to endian mis-matches.  The Bitcoin Protocol uses little endian in its Variable length integers.  Brainwallet gets it wrong and uses big endian encoding.  Go ahead, sign a long (>=253 bytes) using Brainwallet, and then try to verify it in Bitcoin-QT.

The PHP code you posted looks to have it correct.

Quote
Your byte order is wrong in the 16 and 32 bit words.  Try Cn and CN.
If we're using Bitcoin-QT/d and the associated protocol as the reference, then no, Cv is correct.


Title: Re: Message Signing Issues
Post by: syriven on September 20, 2013, 10:57:06 PM
Great, thanks for the help and the links! They were just what I needed.