|
|
@ -10,8 +10,7 @@ var Signature = function Signature(r, s) { |
|
|
|
r: r, |
|
|
|
s: s |
|
|
|
}); |
|
|
|
} |
|
|
|
else if (r) { |
|
|
|
} else if (r) { |
|
|
|
var obj = r; |
|
|
|
this.set(obj); |
|
|
|
} |
|
|
@ -132,13 +131,17 @@ Signature.prototype.toCompact = function(i, compressed) { |
|
|
|
|
|
|
|
if (!(i === 0 || i === 1 || i === 2 || i === 3)) |
|
|
|
throw new Error('i must be equal to 0, 1, 2, or 3'); |
|
|
|
|
|
|
|
|
|
|
|
var val = i + 27 + 4; |
|
|
|
if (compressed === false) |
|
|
|
val = val - 4; |
|
|
|
var b1 = new Buffer([val]); |
|
|
|
var b2 = this.r.toBuffer({size: 32}); |
|
|
|
var b3 = this.s.toBuffer({size: 32}); |
|
|
|
var b2 = this.r.toBuffer({ |
|
|
|
size: 32 |
|
|
|
}); |
|
|
|
var b3 = this.s.toBuffer({ |
|
|
|
size: 32 |
|
|
|
}); |
|
|
|
return Buffer.concat([b1, b2, b3]); |
|
|
|
}; |
|
|
|
|
|
|
@ -168,6 +171,115 @@ Signature.prototype.toString = function() { |
|
|
|
return buf.toString('hex'); |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* This function is translated from bitcoind's IsDERSignature and is used in |
|
|
|
* the script interpreter. This "DER" format actually includes an extra byte, |
|
|
|
* the nhashtype, at the end. It is really the tx format, not DER format. |
|
|
|
* |
|
|
|
* A canonical signature exists of: [30] [total len] [02] [len R] [R] [02] [len S] [S] [hashtype] |
|
|
|
* Where R and S are not negative (their first byte has its highest bit not set), and not |
|
|
|
* excessively padded (do not start with a 0 byte, unless an otherwise negative number follows, |
|
|
|
* in which case a single 0 byte is necessary and even required). |
|
|
|
* |
|
|
|
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
|
|
|
*/ |
|
|
|
Signature.isTxDER = function(buf) { |
|
|
|
if (buf.length < 9) { |
|
|
|
// Non-canonical signature: too short
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (buf.length > 73) { |
|
|
|
// Non-canonical signature: too long
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (buf[0] !== 0x30) { |
|
|
|
// Non-canonical signature: wrong type
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (buf[1] !== buf.length - 3) { |
|
|
|
// Non-canonical signature: wrong length marker
|
|
|
|
return false; |
|
|
|
} |
|
|
|
var nLenR = buf[3]; |
|
|
|
if (5 + nLenR >= buf.length) { |
|
|
|
// Non-canonical signature: S length misplaced
|
|
|
|
return false; |
|
|
|
} |
|
|
|
var nLenS = buf[5 + nLenR]; |
|
|
|
if ((nLenR + nLenS + 7) !== buf.length) { |
|
|
|
// Non-canonical signature: R+S length mismatch
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
var R = buf.slice(4); |
|
|
|
if (buf[4 - 2] !== 0x02) { |
|
|
|
// Non-canonical signature: R value type mismatch
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (nLenR === 0) { |
|
|
|
// Non-canonical signature: R length is zero
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (R[0] & 0x80) { |
|
|
|
// Non-canonical signature: R value negative
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (nLenR > 1 && (R[0] === 0x00) && !(R[1] & 0x80)) { |
|
|
|
// Non-canonical signature: R value excessively padded
|
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
var S = buf.slice(6 + nLenR); |
|
|
|
if (buf[6 + nLenR - 2] !== 0x02) { |
|
|
|
// Non-canonical signature: S value type mismatch
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (nLenS === 0) { |
|
|
|
// Non-canonical signature: S length is zero
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (S[0] & 0x80) { |
|
|
|
// Non-canonical signature: S value negative
|
|
|
|
return false; |
|
|
|
} |
|
|
|
if (nLenS > 1 && (S[0] === 0x00) && !(S[1] & 0x80)) { |
|
|
|
// Non-canonical signature: S value excessively padded
|
|
|
|
return false; |
|
|
|
} |
|
|
|
return true; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* Compares to bitcoind's IsLowDERSignature |
|
|
|
* See also ECDSA signature algorithm which enforces this. |
|
|
|
* See also BIP 62, "low S values in signatures" |
|
|
|
*/ |
|
|
|
Signature.prototype.hasLowS = function() { |
|
|
|
if (this.s.lt(1) || |
|
|
|
this.s.gt(BN('7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0'))) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
return true; |
|
|
|
}; |
|
|
|
|
|
|
|
/** |
|
|
|
* @returns true if the nhashtype is exactly equal to one of the standard options or combinations thereof. |
|
|
|
* Translated from bitcoind's IsDefinedHashtypeSignature |
|
|
|
*/ |
|
|
|
Signature.prototype.hasDefinedHashtype = function() { |
|
|
|
if (this.nhashtype < Signature.SIGHASH_ALL || this.nhashtype > Signature.SIGHASH_SINGLE) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
return true; |
|
|
|
}; |
|
|
|
|
|
|
|
Signature.prototype.toTxFormat = function() { |
|
|
|
var derbuf = this.toDER(); |
|
|
|
var buf = new Buffer(1); |
|
|
|
buf.writeUInt8(this.nhashtype, 0); |
|
|
|
return Buffer.concat([derbuf, buf]); |
|
|
|
}; |
|
|
|
|
|
|
|
Signature.SIGHASH_ALL = 0x01; |
|
|
|
Signature.SIGHASH_NONE = 0x02; |
|
|
|
Signature.SIGHASH_SINGLE = 0x03; |
|
|
|