Skip to content

Commit

Permalink
rm ECSignature, add script.signature instead
Browse files Browse the repository at this point in the history
  • Loading branch information
dcousens committed Jul 11, 2016
1 parent 27a3f9a commit 5c17485
Show file tree
Hide file tree
Showing 17 changed files with 330 additions and 804 deletions.
98 changes: 10 additions & 88 deletions src/ecdsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ var typeforce = require('typeforce')
var types = require('./types')

var BigInteger = require('bigi')
var ECSignature = require('./ecsignature')

var ZERO = new Buffer([0])
var ONE = new Buffer([1])

var ecurve = require('ecurve')
var secp256k1 = ecurve.getCurveByName('secp256k1')

var ECSignatureType = typeforce.compile({
r: types.BigInt,
s: types.BigInt
})

// https://tools.ietf.org/html/rfc6979#section-3.2
function deterministicGenerateK (hash, x, checkSig) {
typeforce(types.tuple(
Expand Down Expand Up @@ -105,13 +109,16 @@ function sign (hash, d) {
s = n.subtract(s)
}

return new ECSignature(r, s)
return {
r: r,
s: s
}
}

function verify (hash, signature, Q) {
typeforce(types.tuple(
types.Hash256bit,
types.ECSignature,
ECSignatureType,
types.ECPoint
), arguments)

Expand Down Expand Up @@ -154,93 +161,8 @@ function verify (hash, signature, Q) {
return v.equals(r)
}

/**
* Recover a public key from a signature.
*
* See SEC 1: Elliptic Curve Cryptography, section 4.1.6, "Public
* Key Recovery Operation".
*
* http://www.secg.org/download/aid-780/sec1-v2.pdf
*/
function recoverPubKey (e, signature, i) {
typeforce(types.tuple(
types.BigInt,
types.ECSignature,
types.UInt2
), arguments)

var n = secp256k1.n
var G = secp256k1.G
var r = signature.r
var s = signature.s

if (r.signum() <= 0 || r.compareTo(n) >= 0) throw new Error('Invalid r value')
if (s.signum() <= 0 || s.compareTo(n) >= 0) throw new Error('Invalid s value')

// A set LSB signifies that the y-coordinate is odd
var isYOdd = i & 1

// The more significant bit specifies whether we should use the
// first or second candidate key.
var isSecondKey = i >> 1

// 1.1 Let x = r + jn
var x = isSecondKey ? r.add(n) : r
var R = secp256k1.pointFromX(isYOdd, x)

// 1.4 Check that nR is at infinity
var nR = R.multiply(n)
if (!secp256k1.isInfinity(nR)) throw new Error('nR is not a valid curve point')

// Compute r^-1
var rInv = r.modInverse(n)

// Compute -e from e
var eNeg = e.negate().mod(n)

// 1.6.1 Compute Q = r^-1 (sR - eG)
// Q = r^-1 (sR + -eG)
var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv)

secp256k1.validate(Q)

return Q
}

/**
* Calculate pubkey extraction parameter.
*
* When extracting a pubkey from a signature, we have to
* distinguish four different cases. Rather than putting this
* burden on the verifier, Bitcoin includes a 2-bit value with the
* signature.
*
* This function simply tries all four cases and returns the value
* that resulted in a successful pubkey recovery.
*/
function calcPubKeyRecoveryParam (e, signature, Q) {
typeforce(types.tuple(
types.BigInt,
types.ECSignature,
types.ECPoint
), arguments)

for (var i = 0; i < 4; i++) {
var Qprime = recoverPubKey(e, signature, i)

// 1.6.2 Verify Q
if (Qprime.equals(Q)) {
return i
}
}

throw new Error('Unable to find valid recovery factor')
}

module.exports = {
calcPubKeyRecoveryParam: calcPubKeyRecoveryParam,
deterministicGenerateK: deterministicGenerateK,
recoverPubKey: recoverPubKey,
sign: sign,
verify: verify,

Expand Down
87 changes: 0 additions & 87 deletions src/ecsignature.js

This file was deleted.

2 changes: 0 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
module.exports = {
Block: require('./block'),
ECPair: require('./ecpair'),
ECSignature: require('./ecsignature'),
HDNode: require('./hdnode'),
Transaction: require('./transaction'),
TransactionBuilder: require('./transaction_builder'),

address: require('./address'),
bufferutils: require('./bufferutils'),
crypto: require('./crypto'),
message: require('./message'),
networks: require('./networks'),
opcodes: require('./opcodes.json'),
script: require('./script')
Expand Down
54 changes: 0 additions & 54 deletions src/message.js

This file was deleted.

1 change: 1 addition & 0 deletions src/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ module.exports = {
toASM: toASM,

number: require('./script_number'),
signature: require('./script_signature'),

isCanonicalPubKey: isCanonicalPubKey,
isCanonicalSignature: isCanonicalSignature,
Expand Down
40 changes: 40 additions & 0 deletions src/script_signature.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
var bip66 = require('bip66')
var BigInteger = require('bigi')

// BIP62: 1 byte hashType flag (only 0x01, 0x02, 0x03, 0x81, 0x82 and 0x83 are allowed)
function decode (buffer) {
var hashType = buffer.readUInt8(buffer.length - 1)
var hashTypeMod = hashType & ~0x80
if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)

var decode = bip66.decode(buffer.slice(0, -1))

return {
signature: {
r: BigInteger.fromDERInteger(decode.r),
s: BigInteger.fromDERInteger(decode.s)
},
hashType: hashType
}
}

function encode (signature, hashType) {
var hashTypeMod = hashType & ~0x80
if (hashTypeMod <= 0 || hashTypeMod >= 4) throw new Error('Invalid hashType ' + hashType)

var hashTypeBuffer = new Buffer(1)
hashTypeBuffer.writeUInt8(hashType, 0)

var r = new Buffer(signature.r.toDERInteger())
var s = new Buffer(signature.s.toDERInteger())

return Buffer.concat([
bip66.encode(r, s),
hashTypeBuffer
])
}

module.exports = {
decode: decode,
encode: encode
}
13 changes: 6 additions & 7 deletions src/transaction_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ var typeforce = require('typeforce')
var types = require('./types')

var ECPair = require('./ecpair')
var ECSignature = require('./ecsignature')
var Transaction = require('./transaction')

// re-orders signatures to match pubKeys, fills undefined otherwise
Expand Down Expand Up @@ -74,7 +73,7 @@ function extractInput (transaction, txIn, vin) {
return result

case 'pubkeyhash':
parsed = ECSignature.parseScriptSignature(scriptSigChunks[0])
parsed = bscript.signature.decode(scriptSigChunks[0])
hashType = parsed.hashType
pubKeys = scriptSigChunks.slice(1)
signatures = [parsed.signature]
Expand All @@ -83,7 +82,7 @@ function extractInput (transaction, txIn, vin) {
break

case 'pubkey':
parsed = ECSignature.parseScriptSignature(scriptSigChunks[0])
parsed = bscript.signature.decode(scriptSigChunks[0])
hashType = parsed.hashType
signatures = [parsed.signature]

Expand All @@ -97,7 +96,7 @@ function extractInput (transaction, txIn, vin) {
signatures = scriptSigChunks.slice(1).map(function (chunk) {
if (chunk === ops.OP_0) return undefined

parsed = ECSignature.parseScriptSignature(chunk)
parsed = bscript.signature.decode(chunk)
hashType = parsed.hashType

return parsed.signature
Expand Down Expand Up @@ -308,18 +307,18 @@ function buildFromInputData (input, scriptType, parentType, redeemScript, allowI

switch (scriptType) {
case 'pubkeyhash':
var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
var pkhSignature = bscript.signature.encode(input.signatures[0], input.hashType)
scriptSig = bscript.pubKeyHashInput(pkhSignature, input.pubKeys[0])
break

case 'pubkey':
var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
var pkSignature = bscript.signature.encode(input.signatures[0], input.hashType)
scriptSig = bscript.pubKeyInput(pkSignature)
break

case 'multisig':
var msSignatures = input.signatures.map(function (signature) {
return signature && signature.toScriptSignature(input.hashType)
return signature && bscript.signature.encode(signature, input.hashType)
})

// fill in blanks with OP_0
Expand Down
Loading

0 comments on commit 5c17485

Please sign in to comment.