diff --git a/src/ecdsa.js b/src/ecdsa.js index a41d0b2..dfb05d1 100644 --- a/src/ecdsa.js +++ b/src/ecdsa.js @@ -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 @@ -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 diff --git a/src/util.js b/src/util.js index 0fda4c5..4c468a0 100644 --- a/src/util.js +++ b/src/util.js @@ -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); @@ -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); @@ -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",