Skip to content

Commit

Permalink
Fixed DER-encoding - expects signed integers.
Browse files Browse the repository at this point in the history
Thanks to Ben Reeves for the report and Tomas Pomin for the solution.

See http://crypto.stackexchange.com/questions/1795/converting-a-der-ecdsa-signature-to-asn-1
  • Loading branch information
justmoon committed Aug 17, 2012
1 parent c2ce224 commit 07f9d55
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 4 deletions.
6 changes: 3 additions & 3 deletions src/ecdsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,8 @@ Bitcoin.ECDSA = (function () {
* Takes two BigIntegers representing r and s and returns a byte array.
*/
serializeSig: function (r, s) {
var rBa = r.toByteArrayUnsigned();
var sBa = s.toByteArrayUnsigned();
var rBa = r.toByteArraySigned();
var sBa = s.toByteArraySigned();

var sequence = [];
sequence.push(0x02); // INTEGER
Expand All @@ -327,7 +327,7 @@ Bitcoin.ECDSA = (function () {
* Parses a byte array containing a DER-encoded signature.
*
* This function will return an object of the form:
*
*
* {
* r: BigInteger,
* s: BigInteger
Expand Down
76 changes: 75 additions & 1 deletion src/util.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
// BigInteger monkey patching
BigInteger.valueOf = nbv;

/**
* Returns a byte array representation of the big integer.
*
* This returns the absolute of the contained value in big endian
* form. A value of zero results in an empty array.
*/
BigInteger.prototype.toByteArrayUnsigned = function () {
var ba = this.toByteArray();
var ba = this.abs().toByteArray();
if (ba.length) {
if (ba[0] == 0) {
ba = ba.slice(1);
Expand All @@ -14,6 +21,13 @@ BigInteger.prototype.toByteArrayUnsigned = function () {
return ba;
}
};

/**
* Turns a byte array into a big integer.
*
* This function will interpret a byte array as a big integer in big
* endian notation and ignore leading zeros.
*/
BigInteger.fromByteArrayUnsigned = function (ba) {
if (!ba.length) {
return ba.valueOf(0);
Expand All @@ -26,6 +40,66 @@ BigInteger.fromByteArrayUnsigned = function (ba) {
}
};

/**
* Converts big integer to signed byte representation.
*
* The format for this value uses a the most significant bit as a sign
* bit. If the most significant bit is already occupied by the
* absolute value, an extra byte is prepended and the sign bit is set
* there.
*
* Examples:
*
* 0 => 0x00
* 1 => 0x01
* -1 => 0x81
* 127 => 0x7f
* -127 => 0xff
* 128 => 0x0080
* -128 => 0x8080
* 255 => 0x00ff
* -255 => 0x80ff
* 16300 => 0x3fac
* -16300 => 0xbfac
* 62300 => 0x00f35c
* -62300 => 0x80f35c
*/
BigInteger.prototype.toByteArraySigned = function () {
var val = this.abs().toByteArrayUnsigned();
var neg = this.compareTo(BigInteger.ZERO) < 0;

if (neg) {
if (val[0] & 0x80) {
val.unshift(0x80);
} else {
val[0] |= 0x80;
}
} else {
if (val[0] & 0x80) {
val.unshift(0x00);
}
}

return val;
};

/**
* Parse a signed big integer byte representation.
*
* For details on the format please see BigInteger.toByteArraySigned.
*/
BigInteger.fromByteArraySigned = function (ba) {
// Check for negative value
if (ba[0] & 0x80) {
// Remove sign bit
ba[0] &= 0x7f;

return BigInteger.fromByteArrayUnsigned(ba).negate();
} else {
return BigInteger.fromByteArrayUnsigned(ba);
}
};

// Console ignore
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count",
Expand Down

0 comments on commit 07f9d55

Please sign in to comment.