Bitcoin Forum
May 25, 2024, 06:54:09 AM *
News: Latest Bitcoin Core release: 27.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: Message Signing Issues  (Read 1083 times)
syriven (OP)
Newbie
*
Offline Offline

Activity: 31
Merit: 0


View Profile
September 20, 2013, 03:28:43 AM
 #1

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!
kjj
Legendary
*
Offline Offline

Activity: 1302
Merit: 1025



View Profile
September 20, 2013, 04:39:38 AM
 #2

Your byte order is wrong in the 16 and 32 bit words.  Try Cn and CN.

17Np17BSrpnHCZ2pgtiMNnhjnsWJ2TMqq8
I routinely ignore posters with paid advertising in their sigs.  You should too.
fpgaminer
Hero Member
*****
Offline Offline

Activity: 560
Merit: 517



View Profile WWW
September 20, 2013, 05:00:03 AM
 #3

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

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.

syriven (OP)
Newbie
*
Offline Offline

Activity: 31
Merit: 0


View Profile
September 20, 2013, 10:57:06 PM
 #4

Great, thanks for the help and the links! They were just what I needed.
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!