Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/base58.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Merged Buffer refactorings from base58-native by Stephen Pair
// Copyright (c) 2013 BitPay Inc

var assert = require('assert')
var BigInteger = require('bigi')

var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
Expand Down Expand Up @@ -46,7 +47,11 @@ function decode(string) {

for (var i = 0; i < string.length; i++) {
num = num.multiply(BASE)
num = num.add(ALPHABET_MAP[string.charAt(i)])

var figure = ALPHABET_MAP[string.charAt(i)]
assert.notEqual(figure, undefined, 'Non-base58 character')

num = num.add(figure)
}

// deal with leading zeros
Expand Down
2 changes: 1 addition & 1 deletion src/base58check.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ function decode(string) {
var checksum = buffer.slice(-4)
var newChecksum = crypto.hash256(message).slice(0, 4)

assert.deepEqual(newChecksum, checksum)
assert.deepEqual(newChecksum, checksum, 'Invalid checksum')

var version = message.readUInt8(0)
var payload = message.slice(1)
Expand Down
82 changes: 79 additions & 3 deletions src/bufferutils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,46 @@
var assert = require('assert')
var opcodes = require('./opcodes')

function pushDataSize(i) {
return i < opcodes.OP_PUSHDATA1 ? 1
: i < 0xff ? 2
: i < 0xffff ? 3
: 5
}

function readPushDataInt(buffer, offset) {
var opcode = buffer.readUInt8(offset)
var number, size

// ~6 bit
if (opcode < opcodes.OP_PUSHDATA1) {
number = opcode
size = 1

// 8 bit
} else if (opcode === opcodes.OP_PUSHDATA1) {
number = buffer.readUInt8(offset + 1)
size = 2

// 16 bit
} else if (opcode === opcodes.OP_PUSHDATA2) {
number = buffer.readUInt16LE(offset + 1)
size = 3

// 32 bit
} else {
assert.equal(opcode, opcodes.OP_PUSHDATA4, 'Unexpected opcode')

number = buffer.readUInt32LE(offset + 1)
size = 5

}

return {
number: number,
size: size
}
}

function readUInt64LE(buffer, offset) {
var a = buffer.readUInt32LE(offset)
Expand All @@ -16,17 +58,17 @@ function readVarInt(buffer, offset) {
var t = buffer.readUInt8(offset)
var number, size

// 8-bit
// 8 bit
if (t < 253) {
number = t
size = 1

// 16-bit
// 16 bit
} else if (t < 254) {
number = buffer.readUInt16LE(offset + 1)
size = 3

// 32-bit
// 32 bit
} else if (t < 255) {
number = buffer.readUInt32LE(offset + 1)
size = 5
Expand All @@ -43,6 +85,37 @@ function readVarInt(buffer, offset) {
}
}

function writePushDataInt(buffer, number, offset) {
var size = pushDataSize(number)

// ~6 bit
if (size === 1) {
buffer.writeUInt8(number, offset)

// 8 bit
} else if (size === 2) {
buffer.writeUInt8(opcodes.OP_PUSHDATA1, offset)
buffer.writeUInt8(number, offset + 1)

// 16 bit
} else if (size === 3) {
buffer.writeUInt8(opcodes.OP_PUSHDATA2, offset)
buffer.writeUInt16LE(number, offset + 1)

// 32 bit
} else {
// Javascript Safe Integer limitation
// assert(Number.isSafeInteger(value), 'value must be < 2^53')
assert(number < 0x0020000000000000, 'value must be < 2^53')

buffer.writeUInt8(opcodes.OP_PUSHDATA4, offset)
buffer.writeUInt32LE(number, offset + 1)

}

return size
}

function writeUInt64LE(buffer, value, offset) {
// Javascript Safe Integer limitation
// assert(Number.isSafeInteger(value), 'value must be < 2^53')
Expand Down Expand Up @@ -86,9 +159,12 @@ function writeVarInt(buffer, number, offset) {
}

module.exports = {
pushDataSize: pushDataSize,
readPushDataInt: readPushDataInt,
readUInt64LE: readUInt64LE,
readVarInt: readVarInt,
varIntSize: varIntSize,
writePushDataInt: writePushDataInt,
writeUInt64LE: writeUInt64LE,
writeVarInt: writeVarInt
}
9 changes: 6 additions & 3 deletions src/ecdsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,17 @@ function parseSig(buffer) {
assert.equal(buffer.readUInt8(0), 0x30, 'Not a DER sequence')
assert.equal(buffer.readUInt8(1), buffer.length - 2, 'Invalid sequence length')

assert.equal(buffer.readUInt8(2), 0x02, 'Expected DER integer')
assert.equal(buffer.readUInt8(2), 0x02, 'Expected a DER integer')
var rLen = buffer.readUInt8(3)
var rB = buffer.slice(4, 4 + rLen)

var offset = 4 + rLen
assert.equal(buffer.readUInt8(offset), 0x02, 'Expected a 2nd DER integer')
assert.equal(buffer.readUInt8(offset), 0x02, 'Expected a DER integer (2)')
var sLen = buffer.readUInt8(1 + offset)
var sB = buffer.slice(2 + offset)
offset += 2 + sLen

assert.equal(offset, buffer.length, 'Invalid DER encoding')

return {
r: BigInteger.fromDERInteger(rB),
Expand Down Expand Up @@ -155,7 +158,7 @@ function parseSigCompact(buffer) {
var i = buffer.readUInt8(0) - 27

// At most 3 bits
assert.equal(i, i & 7, 'Invalid signature type')
assert.equal(i, i & 7, 'Invalid signature parameter')
var compressed = !!(i & 4)

// Recovery param only
Expand Down
2 changes: 1 addition & 1 deletion src/eckey.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ ECKey.fromWIF = function(string) {
var compressed = false

if (payload.length === 33) {
assert.strictEqual(payload[32], 0x01, 'Invalid WIF string')
assert.strictEqual(payload[32], 0x01, 'Invalid compression flag')

payload = payload.slice(0, -1)
compressed = true
Expand Down
4 changes: 2 additions & 2 deletions src/ecpubkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ var sec = require('./sec')
var ecparams = sec('secp256k1')

function ECPubKey(Q, compressed) {
assert(Q instanceof ECPointFp, 'Q must be an ECPointFP')
assert(Q instanceof ECPointFp, 'Expected ECPointFP, got ' + Q)

if (compressed == undefined) compressed = true
assert.strictEqual(typeof compressed, 'boolean', 'Invalid compression flag')
assert.strictEqual(typeof compressed, 'boolean', 'Expected boolean, got ' + compressed)

this.compressed = compressed
this.Q = Q
Expand Down
51 changes: 49 additions & 2 deletions src/script.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var assert = require('assert')
var bufferutils = require('./bufferutils')
var crypto = require('./crypto')
var opcodes = require('./opcodes')

Expand Down Expand Up @@ -246,7 +247,7 @@ Script.prototype.writeOp = function(opcode) {
Script.prototype.writeBytes = function(data) {
// FIXME: Script module doesn't support buffers yet
if (Buffer.isBuffer(data)) data = Array.prototype.slice.call(data);
assert(Array.isArray(data), "Expected a byte array. Got " + data)
assert(Array.isArray(data), 'Expected a byte array, got ' + data)

if (data.length < opcodes.OP_PUSHDATA1) {
this.buffer.push(data.length)
Expand Down Expand Up @@ -304,7 +305,7 @@ Script.createP2SHScriptPubKey = function(hash) {

// m [pubKeys ...] n OP_CHECKMULTISIG
Script.createMultisigScriptPubKey = function(m, pubKeys) {
assert(Array.isArray(pubKeys), 'Expected Array, got: ' + pubKeys)
assert(Array.isArray(pubKeys), 'Expected Array, got ' + pubKeys)
assert(pubKeys.length >= m, 'Not enough pubKeys provided')
var script = new Script()
var n = pubKeys.length
Expand Down Expand Up @@ -367,4 +368,50 @@ Script.prototype.clone = function() {
return new Script(this.buffer)
}

Script.fromChunks = function(chunks) {
assert(Array.isArray(chunks), 'Expected Array, got ' + chunks)

var bufferSize = chunks.reduce(function(accum, chunk) {
var chunkSize = 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per discussed in IRC, this implied branch for handling opcodes may not be the clearest. Perhaps making it an actual else branch makes the code easier to read.


// FIXME: transitionary
if (Array.isArray(chunk) || Buffer.isBuffer(chunk)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just convert every array-like chunk in chunks into a buffer after line 372? then the type check won't be necessary here and below. And when chunks are fully bufferified, just remove the conversion code we are good to go. minor point given that this is still WIP

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly what will happen, just avoided for now because this would require changing a lot more code.
In fact, the conversion won't even be necessary, we'll never accept Arrays in the first place once Script is "bufferified".

chunkSize = bufferutils.pushDataSize(chunk.length) + chunk.length
}

return accum + chunkSize
}, 0.0)

var buffer = new Buffer(bufferSize)
var offset = 0

chunks.forEach(function(chunk) {
// FIXME: transitionary
if (Array.isArray(chunk) || Buffer.isBuffer(chunk)) {
offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)

// FIXME: transitionary
// chunk.copy(buffer, offset)
for (var i = 0; i < chunk.length; ++i) {
buffer[offset + i] = chunk[i]
}

offset += chunk.length

} else {
buffer.writeUInt8(chunk, offset)
offset += 1
}
})

return Script.fromBuffer(buffer)
}

// FIXME: doesn't work for data chunks, maybe time to use buffertools.compare...
Script.prototype.without = function(needle) {
return Script.fromChunks(this.chunks.filter(function(op) {
return op !== needle
}))
}

module.exports = Script
Loading