Eric Martindale
10 years ago
79 changed files with 8981 additions and 12 deletions
@ -1,13 +1,5 @@ |
|||
build/ |
|||
node_modules/ |
|||
*.swp |
|||
*.swo |
|||
*~ |
|||
.project |
|||
README.html |
|||
CONTRIBUTING.html |
|||
tags |
|||
coverage |
|||
.DS_Store |
|||
docs |
|||
browser/bitcore-dev.js |
|||
node_modules |
|||
browser/fullnode.js |
|||
browser/tests.js |
|||
|
@ -0,0 +1,30 @@ |
|||
This software is licensed under the MIT License. |
|||
|
|||
Copyright (c) 2014 Ryan X. Charles <ryanxcharles@gmail.com> |
|||
|
|||
Parts of this software are based on bitcore |
|||
Copyright (c) 2014 BitPay Inc. |
|||
|
|||
Parts of this software are based on BitcoinJS |
|||
Copyright (c) 2011 Stefan Thomas <justmoon@members.fsf.org> |
|||
|
|||
Parts of this software are based on BitcoinJ |
|||
Copyright (c) 2011 Google Inc. |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in |
|||
all copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|||
THE SOFTWARE. |
@ -0,0 +1,4 @@ |
|||
#!/bin/bash |
|||
|
|||
browserify index.js -o browser/fullnode.js |
|||
ls test/*.js | xargs browserify -o browser/tests.js |
@ -0,0 +1,25 @@ |
|||
var Block = require('../lib/block'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
|
|||
//This example will parse the blocks in a block file.
|
|||
//To use, pipe in a blk*****.dat file. e.g.:
|
|||
//cat blk00000.dat | node blockreader.js
|
|||
|
|||
var head = null; |
|||
|
|||
process.stdin.on('readable', function() { |
|||
if (!head) { |
|||
head = process.stdin.read(8); |
|||
if (!head) |
|||
return; |
|||
} |
|||
var body = process.stdin.read(head.slice(4).readUInt32LE(0)); |
|||
if (!body) |
|||
return; |
|||
var blockbuf = BufferWriter().write(head).write(body).concat(); |
|||
var block = Block().fromBuffer(blockbuf); |
|||
console.log(block.toJSON()); |
|||
head = null; |
|||
process.stdin.unshift(process.stdin.read()); |
|||
}); |
@ -0,0 +1,21 @@ |
|||
var ECDSA = require('../lib/ecdsa'); |
|||
var Keypair = require('../lib/keypair'); |
|||
var Hash = require('../lib/hash'); |
|||
|
|||
//ECDSA is the signature algorithm used in bitcoin
|
|||
|
|||
//start with a keypair that you will use for signing
|
|||
var keypair = Keypair().fromRandom(); |
|||
|
|||
//a message to be signed (normally you would have the hash of a transaction)
|
|||
var messagebuf = new Buffer('This is a message I would like to sign'); |
|||
|
|||
//calculate a 32 byte hash for use in ECDSA. one way to do that is sha256.
|
|||
var hashbuf = Hash.sha256(messagebuf); |
|||
|
|||
var sig = ECDSA.sign(hashbuf, keypair); |
|||
|
|||
//Anyone with the public key can verify
|
|||
var pubkey = keypair.pubkey; |
|||
console.log('Valid signature? ' + ECDSA.verify(hashbuf, sig, pubkey)); |
|||
|
@ -0,0 +1,63 @@ |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var Address = require('../lib/address'); |
|||
var Stealthkey = require('../lib/expmt/stealthkey'); |
|||
var StealthAddress = require('../lib/expmt/stealthaddress'); |
|||
var StealthMessage = require('../lib/expmt/stealthmessage'); |
|||
var Keypair = require('../lib/keypair') |
|||
|
|||
//First, the person receiving must make a stealth key.
|
|||
|
|||
var sk = Stealthkey().fromRandom(); |
|||
|
|||
//It has an associated stealth address.
|
|||
|
|||
var sa = StealthAddress().fromStealthkey(sk); |
|||
|
|||
console.log('Stealth address: ' + sa); |
|||
|
|||
//Now make a message.
|
|||
|
|||
var messagebuf = new Buffer('Hello there. Only you know this message is to you, and only you know what it says.'); |
|||
|
|||
//Encrypt the message with the stealth address.
|
|||
|
|||
var encbuf = StealthMessage.encrypt(messagebuf, sa); |
|||
|
|||
console.log('Hex of the encrypted message: ' + encbuf.toString('hex')); |
|||
|
|||
//Note that the first 20 bytes are a pubkeyhash, which may be interpreted as a bitcoin address.
|
|||
//This address has never been seen before in public.
|
|||
|
|||
var address = Address().set({hashbuf: encbuf.slice(0, 20)}); |
|||
|
|||
console.log('The randomly generated address the message is to: ' + address); |
|||
|
|||
//And the next 33 bytes are a nonce public key, which the message is "from".
|
|||
//It has never been seen before in public.
|
|||
|
|||
var pubkey = Pubkey().fromDER(encbuf.slice(20, 20 + 33)); |
|||
|
|||
console.log('Nonce public key: ' + pubkey); |
|||
|
|||
//The owner of the stealth key can check to see if it is for them.
|
|||
|
|||
console.log('Is the message for me? ' + (StealthMessage.isForMe(encbuf, sk) ? "yes" : "no")); |
|||
|
|||
//The owner can decrypt it.
|
|||
|
|||
var messagebuf2 = StealthMessage.decrypt(encbuf, sk); |
|||
|
|||
console.log('Decrypted message: ' + messagebuf2.toString()); |
|||
|
|||
//If you do not have the payload privkey, you can still use isForMe.
|
|||
sk.payloadKeypair.privkey = undefined; |
|||
|
|||
console.log('Without payload privkey, is the message for me? ' + (StealthMessage.isForMe(encbuf, sk) ? "yes" : "no")); |
|||
|
|||
//...but not decrypt
|
|||
|
|||
try { |
|||
StealthMessage.decrypt(encbuf, sk); |
|||
} catch (e) { |
|||
console.log("...but without the payload privkey, I can't decrypt."); |
|||
} |
@ -0,0 +1,56 @@ |
|||
var fullnode = module.exports; |
|||
|
|||
//main bitcoin library
|
|||
fullnode.Address = require('./lib/address'); |
|||
fullnode.Base58 = require('./lib/base58'); |
|||
fullnode.Base58Check = require('./lib/base58check'); |
|||
fullnode.BIP32 = require('./lib/bip32'); |
|||
fullnode.Block = require('./lib/block'); |
|||
fullnode.Blockheader = require('./lib/blockheader'); |
|||
fullnode.BN = require('./lib/bn'); |
|||
fullnode.BufferReader = require('./lib/bufferreader'); |
|||
fullnode.BufferWriter = require('./lib/bufferwriter'); |
|||
fullnode.Constants = require('./lib/constants'); |
|||
fullnode.ECDSA = require('./lib/ecdsa'); |
|||
fullnode.Hash = require('./lib/hash'); |
|||
fullnode.KDF = require('./lib/kdf'); |
|||
fullnode.Keypair = require('./lib/keypair'); |
|||
fullnode.Message = require('./lib/message'); |
|||
fullnode.Opcode = require('./lib/opcode'); |
|||
fullnode.Point = require('./lib/point'); |
|||
fullnode.Privkey = require('./lib/privkey'); |
|||
fullnode.Pubkey = require('./lib/pubkey'); |
|||
fullnode.Random = require('./lib/random'); |
|||
fullnode.Script = require('./lib/script'); |
|||
fullnode.Signature = require('./lib/signature'); |
|||
fullnode.Transaction = require('./lib/transaction'); |
|||
fullnode.Txin = require('./lib/txin'); |
|||
fullnode.Txout = require('./lib/txout'); |
|||
fullnode.Varint = require('./lib/varint'); |
|||
|
|||
//experimental, nonstandard, or unstable features
|
|||
fullnode.expmt = {}; |
|||
fullnode.expmt.AES = require('./lib/expmt/aes'); |
|||
fullnode.expmt.AESCBC = require('./lib/expmt/aescbc'); |
|||
fullnode.expmt.CBC = require('./lib/expmt/cbc'); |
|||
fullnode.expmt.ECIES = require('./lib/expmt/ecies'); |
|||
fullnode.expmt.StealthAddress = require('./lib/expmt/stealthaddress'); |
|||
fullnode.expmt.Stealthkey = require('./lib/expmt/stealthkey'); |
|||
fullnode.expmt.StealthMessage = require('./lib/expmt/stealthmessage'); |
|||
fullnode.expmt.StealthTx = require('./lib/expmt/stealthtx'); |
|||
|
|||
//dependencies, subject to change
|
|||
fullnode.deps = {}; |
|||
fullnode.deps.aes = require('aes'); |
|||
fullnode.deps.bnjs = require('bn.js'); |
|||
fullnode.deps.bs58 = require('bs58'); |
|||
fullnode.deps.Buffer = Buffer; |
|||
fullnode.deps.elliptic = require('elliptic'); |
|||
fullnode.deps.hashjs = require('hash.js'); |
|||
fullnode.deps.sha512 = require('sha512'); |
|||
|
|||
//fullnode.scriptexec = require('lib/scriptexec');
|
|||
//fullnode.tx = require('lib/tx');
|
|||
//fullnode.txpartial = require('lib/txpartial');
|
|||
|
|||
//fullnode.bip70 = require('lib/bip70');
|
@ -0,0 +1,120 @@ |
|||
var base58check = require('./base58check'); |
|||
var constants = require('./constants'); |
|||
var Hash = require('./hash'); |
|||
var Pubkey = require('./pubkey'); |
|||
var Script = require('./script'); |
|||
|
|||
function Address(buf) { |
|||
if (!(this instanceof Address)) |
|||
return new Address(buf); |
|||
if (Buffer.isBuffer(buf)) { |
|||
this.fromBuffer(buf); |
|||
} else if (typeof buf === 'string') { |
|||
var str = buf; |
|||
this.fromString(str); |
|||
} else if (buf) { |
|||
var obj = buf; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Address.prototype.set = function(obj) { |
|||
this.hashbuf = obj.hashbuf || this.hashbuf || null; |
|||
this.networkstr = obj.networkstr || this.networkstr || 'mainnet'; |
|||
this.typestr = obj.typestr || this.typestr || 'pubkeyhash'; |
|||
return this; |
|||
}; |
|||
|
|||
Address.prototype.fromBuffer = function(buf) { |
|||
if (buf.length !== 1 + 20) |
|||
throw new Error('Address buffers must be exactly 21 bytes'); |
|||
var version = buf[0]; |
|||
if (version === constants['mainnet']['pubkeyhash']) { |
|||
this.networkstr = 'mainnet'; |
|||
this.typestr = 'pubkeyhash'; |
|||
} else if (version === constants['mainnet']['scripthash']) { |
|||
this.networkstr = 'mainnet'; |
|||
this.typestr = 'scripthash'; |
|||
} else if (version === constants['testnet']['pubkeyhash']) { |
|||
this.networkstr = 'testnet'; |
|||
this.typestr = 'pubkeyhash'; |
|||
} else if (version === constants['testnet']['scripthash']) { |
|||
this.networkstr = 'testnet'; |
|||
this.typestr = 'scripthash'; |
|||
} else { |
|||
this.networkstr = 'unknown'; |
|||
this.typestr = 'unknown'; |
|||
} |
|||
|
|||
this.hashbuf = buf.slice(1); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
Address.prototype.fromHashbuf = function(hashbuf, networkstr, typestr) { |
|||
if (hashbuf.length !== 20) |
|||
throw new Error('hashbuf must be exactly 20 bytes'); |
|||
this.hashbuf = hashbuf; |
|||
this.networkstr = networkstr || 'mainnet'; |
|||
this.typestr = typestr || 'pubkeyhash'; |
|||
return this; |
|||
}; |
|||
|
|||
Address.prototype.fromPubkey = function(pubkey, networkstr) { |
|||
this.hashbuf = Hash.sha256ripemd160(pubkey.toBuffer()); |
|||
this.networkstr = networkstr || 'mainnet'; |
|||
this.typestr = 'pubkeyhash'; |
|||
return this; |
|||
}; |
|||
|
|||
Address.prototype.fromScript = function(script, networkstr) { |
|||
this.hashbuf = Hash.sha256ripemd160(script.toBuffer()); |
|||
this.networkstr = networkstr || 'mainnet'; |
|||
this.typestr = 'scripthash'; |
|||
return this; |
|||
}; |
|||
|
|||
Address.prototype.fromString = function(str) { |
|||
var buf = base58check.decode(str); |
|||
return this.fromBuffer(buf); |
|||
} |
|||
|
|||
Address.isValid = function(addrstr) { |
|||
try { |
|||
var address = new Address().fromString(addrstr); |
|||
} catch (e) { |
|||
return false; |
|||
} |
|||
return address.isValid(); |
|||
}; |
|||
|
|||
Address.prototype.isValid = function() { |
|||
try { |
|||
this.validate(); |
|||
return true; |
|||
} catch (e) { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
Address.prototype.toBuffer = function() { |
|||
version = new Buffer([constants[this.networkstr][this.typestr]]); |
|||
var buf = Buffer.concat([version, this.hashbuf]); |
|||
return buf; |
|||
}; |
|||
|
|||
Address.prototype.toString = function() { |
|||
return base58check.encode(this.toBuffer()); |
|||
}; |
|||
|
|||
Address.prototype.validate = function() { |
|||
if (!Buffer.isBuffer(this.hashbuf) || this.hashbuf.length !== 20) |
|||
throw new Error('hash must be a buffer of 20 bytes'); |
|||
if (this.networkstr !== 'mainnet' && this.networkstr !== 'testnet') |
|||
throw new Error('networkstr must be "mainnet" or "testnet"'); |
|||
if (this.typestr !== 'pubkeyhash' && this.typestr !== 'scripthash') |
|||
throw new Error('typestr must be "pubkeyhash" or "scripthash"'); |
|||
return this; |
|||
}; |
|||
|
|||
module.exports = Address; |
@ -0,0 +1,53 @@ |
|||
var bs58 = require('bs58'); |
|||
|
|||
var Base58 = function Base58(obj) { |
|||
if (!(this instanceof Base58)) |
|||
return new Base58(obj); |
|||
if (Buffer.isBuffer(obj)) { |
|||
var buf = obj; |
|||
this.fromBuffer(buf); |
|||
} else if (typeof obj === 'string') { |
|||
var str = obj; |
|||
this.fromString(str); |
|||
} else if (obj) { |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Base58.prototype.set = function(obj) { |
|||
this.buf = obj.buf || this.buf || undefined; |
|||
return this; |
|||
}; |
|||
|
|||
Base58.encode = function(buf) { |
|||
if (!Buffer.isBuffer(buf)) |
|||
throw new Error('Input should be a buffer'); |
|||
return bs58.encode(buf); |
|||
}; |
|||
|
|||
Base58.decode = function(str) { |
|||
if (typeof str !== 'string') |
|||
throw new Error('Input should be a string'); |
|||
return bs58.decode(str); |
|||
}; |
|||
|
|||
Base58.prototype.fromBuffer = function(buf) { |
|||
this.buf = buf; |
|||
return this; |
|||
}; |
|||
|
|||
Base58.prototype.fromString = function(str) { |
|||
var buf = Base58.decode(str); |
|||
this.buf = buf; |
|||
return this; |
|||
}; |
|||
|
|||
Base58.prototype.toBuffer = function() { |
|||
return this.buf; |
|||
}; |
|||
|
|||
Base58.prototype.toString = function() { |
|||
return Base58.encode(this.buf); |
|||
}; |
|||
|
|||
module.exports = Base58; |
@ -0,0 +1,73 @@ |
|||
var base58 = require('./base58'); |
|||
var sha256sha256 = require('./hash').sha256sha256; |
|||
|
|||
var Base58Check = function Base58Check(obj) { |
|||
if (!(this instanceof Base58Check)) |
|||
return new Base58Check(obj); |
|||
if (Buffer.isBuffer(obj)) { |
|||
var buf = obj; |
|||
this.fromBuffer(buf); |
|||
} else if (typeof obj === 'string') { |
|||
var str = obj; |
|||
this.fromString(str); |
|||
} else if (obj) { |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Base58Check.prototype.set = function(obj) { |
|||
this.buf = obj.buf || this.buf || undefined; |
|||
return this; |
|||
}; |
|||
|
|||
Base58Check.decode = function(s) { |
|||
if (typeof s !== 'string') |
|||
throw new Error('Input must be a string'); |
|||
|
|||
var buf = base58.decode(s); |
|||
|
|||
if (buf.length < 4) |
|||
throw new Error("Input string too short"); |
|||
|
|||
var data = buf.slice(0, -4); |
|||
var csum = buf.slice(-4); |
|||
|
|||
var hash = sha256sha256(data); |
|||
var hash4 = hash.slice(0, 4); |
|||
|
|||
if (csum.toString('hex') !== hash4.toString('hex')) |
|||
throw new Error("Checksum mismatch"); |
|||
|
|||
return data; |
|||
}; |
|||
|
|||
Base58Check.encode = function(buf) { |
|||
if (!Buffer.isBuffer(buf)) |
|||
throw new Error('Input must be a buffer'); |
|||
var checkedBuf = new Buffer(buf.length + 4); |
|||
var hash = sha256sha256(buf); |
|||
buf.copy(checkedBuf); |
|||
hash.copy(checkedBuf, buf.length); |
|||
return base58.encode(checkedBuf); |
|||
}; |
|||
|
|||
Base58Check.prototype.fromBuffer = function(buf) { |
|||
this.buf = buf; |
|||
return this; |
|||
}; |
|||
|
|||
Base58Check.prototype.fromString = function(str) { |
|||
var buf = Base58Check.decode(str); |
|||
this.buf = buf; |
|||
return this; |
|||
}; |
|||
|
|||
Base58Check.prototype.toBuffer = function() { |
|||
return this.buf; |
|||
}; |
|||
|
|||
Base58Check.prototype.toString = function() { |
|||
return Base58Check.encode(this.buf); |
|||
}; |
|||
|
|||
module.exports = Base58Check; |
@ -0,0 +1,326 @@ |
|||
var Base58Check = require('./base58check'); |
|||
var Hash = require('./hash'); |
|||
var Keypair = require('./keypair'); |
|||
var Pubkey = require('./pubkey'); |
|||
var Privkey = require('./privkey'); |
|||
var Point = require('./point'); |
|||
var Random = require('./random'); |
|||
var BN = require('./bn'); |
|||
var constants = require('./constants'); |
|||
|
|||
var BIP32 = function BIP32(obj) { |
|||
if (!(this instanceof BIP32)) |
|||
return new BIP32(obj); |
|||
if (typeof obj === 'string') { |
|||
var str = obj; |
|||
this.fromString(str); |
|||
} else if (obj ) { |
|||
this.set(obj); |
|||
} |
|||
} |
|||
|
|||
BIP32.prototype.set = function(obj) { |
|||
this.version = typeof obj.version !== 'undefined' ? obj.version : this.version; |
|||
this.depth = typeof obj.depth !== 'undefined' ? obj.depth : this.depth; |
|||
this.parentfingerprint = obj.parentfingerprint || this.parentfingerprint; |
|||
this.childindex = obj.childindex || this.childindex; |
|||
this.chaincode = obj.chaincode || this.chaincode; |
|||
this.keypair = obj.keypair || this.keypair; |
|||
this.hasprivkey = typeof obj.hasprivkey !== 'undefined' ? obj.hasprivkey : this.hasprivkey; |
|||
this.pubkeyhash = obj.pubkeyhash || this.pubkeyhash; |
|||
this.xpubkey = obj.xpubkey || this.xpubkey; |
|||
this.xprivkey = obj.xprivkey || this.xprivkey; |
|||
return this; |
|||
}; |
|||
|
|||
BIP32.prototype.fromRandom = function(networkstr) { |
|||
if (!networkstr) |
|||
networkstr = 'mainnet'; |
|||
this.version = constants[networkstr].bip32privkey; |
|||
this.depth = 0x00; |
|||
this.parentfingerprint = new Buffer([0, 0, 0, 0]); |
|||
this.childindex = new Buffer([0, 0, 0, 0]); |
|||
this.chaincode = Random.getRandomBuffer(32); |
|||
this.keypair = (new Keypair()).fromRandom(); |
|||
this.hasprivkey = true; |
|||
this.pubkeyhash = Hash.sha256ripemd160(this.keypair.pubkey.toBuffer()); |
|||
this.buildxpubkey(); |
|||
this.buildxprivkey(); |
|||
}; |
|||
|
|||
BIP32.prototype.fromString = function(str) { |
|||
var bytes = Base58Check.decode(str); |
|||
this.initFromBytes(bytes); |
|||
return this; |
|||
}; |
|||
|
|||
BIP32.prototype.fromSeed = function(bytes, networkstr) { |
|||
if (!networkstr) |
|||
networkstr = 'mainnet'; |
|||
|
|||
if (!Buffer.isBuffer(bytes)) |
|||
throw new Error('bytes must be a buffer'); |
|||
if (bytes.length < 128 / 8) |
|||
throw new Error('Need more than 128 bytes of entropy'); |
|||
if (bytes.length > 512 / 8) |
|||
throw new Error('More than 512 bytes of entropy is nonstandard'); |
|||
var hash = Hash.sha512hmac(bytes, new Buffer('Bitcoin seed')); |
|||
|
|||
this.depth = 0x00; |
|||
this.parentfingerprint = new Buffer([0, 0, 0, 0]); |
|||
this.childindex = new Buffer([0, 0, 0, 0]); |
|||
this.chaincode = hash.slice(32, 64); |
|||
this.version = constants[networkstr].bip32privkey; |
|||
this.keypair = new Keypair(); |
|||
this.keypair.privkey = new Privkey({bn: BN().fromBuffer(hash.slice(0, 32))}); |
|||
this.keypair.privkey2pubkey(); |
|||
this.hasprivkey = true; |
|||
this.pubkeyhash = Hash.sha256ripemd160(this.keypair.pubkey.toBuffer()); |
|||
|
|||
this.buildxpubkey(); |
|||
this.buildxprivkey(); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
BIP32.prototype.initFromBytes = function(bytes) { |
|||
// Both pub and private extended keys are 78 bytes
|
|||
if (bytes.length != 78) |
|||
throw new Error('not enough data'); |
|||
|
|||
this.version = bytes.slice(0, 4).readUInt32BE(0); |
|||
this.depth = bytes.slice(4, 5).readUInt8(0); |
|||
this.parentfingerprint = bytes.slice(5, 9); |
|||
this.childindex = bytes.slice(9, 13).readUInt32BE(0); |
|||
this.chaincode = bytes.slice(13, 45); |
|||
|
|||
var keyBytes = bytes.slice(45, 78); |
|||
|
|||
var isPrivate = |
|||
(this.version == constants.mainnet.bip32privkey || |
|||
this.version == constants.testnet.bip32privkey); |
|||
|
|||
var isPublic = |
|||
(this.version == constants.mainnet.bip32pubkey || |
|||
this.version == constants.testnet.bip32pubkey); |
|||
|
|||
if (isPrivate && keyBytes[0] == 0) { |
|||
this.keypair = new Keypair(); |
|||
this.keypair.privkey = new Privkey({bn: BN().fromBuffer(keyBytes.slice(1, 33))}); |
|||
this.keypair.privkey2pubkey(); |
|||
this.pubkeyhash = Hash.sha256ripemd160(this.keypair.pubkey.toBuffer()); |
|||
this.hasprivkey = true; |
|||
} else if (isPublic && (keyBytes[0] == 0x02 || keyBytes[0] == 0x03)) { |
|||
this.keypair = new Keypair(); |
|||
this.keypair.pubkey = (new Pubkey()).fromDER(keyBytes); |
|||
this.pubkeyhash = Hash.sha256ripemd160(this.keypair.pubkey.toBuffer()); |
|||
this.hasprivkey = false; |
|||
} else { |
|||
throw new Error('Invalid key'); |
|||
} |
|||
|
|||
this.buildxpubkey(); |
|||
this.buildxprivkey(); |
|||
} |
|||
|
|||
BIP32.prototype.buildxpubkey = function() { |
|||
this.xpubkey = new Buffer([]); |
|||
|
|||
var v = null; |
|||
switch (this.version) { |
|||
case constants.mainnet.bip32pubkey: |
|||
case constants.mainnet.bip32privkey: |
|||
v = constants.mainnet.bip32pubkey; |
|||
break; |
|||
case constants.testnet.bip32pubkey: |
|||
case constants.testnet.bip32privkey: |
|||
v = constants.testnet.bip32pubkey; |
|||
break; |
|||
default: |
|||
throw new Error('Unknown version'); |
|||
} |
|||
|
|||
// Version
|
|||
this.xpubkey = Buffer.concat([ |
|||
new Buffer([v >> 24]), |
|||
new Buffer([(v >> 16) & 0xff]), |
|||
new Buffer([(v >> 8) & 0xff]), |
|||
new Buffer([v & 0xff]), |
|||
new Buffer([this.depth]), |
|||
this.parentfingerprint, |
|||
new Buffer([this.childindex >>> 24]), |
|||
new Buffer([(this.childindex >>> 16) & 0xff]), |
|||
new Buffer([(this.childindex >>> 8) & 0xff]), |
|||
new Buffer([this.childindex & 0xff]), |
|||
this.chaincode, |
|||
this.keypair.pubkey.toBuffer() |
|||
]); |
|||
} |
|||
|
|||
BIP32.prototype.xpubkeyString = function(format) { |
|||
if (format === undefined || format === 'base58') { |
|||
return Base58Check.encode(this.xpubkey); |
|||
} else if (format === 'hex') { |
|||
return this.xpubkey.toString('hex'); |
|||
} else { |
|||
throw new Error('bad format'); |
|||
} |
|||
} |
|||
|
|||
BIP32.prototype.buildxprivkey = function() { |
|||
if (!this.hasprivkey) return; |
|||
this.xprivkey = new Buffer([]); |
|||
|
|||
var v = this.version; |
|||
|
|||
this.xprivkey = Buffer.concat([ |
|||
new Buffer([v >> 24]), |
|||
new Buffer([(v >> 16) & 0xff]), |
|||
new Buffer([(v >> 8) & 0xff]), |
|||
new Buffer([v & 0xff]), |
|||
new Buffer([this.depth]), |
|||
this.parentfingerprint, |
|||
new Buffer([this.childindex >>> 24]), |
|||
new Buffer([(this.childindex >>> 16) & 0xff]), |
|||
new Buffer([(this.childindex >>> 8) & 0xff]), |
|||
new Buffer([this.childindex & 0xff]), |
|||
this.chaincode, |
|||
new Buffer([0]), |
|||
this.keypair.privkey.bn.toBuffer({size: 32}) |
|||
]); |
|||
} |
|||
|
|||
BIP32.prototype.xprivkeyString = function(format) { |
|||
if (format === undefined || format === 'base58') { |
|||
return Base58Check.encode(this.xprivkey); |
|||
} else if (format === 'hex') { |
|||
return this.xprivkey.toString('hex'); |
|||
} else { |
|||
throw new Error('bad format'); |
|||
} |
|||
} |
|||
|
|||
|
|||
BIP32.prototype.derive = function(path) { |
|||
var e = path.split('/'); |
|||
|
|||
// Special cases:
|
|||
if (path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'') |
|||
return this; |
|||
|
|||
var bip32 = this; |
|||
for (var i in e) { |
|||
var c = e[i]; |
|||
|
|||
if (i == 0) { |
|||
if (c != 'm') throw new Error('invalid path'); |
|||
continue; |
|||
} |
|||
|
|||
if (parseInt(c.replace("'", "")).toString() !== c.replace("'", "")) |
|||
throw new Error('invalid path'); |
|||
|
|||
var usePrivate = (c.length > 1) && (c[c.length - 1] == '\''); |
|||
var childindex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff; |
|||
|
|||
if (usePrivate) |
|||
childindex += 0x80000000; |
|||
|
|||
bip32 = bip32.deriveChild(childindex); |
|||
} |
|||
|
|||
return bip32; |
|||
} |
|||
|
|||
BIP32.prototype.deriveChild = function(i) { |
|||
if (typeof i !== 'number') |
|||
throw new Error('i must be a number'); |
|||
|
|||
var ib = []; |
|||
ib.push((i >> 24) & 0xff); |
|||
ib.push((i >> 16) & 0xff); |
|||
ib.push((i >> 8) & 0xff); |
|||
ib.push(i & 0xff); |
|||
ib = new Buffer(ib); |
|||
|
|||
var usePrivate = (i & 0x80000000) != 0; |
|||
|
|||
var isPrivate = |
|||
(this.version == constants.mainnet.bip32privkey || |
|||
this.version == constants.testnet.bip32privkey); |
|||
|
|||
if (usePrivate && (!this.hasprivkey || !isPrivate)) |
|||
throw new Error('Cannot do private key derivation without private key'); |
|||
|
|||
var ret = null; |
|||
if (this.hasprivkey) { |
|||
var data = null; |
|||
|
|||
if (usePrivate) { |
|||
data = Buffer.concat([new Buffer([0]), this.keypair.privkey.bn.toBuffer({size: 32}), ib]); |
|||
} else { |
|||
data = Buffer.concat([this.keypair.pubkey.toBuffer({size: 32}), ib]); |
|||
} |
|||
|
|||
var hash = Hash.sha512hmac(data, this.chaincode); |
|||
var il = BN().fromBuffer(hash.slice(0, 32), {size: 32}); |
|||
var ir = hash.slice(32, 64); |
|||
|
|||
// ki = IL + kpar (mod n).
|
|||
var k = il.add(this.keypair.privkey.bn).mod(Point.getN()); |
|||
|
|||
ret = new BIP32(); |
|||
ret.chaincode = ir; |
|||
|
|||
ret.keypair = new Keypair(); |
|||
ret.keypair.privkey = new Privkey({bn: k}); |
|||
ret.keypair.privkey2pubkey(); |
|||
ret.hasprivkey = true; |
|||
|
|||
} else { |
|||
var data = Buffer.concat([this.keypair.pubkey.toBuffer(), ib]); |
|||
var hash = Hash.sha512hmac(data, this.chaincode); |
|||
var il = BN().fromBuffer(hash.slice(0, 32)); |
|||
var ir = hash.slice(32, 64); |
|||
|
|||
// Ki = (IL + kpar)*G = IL*G + Kpar
|
|||
var ilG = Point.getG().mul(il); |
|||
var Kpar = this.keypair.pubkey.point; |
|||
var Ki = ilG.add(Kpar); |
|||
var newpub = new Pubkey(); |
|||
newpub.point = Ki; |
|||
|
|||
ret = new BIP32(); |
|||
ret.chaincode = ir; |
|||
|
|||
var keypair = new Keypair(); |
|||
keypair.pubkey = newpub; |
|||
ret.keypair = keypair; |
|||
ret.hasprivkey = false; |
|||
} |
|||
|
|||
ret.childindex = i; |
|||
ret.parentfingerprint = this.pubkeyhash.slice(0, 4); |
|||
ret.version = this.version; |
|||
ret.depth = this.depth + 1; |
|||
|
|||
ret.pubkeyhash = Hash.sha256ripemd160(ret.keypair.pubkey.toBuffer()); |
|||
|
|||
ret.buildxpubkey(); |
|||
ret.buildxprivkey(); |
|||
|
|||
return ret; |
|||
} |
|||
|
|||
BIP32.prototype.toString = function() { |
|||
var isPrivate = |
|||
(this.version == constants.mainnet.bip32privkey || |
|||
this.version == constants.testnet.bip32privkey); |
|||
|
|||
if (isPrivate) |
|||
return this.xprivkeyString(); |
|||
else |
|||
return this.xpubkeyString(); |
|||
}; |
|||
|
|||
module.exports = BIP32; |
@ -0,0 +1,108 @@ |
|||
var Transaction = require('./transaction'); |
|||
var BufferReader = require('./bufferreader'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var Blockheader = require('./blockheader'); |
|||
var Varint = require('./varint'); |
|||
var Hash = require('./hash'); |
|||
|
|||
var Block = function Block(magicnum, blocksize, blockheader, txsvi, txs) { |
|||
if (!(this instanceof Block)) |
|||
return new Block(magicnum, blocksize, blockheader, txsvi, txs); |
|||
if (typeof magicnum === 'number') { |
|||
this.set({ |
|||
magicnum: magicnum, |
|||
blocksize: blocksize, |
|||
blockheader: blockheader, |
|||
txsvi: txsvi, |
|||
txs: txs |
|||
}); |
|||
} else if (Buffer.isBuffer(magicnum)) { |
|||
var blockbuf = magicnum; |
|||
this.fromBuffer(blockbuf); |
|||
} else if (magicnum) { |
|||
var obj = magicnum; |
|||
} |
|||
}; |
|||
|
|||
Block.prototype.set = function(obj) { |
|||
this.magicnum = typeof obj.magicnum !== 'undefined' ? obj.magicnum : this.magicnum; |
|||
this.blocksize = typeof obj.blocksize !== 'undefined' ? obj.blocksize : this.blocksize; |
|||
this.blockheader = obj.blockheader || this.blockheader; |
|||
this.txsvi = obj.txsvi || this.txsvi; |
|||
this.txs = obj.txs || this.txs; |
|||
return this; |
|||
}; |
|||
|
|||
Block.prototype.fromJSON = function(json) { |
|||
var txs = []; |
|||
json.txs.forEach(function(tx) { |
|||
txs.push(Transaction().fromJSON(tx)); |
|||
}); |
|||
this.set({ |
|||
magicnum: json.magicnum, |
|||
blocksize: json.blocksize, |
|||
blockheader: Blockheader().fromJSON(json.blockheader), |
|||
txsvi: Varint().fromJSON(json.txsvi), |
|||
txs: txs |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Block.prototype.toJSON = function() { |
|||
var txs = []; |
|||
this.txs.forEach(function(tx) { |
|||
txs.push(tx.toJSON()); |
|||
}); |
|||
return { |
|||
magicnum: this.magicnum, |
|||
blocksize: this.blocksize, |
|||
blockheader: this.blockheader.toJSON(), |
|||
txsvi: this.txsvi.toJSON(), |
|||
txs: txs |
|||
}; |
|||
}; |
|||
|
|||
Block.prototype.fromBuffer = function(buf) { |
|||
return this.fromBufferReader(BufferReader(buf)); |
|||
}; |
|||
|
|||
Block.prototype.fromBufferReader = function(br) { |
|||
this.magicnum = br.readUInt32LE(); |
|||
this.blocksize = br.readUInt32LE(); |
|||
this.blockheader = Blockheader().fromBufferReader(br); |
|||
this.txsvi = Varint(br.readVarintBuf()); |
|||
var txslen = this.txsvi.toNumber(); |
|||
this.txs = []; |
|||
for (var i = 0; i < txslen; i++) { |
|||
this.txs.push(Transaction().fromBufferReader(br)); |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
Block.prototype.toBuffer = function() { |
|||
return this.toBufferWriter().concat(); |
|||
}; |
|||
|
|||
Block.prototype.toBufferWriter = function(bw) { |
|||
if (!bw) |
|||
bw = new BufferWriter(); |
|||
bw.writeUInt32LE(this.magicnum); |
|||
bw.writeUInt32LE(this.blocksize); |
|||
bw.write(this.blockheader.toBuffer()); |
|||
bw.write(this.txsvi.buf); |
|||
var txslen = this.txsvi.toNumber(); |
|||
for (var i = 0; i < txslen; i++) { |
|||
this.txs[i].toBufferWriter(bw); |
|||
} |
|||
return bw; |
|||
}; |
|||
|
|||
Block.prototype.hash = function() { |
|||
return Hash.sha256sha256(this.blockheader.toBuffer()); |
|||
}; |
|||
|
|||
Block.prototype.id = function() { |
|||
return BufferReader(this.hash()).reverse().read(); |
|||
}; |
|||
|
|||
module.exports = Block; |
@ -0,0 +1,88 @@ |
|||
var BufferReader = require('./bufferreader'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
|
|||
var Blockheader = function Blockheader(version, prevblockidbuf, merklerootbuf, time, bits, nonce) { |
|||
if (!(this instanceof Blockheader)) |
|||
return new Blockheader(version, prevblockidbuf, merklerootbuf, time, bits, nonce); |
|||
if (typeof version === 'number') { |
|||
this.set({ |
|||
version: version, |
|||
prevblockidbuf: prevblockidbuf, |
|||
merklerootbuf: merklerootbuf, |
|||
time: time, |
|||
bits: bits, |
|||
nonce: nonce |
|||
}); |
|||
} else if (Buffer.isBuffer(version)) { |
|||
var bhbuf = version; |
|||
this.fromBuffer(bhbuf); |
|||
} else if (version) { |
|||
var obj = version; |
|||
this.set(obj); |
|||
} |
|||
} |
|||
|
|||
Blockheader.prototype.set = function(obj) { |
|||
this.version = typeof obj.version !== 'undefined' ? obj.version : this.version; |
|||
this.prevblockidbuf = obj.prevblockidbuf || this.prevblockidbuf; |
|||
this.merklerootbuf = obj.merklerootbuf || this.merklerootbuf; |
|||
this.time = typeof obj.time !== 'undefined' ? obj.time : this.time; |
|||
this.bits = typeof obj.bits !== 'undefined' ? obj.bits : this.bits; |
|||
this.nonce = typeof obj.nonce !== 'undefined' ? obj.nonce : this.nonce; |
|||
return this; |
|||
}; |
|||
|
|||
Blockheader.prototype.fromJSON = function(json) { |
|||
this.set({ |
|||
version: json.version, |
|||
prevblockidbuf: new Buffer(json.prevblockidbuf, 'hex'), |
|||
merklerootbuf: new Buffer(json.merklerootbuf, 'hex'), |
|||
time: json.time, |
|||
bits: json.bits, |
|||
nonce: json.nonce |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Blockheader.prototype.toJSON = function() { |
|||
return { |
|||
version: this.version, |
|||
prevblockidbuf: this.prevblockidbuf.toString('hex'), |
|||
merklerootbuf: this.merklerootbuf.toString('hex'), |
|||
time: this.time, |
|||
bits: this.bits, |
|||
nonce: this.nonce |
|||
}; |
|||
}; |
|||
|
|||
Blockheader.prototype.fromBuffer = function(buf) { |
|||
return this.fromBufferReader(BufferReader(buf)); |
|||
}; |
|||
|
|||
Blockheader.prototype.fromBufferReader = function(br) { |
|||
this.version = br.readUInt32LE(); |
|||
this.prevblockidbuf = br.read(32); |
|||
this.merklerootbuf = br.read(32); |
|||
this.time = br.readUInt32LE(); |
|||
this.bits = br.readUInt32LE(); |
|||
this.nonce = br.readUInt32LE(); |
|||
return this; |
|||
}; |
|||
|
|||
Blockheader.prototype.toBuffer = function() { |
|||
return this.toBufferWriter().concat(); |
|||
}; |
|||
|
|||
Blockheader.prototype.toBufferWriter = function(bw) { |
|||
if (!bw) |
|||
bw = new BufferWriter(); |
|||
bw.writeUInt32LE(this.version); |
|||
bw.write(this.prevblockidbuf); |
|||
bw.write(this.merklerootbuf); |
|||
bw.writeUInt32LE(this.time); |
|||
bw.writeUInt32LE(this.bits); |
|||
bw.writeUInt32LE(this.nonce); |
|||
return bw; |
|||
}; |
|||
|
|||
module.exports = Blockheader; |
@ -0,0 +1,132 @@ |
|||
var _BN = require('bn.js'); |
|||
|
|||
var BN = function BN_extended(n) { |
|||
if (!(this instanceof BN_extended)) { |
|||
return new BN(n); |
|||
} |
|||
arguments[0] = n; |
|||
return _BN.apply(this, arguments); |
|||
}; |
|||
|
|||
module.exports = BN; |
|||
|
|||
BN.prototype = _BN.prototype; |
|||
|
|||
var reversebuf = function(buf, nbuf) { |
|||
for (var i = 0; i < buf.length; i++) { |
|||
nbuf[i] = buf[buf.length-1-i]; |
|||
} |
|||
}; |
|||
|
|||
BN.prototype.toJSON = function() { |
|||
return this.toString(); |
|||
}; |
|||
|
|||
BN.prototype.fromJSON = function(str) { |
|||
var bn = BN(str); |
|||
bn.copy(this); |
|||
return this; |
|||
}; |
|||
|
|||
BN.prototype.fromString = function(str) { |
|||
var bn = BN(str); |
|||
bn.copy(this); |
|||
return this; |
|||
}; |
|||
|
|||
BN.fromBuffer = function(buf, opts) { |
|||
if (typeof opts !== 'undefined' && opts.endian === 'little') { |
|||
var nbuf = new Buffer(buf.length); |
|||
reversebuf(buf, nbuf); |
|||
buf = nbuf; |
|||
} |
|||
var hex = buf.toString('hex'); |
|||
if (hex.length % 2) |
|||
hex = "0" + hex; |
|||
var bn = new BN(hex, 16); |
|||
return bn; |
|||
}; |
|||
|
|||
BN.prototype.fromBuffer = function(buf, opts) { |
|||
var bn = BN.fromBuffer(buf, opts); |
|||
bn.copy(this); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
BN.prototype.toBuffer = function(opts) { |
|||
var buf; |
|||
if (opts && opts.size) { |
|||
var hex = this.toString(16); |
|||
if (hex.length % 2) |
|||
hex = "0" + hex; |
|||
var natlen = hex.length/2; |
|||
buf = new Buffer(hex, 'hex'); |
|||
|
|||
if (natlen == opts.size) |
|||
buf = buf; |
|||
|
|||
else if (natlen > opts.size) { |
|||
buf = buf.slice(natlen - buf.length, buf.length); |
|||
} |
|||
|
|||
else if (natlen < opts.size) { |
|||
var rbuf = new Buffer(opts.size); |
|||
//rbuf.fill(0);
|
|||
for (var i = 0; i < buf.length; i++) |
|||
rbuf[rbuf.length-1-i] = buf[buf.length-1-i]; |
|||
for (var i = 0; i < opts.size - natlen; i++) |
|||
rbuf[i] = 0; |
|||
buf = rbuf; |
|||
} |
|||
} |
|||
else { |
|||
var hex = this.toString(16); |
|||
if (hex.length % 2) |
|||
hex = "0" + hex; |
|||
buf = new Buffer(hex, 'hex'); |
|||
} |
|||
|
|||
if (typeof opts !== 'undefined' && opts.endian === 'little') { |
|||
var nbuf = new Buffer(buf.length); |
|||
reversebuf(buf, nbuf); |
|||
buf = nbuf; |
|||
} |
|||
|
|||
return buf; |
|||
}; |
|||
|
|||
function decorate(name) { |
|||
BN.prototype['_' + name] = _BN.prototype[name]; |
|||
var f = function(b) { |
|||
if (typeof b === 'string') |
|||
b = new _BN(b); |
|||
else if (typeof b === 'number') |
|||
b = new _BN(b.toString()); |
|||
return this['_' + name](b); |
|||
}; |
|||
BN.prototype[name] = f; |
|||
}; |
|||
|
|||
_BN.prototype.gt = function(b) { |
|||
return this.cmp(b) > 0; |
|||
}; |
|||
|
|||
_BN.prototype.lt = function(b) { |
|||
return this.cmp(b) < 0; |
|||
}; |
|||
|
|||
decorate('add'); |
|||
decorate('sub'); |
|||
decorate('mul'); |
|||
decorate('mod'); |
|||
decorate('div'); |
|||
decorate('cmp'); |
|||
decorate('gt'); |
|||
decorate('lt'); |
|||
|
|||
BN.prototype.toNumber = function() { |
|||
return parseInt(this['toString'](10), 10); |
|||
}; |
|||
|
|||
module.exports = BN; |
@ -0,0 +1,133 @@ |
|||
var BN = require('./bn'); |
|||
|
|||
var BufferReader = function BufferReader(buf) { |
|||
if (!(this instanceof BufferReader)) |
|||
return new BufferReader(buf); |
|||
if (Buffer.isBuffer(buf)) { |
|||
this.set({buf: buf}); |
|||
} |
|||
else if (buf) { |
|||
var obj = buf; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
BufferReader.prototype.set = function(obj) { |
|||
this.buf = obj.buf || this.buf || undefined; |
|||
this.pos = obj.pos || this.pos || 0; |
|||
return this; |
|||
}; |
|||
|
|||
BufferReader.prototype.eof = function() { |
|||
return this.pos >= this.buf.length; |
|||
}; |
|||
|
|||
BufferReader.prototype.read = function(len) { |
|||
if (!len) |
|||
var len = this.buf.length; |
|||
var buf = this.buf.slice(this.pos, this.pos + len); |
|||
this.pos = this.pos + len; |
|||
return buf; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt8 = function() { |
|||
var val = this.buf.readUInt8(this.pos); |
|||
this.pos = this.pos + 1; |
|||
return val; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt16BE = function() { |
|||
var val = this.buf.readUInt16BE(this.pos); |
|||
this.pos = this.pos + 2; |
|||
return val; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt16LE = function() { |
|||
var val = this.buf.readUInt16LE(this.pos); |
|||
this.pos = this.pos + 2; |
|||
return val; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt32BE = function() { |
|||
var val = this.buf.readUInt32BE(this.pos); |
|||
this.pos = this.pos + 4; |
|||
return val; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt32LE = function() { |
|||
var val = this.buf.readUInt32LE(this.pos); |
|||
this.pos = this.pos + 4; |
|||
return val; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt64BEBN = function() { |
|||
var buf = this.buf.slice(this.pos, this.pos + 8); |
|||
var bn = BN().fromBuffer(buf); |
|||
this.pos = this.pos + 8; |
|||
return bn; |
|||
}; |
|||
|
|||
BufferReader.prototype.readUInt64LEBN = function() { |
|||
var buf = this.buf.slice(this.pos, this.pos + 8); |
|||
var reversebuf = BufferReader({buf: buf}).reverse().read(); |
|||
var bn = BN().fromBuffer(reversebuf); |
|||
this.pos = this.pos + 8; |
|||
return bn; |
|||
}; |
|||
|
|||
BufferReader.prototype.readVarintNum = function() { |
|||
var first = this.readUInt8(); |
|||
switch (first) { |
|||
case 0xFD: |
|||
return this.readUInt16LE(); |
|||
case 0xFE: |
|||
return this.readUInt32LE(); |
|||
case 0xFF: |
|||
var bn = this.readUInt64LEBN(); |
|||
var n = bn.toNumber(); |
|||
if (n <= Math.pow(2, 53)) |
|||
return n; |
|||
else |
|||
throw new Error('number too large to retain precision - use readVarintBN'); |
|||
default: |
|||
return first; |
|||
} |
|||
}; |
|||
|
|||
BufferReader.prototype.readVarintBuf = function() { |
|||
var first = this.buf.readUInt8(this.pos); |
|||
switch (first) { |
|||
case 0xFD: |
|||
return this.read(1 + 2); |
|||
case 0xFE: |
|||
return this.read(1 + 4); |
|||
case 0xFF: |
|||
return this.read(1 + 8); |
|||
default: |
|||
return this.read(1); |
|||
} |
|||
}; |
|||
|
|||
BufferReader.prototype.readVarintBN = function() { |
|||
var first = this.readUInt8(); |
|||
switch (first) { |
|||
case 0xFD: |
|||
return BN(this.readUInt16LE()); |
|||
case 0xFE: |
|||
return BN(this.readUInt32LE()); |
|||
case 0xFF: |
|||
return this.readUInt64LEBN(); |
|||
default: |
|||
return BN(first); |
|||
} |
|||
}; |
|||
|
|||
BufferReader.prototype.reverse = function() { |
|||
var buf = new Buffer(this.buf.length); |
|||
for (var i = 0; i < buf.length; i++) |
|||
buf[i] = this.buf[this.buf.length - 1 - i]; |
|||
this.buf = buf; |
|||
return this; |
|||
}; |
|||
|
|||
module.exports = BufferReader; |
@ -0,0 +1,135 @@ |
|||
var BN = require('./bn'); |
|||
|
|||
var BufferWriter = function BufferWriter(obj) { |
|||
if (!(this instanceof BufferWriter)) |
|||
return new BufferWriter(obj); |
|||
if (obj) |
|||
this.set(obj); |
|||
else |
|||
this.bufs = []; |
|||
}; |
|||
|
|||
BufferWriter.prototype.set = function(obj) { |
|||
this.bufs = obj.bufs || this.bufs || []; |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.toBuffer = function() { |
|||
return this.concat(); |
|||
}; |
|||
|
|||
BufferWriter.prototype.concat = function() { |
|||
return Buffer.concat(this.bufs); |
|||
}; |
|||
|
|||
BufferWriter.prototype.write = function(buf) { |
|||
this.bufs.push(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt8 = function(n) { |
|||
var buf = new Buffer(1); |
|||
buf.writeUInt8(n, 0); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt16BE = function(n) { |
|||
var buf = new Buffer(2); |
|||
buf.writeUInt16BE(n, 0); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt16LE = function(n) { |
|||
var buf = new Buffer(2); |
|||
buf.writeUInt16LE(n, 0); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt32BE = function(n) { |
|||
var buf = new Buffer(4); |
|||
buf.writeUInt32BE(n, 0); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt32LE = function(n) { |
|||
var buf = new Buffer(4); |
|||
buf.writeUInt32LE(n, 0); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt64BEBN = function(bn) { |
|||
var buf = bn.toBuffer({size: 8}); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeUInt64LEBN = function(bn) { |
|||
var buf = bn.toBuffer({size: 8}); |
|||
var reversebuf = new Buffer(Array.apply(new Array(), buf).reverse()); |
|||
this.write(reversebuf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeVarintNum = function(n) { |
|||
var buf = BufferWriter.varintBufNum(n); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.prototype.writeVarintBN = function(bn) { |
|||
var buf = BufferWriter.varintBufBN(bn); |
|||
this.write(buf); |
|||
return this; |
|||
}; |
|||
|
|||
BufferWriter.varintBufNum = function(n) { |
|||
var buf = undefined; |
|||
if (n < 253) { |
|||
buf = new Buffer(1); |
|||
buf.writeUInt8(n, 0); |
|||
} else if (n < 0x10000) { |
|||
buf = new Buffer(1 + 2); |
|||
buf.writeUInt8(253, 0); |
|||
buf.writeUInt16LE(n, 1); |
|||
} else if (n < 0x100000000) { |
|||
buf = new Buffer(1 + 4); |
|||
buf.writeUInt8(254, 0); |
|||
buf.writeUInt32LE(n, 1); |
|||
} else { |
|||
buf = new Buffer(1 + 8); |
|||
buf.writeUInt8(255, 0); |
|||
buf.writeInt32LE(n & -1, 1); |
|||
buf.writeUInt32LE(Math.floor(n / 0x100000000), 5); |
|||
} |
|||
return buf; |
|||
}; |
|||
|
|||
BufferWriter.varintBufBN = function(bn) { |
|||
var buf = undefined; |
|||
var n = bn.toNumber(); |
|||
if (n < 253) { |
|||
buf = new Buffer(1); |
|||
buf.writeUInt8(n, 0); |
|||
} else if (n < 0x10000) { |
|||
buf = new Buffer(1 + 2); |
|||
buf.writeUInt8(253, 0); |
|||
buf.writeUInt16LE(n, 1); |
|||
} else if (n < 0x100000000) { |
|||
buf = new Buffer(1 + 4); |
|||
buf.writeUInt8(254, 0); |
|||
buf.writeUInt32LE(n, 1); |
|||
} else { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt8(255); |
|||
bw.writeUInt64LEBN(bn); |
|||
var buf = bw.concat(); |
|||
} |
|||
return buf; |
|||
}; |
|||
|
|||
module.exports = BufferWriter; |
@ -0,0 +1,15 @@ |
|||
exports.mainnet = { |
|||
pubkeyhash: 0x00, |
|||
privkey: 0x80, |
|||
scripthash: 0x05, |
|||
bip32pubkey: 0x0488b21e, |
|||
bip32privkey: 0x0488ade4, |
|||
}; |
|||
|
|||
exports.testnet = { |
|||
pubkeyhash: 0x6f, |
|||
privkey: 0xef, |
|||
scripthash: 0xc4, |
|||
bip32pubkey: 0x043587cf, |
|||
bip32privkey: 0x04358394, |
|||
}; |
@ -0,0 +1,216 @@ |
|||
var BN = require('./bn'); |
|||
var Point = require('./point'); |
|||
var Signature = require('./signature'); |
|||
var Keypair = require('./keypair'); |
|||
var Pubkey = require('./pubkey'); |
|||
var Random = require('./random'); |
|||
|
|||
var ECDSA = function ECDSA(obj) { |
|||
if (!(this instanceof ECDSA)) |
|||
return new ECDSA(obj); |
|||
if (obj) |
|||
this.set(obj); |
|||
}; |
|||
|
|||
ECDSA.prototype.set = function(obj) { |
|||
this.hashbuf = obj.hashbuf || this.hashbuf; |
|||
this.keypair = obj.keypair || this.keypair; |
|||
this.sig = obj.sig || this.sig; |
|||
this.k = obj.k || this.k; |
|||
this.verified = obj.verified || this.verified; |
|||
return this; |
|||
}; |
|||
|
|||
ECDSA.prototype.calci = function() { |
|||
for (var i = 0; i < 4; i++) { |
|||
this.sig.i = i; |
|||
try { |
|||
var Qprime = this.sig2pubkey(); |
|||
} catch (e) { |
|||
continue; |
|||
} |
|||
|
|||
if (Qprime.point.eq(this.keypair.pubkey.point)) { |
|||
this.sig.compressed = this.keypair.pubkey.compressed; |
|||
return this; |
|||
} |
|||
} |
|||
|
|||
this.sig.i = undefined; |
|||
throw new Error('Unable to find valid recovery factor'); |
|||
}; |
|||
|
|||
ECDSA.prototype.fromString = function(str) { |
|||
var obj = JSON.parse(str); |
|||
if (obj.hashbuf) |
|||
this.hashbuf = new Buffer(obj.hashbuf, 'hex'); |
|||
if (obj.keypair) |
|||
this.keypair = Keypair().fromString(obj.keypair); |
|||
if (obj.sig) |
|||
this.sig = Signature().fromString(obj.sig); |
|||
if (obj.k) |
|||
this.k = BN(obj.k, 10); |
|||
return this; |
|||
}; |
|||
|
|||
ECDSA.prototype.randomK = function() { |
|||
var N = Point.getN(); |
|||
var k; |
|||
do { |
|||
k = BN().fromBuffer(Random.getRandomBuffer(32)); |
|||
} while (!(k.lt(N) && k.gt(0))); |
|||
this.k = k; |
|||
return this; |
|||
}; |
|||
|
|||
// Information about public key recovery:
|
|||
// https://bitcointalk.org/index.php?topic=6430.0
|
|||
// http://stackoverflow.com/questions/19665491/how-do-i-get-an-ecdsa-public-key-from-just-a-bitcoin-signature-sec1-4-1-6-k
|
|||
ECDSA.prototype.sig2pubkey = function() { |
|||
var i = this.sig.i; |
|||
if (!(i === 0 || i === 1 || i === 2 || i === 3)) |
|||
throw new Error('i must be equal to 0, 1, 2, or 3'); |
|||
|
|||
var e = BN().fromBuffer(this.hashbuf); |
|||
var r = this.sig.r; |
|||
var s = this.sig.s; |
|||
|
|||
// 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; |
|||
|
|||
var n = Point.getN(); |
|||
var G = Point.getG(); |
|||
|
|||
// 1.1 Let x = r + jn
|
|||
var x = isSecondKey ? r.add(n) : r; |
|||
var R = Point.fromX(isYOdd, x); |
|||
|
|||
// 1.4 Check that nR is at infinity
|
|||
var nR = R.mul(n); |
|||
|
|||
if (!nR.isInfinity()) |
|||
throw new Error('nR is not a valid curve point'); |
|||
|
|||
// Compute -e from e
|
|||
var eNeg = e.neg().mod(n); |
|||
|
|||
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
|||
// Q = r^-1 (sR + -eG)
|
|||
var rInv = r.invm(n); |
|||
|
|||
//var Q = R.multiplyTwo(s, G, eNeg).mul(rInv);
|
|||
var Q = R.mul(s).add(G.mul(eNeg)).mul(rInv); |
|||
|
|||
var pubkey = new Pubkey({point: Q}); |
|||
pubkey.compressed = this.sig.compressed; |
|||
pubkey.validate(); |
|||
|
|||
return pubkey; |
|||
}; |
|||
|
|||
ECDSA.prototype.sigError = function() { |
|||
if (!Buffer.isBuffer(this.hashbuf) || this.hashbuf.length !== 32) |
|||
return 'hashbuf must be a 32 byte buffer'; |
|||
|
|||
try { |
|||
this.keypair.pubkey.validate(); |
|||
} catch (e) { |
|||
return 'Invalid pubkey: ' + e; |
|||
} |
|||
|
|||
var r = this.sig.r; |
|||
var s = this.sig.s; |
|||
if (!(r.gt(0) && r.lt(Point.getN())) |
|||
|| !(s.gt(0) && s.lt(Point.getN()))) |
|||
return 'r and s not in range'; |
|||
|
|||
var e = BN().fromBuffer(this.hashbuf); |
|||
var n = Point.getN(); |
|||
var sinv = s.invm(n); |
|||
var u1 = sinv.mul(e).mod(n); |
|||
var u2 = sinv.mul(r).mod(n); |
|||
|
|||
var p = Point.getG().mulAdd(u1, this.keypair.pubkey.point, u2); |
|||
if (p.isInfinity()) |
|||
return 'p is infinity'; |
|||
|
|||
if (!(p.getX().mod(n).cmp(r) === 0)) |
|||
return 'Invalid signature'; |
|||
else |
|||
return false; |
|||
}; |
|||
|
|||
ECDSA.prototype.sign = function() { |
|||
var hashbuf = this.hashbuf; |
|||
var privkey = this.keypair.privkey; |
|||
var k = this.k; |
|||
var d = privkey.bn; |
|||
|
|||
if (!k) |
|||
throw new Error('You must specify k - perhaps you should run signRandomK instead'); |
|||
|
|||
if (!hashbuf || !privkey || !d) |
|||
throw new Error('invalid parameters'); |
|||
|
|||
if (!Buffer.isBuffer(hashbuf) || hashbuf.length !== 32) |
|||
throw new Error('hashbuf must be a 32 byte buffer'); |
|||
|
|||
var N = Point.getN(); |
|||
var G = Point.getG(); |
|||
var e = BN().fromBuffer(hashbuf); |
|||
|
|||
do { |
|||
var Q = G.mul(k); |
|||
var r = Q.x.mod(N); |
|||
var s = k.invm(N).mul(e.add(d.mul(r))).mod(N); |
|||
} while (r.cmp(0) <= 0 || s.cmp(0) <= 0); |
|||
|
|||
this.sig = new Signature({r: r, s: s, compressed: this.keypair.pubkey.compressed}); |
|||
return this.sig; |
|||
}; |
|||
|
|||
ECDSA.prototype.signRandomK = function() { |
|||
var k = this.randomK(); |
|||
return this.sign(); |
|||
}; |
|||
|
|||
ECDSA.prototype.toString = function() { |
|||
var obj = {}; |
|||
if (this.hashbuf) |
|||
obj.hashbuf = this.hashbuf.toString('hex'); |
|||
if (this.keypair) |
|||
obj.keypair = this.keypair.toString(); |
|||
if (this.sig) |
|||
obj.sig = this.sig.toString(); |
|||
if (this.k) |
|||
obj.k = this.k.toString(); |
|||
return JSON.stringify(obj); |
|||
}; |
|||
|
|||
ECDSA.prototype.verify = function() { |
|||
if (!this.sigError()) |
|||
return true; |
|||
else |
|||
return false; |
|||
}; |
|||
|
|||
ECDSA.sign = function(hashbuf, keypair) { |
|||
return ECDSA().set({ |
|||
hashbuf: hashbuf, |
|||
keypair: keypair |
|||
}).signRandomK(); |
|||
}; |
|||
|
|||
ECDSA.verify = function(hashbuf, sig, pubkey) { |
|||
return ECDSA().set({ |
|||
hashbuf: hashbuf, |
|||
sig: sig, |
|||
keypair: Keypair().set({pubkey: pubkey}) |
|||
}).verify(); |
|||
}; |
|||
|
|||
module.exports = ECDSA; |
@ -0,0 +1,47 @@ |
|||
var aes = require('aes'); |
|||
|
|||
var AES = function AES() { |
|||
}; |
|||
|
|||
AES.encrypt = function(messagebuf, keybuf) { |
|||
var key = AES.buf2words(keybuf); |
|||
var message = AES.buf2words(messagebuf); |
|||
var a = new aes(key); |
|||
var enc = a.encrypt(message); |
|||
var encbuf = AES.words2buf(enc); |
|||
return encbuf; |
|||
}; |
|||
|
|||
AES.decrypt = function(encbuf, keybuf) { |
|||
var enc = AES.buf2words(encbuf); |
|||
var key = AES.buf2words(keybuf); |
|||
var a = new aes(key); |
|||
var message = a.decrypt(enc); |
|||
var messagebuf = AES.words2buf(message); |
|||
return messagebuf; |
|||
}; |
|||
|
|||
AES.buf2words = function(buf) { |
|||
if (buf.length % 4) |
|||
throw new Error('buf length must be a multiple of 4'); |
|||
|
|||
var words = []; |
|||
|
|||
for (var i = 0; i < buf.length / 4; i++) { |
|||
words.push(buf.readUInt32BE(i * 4)); |
|||
}; |
|||
|
|||
return words; |
|||
}; |
|||
|
|||
AES.words2buf = function(words) { |
|||
var buf = new Buffer(words.length * 4); |
|||
|
|||
for (var i = 0; i < words.length; i++) { |
|||
buf.writeUInt32BE(words[i], i * 4); |
|||
}; |
|||
|
|||
return buf; |
|||
}; |
|||
|
|||
module.exports = AES; |
@ -0,0 +1,34 @@ |
|||
var AES = require('./aes'); |
|||
var CBC = require('./cbc'); |
|||
var Random = require('../random'); |
|||
var Hash = require('../hash'); |
|||
|
|||
// Symmetric encryption with AES and CBC convenience class
|
|||
var AESCBC = function AESCBC() { |
|||
}; |
|||
|
|||
AESCBC.encrypt = function(messagebuf, passwordstr) { |
|||
var cipherkeybuf = Hash.sha256(new Buffer(passwordstr)); |
|||
return AESCBC.encryptCipherkey(messagebuf, cipherkeybuf); |
|||
}; |
|||
|
|||
AESCBC.decrypt = function(encbuf, passwordstr) { |
|||
var cipherkeybuf = Hash.sha256(new Buffer(passwordstr)); |
|||
return AESCBC.decryptCipherkey(encbuf, cipherkeybuf); |
|||
}; |
|||
|
|||
AESCBC.encryptCipherkey = function(messagebuf, cipherkeybuf, ivbuf) { |
|||
ivbuf = ivbuf || Random.getRandomBuffer(128 / 8); |
|||
var ctbuf = CBC.encrypt(messagebuf, ivbuf, AES, cipherkeybuf); |
|||
var encbuf = Buffer.concat([ivbuf, ctbuf]); |
|||
return encbuf; |
|||
}; |
|||
|
|||
AESCBC.decryptCipherkey = function(encbuf, cipherkeybuf) { |
|||
var ivbuf = encbuf.slice(0, 128 / 8); |
|||
var ctbuf = encbuf.slice(128 / 8); |
|||
var messagebuf = CBC.decrypt(ctbuf, ivbuf, AES, cipherkeybuf); |
|||
return messagebuf; |
|||
}; |
|||
|
|||
module.exports = AESCBC; |
@ -0,0 +1,138 @@ |
|||
var Random = require('../random'); |
|||
|
|||
// Cipher Block Chaining
|
|||
// http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Cipher-block_chaining_.28CBC.29
|
|||
var CBC = function CBC(blockcipher, cipherkeybuf, ivbuf) { |
|||
if (!(this instanceof CBC)) |
|||
return new CBC(blockcipher, cipherkeybuf, ivbuf); |
|||
|
|||
this.blockcipher = blockcipher; |
|||
this.cipherkeybuf = cipherkeybuf; |
|||
this.ivbuf = ivbuf; |
|||
}; |
|||
|
|||
CBC.buf2blockbufs = function(buf, blocksize) { |
|||
var bytesize = blocksize / 8; |
|||
var blockbufs = []; |
|||
|
|||
for (var i = 0; i <= buf.length / bytesize; i++) { |
|||
var blockbuf = buf.slice(i * bytesize, i * bytesize + bytesize); |
|||
|
|||
if (blockbuf.length < blocksize) |
|||
blockbuf = CBC.pkcs7pad(blockbuf, blocksize); |
|||
|
|||
blockbufs.push(blockbuf); |
|||
} |
|||
|
|||
return blockbufs; |
|||
}; |
|||
|
|||
CBC.blockbufs2buf = function(blockbufs, blocksize) { |
|||
var bytesize = blocksize / 8; |
|||
|
|||
var last = blockbufs[blockbufs.length - 1]; |
|||
last = CBC.pkcs7unpad(last); |
|||
blockbufs[blockbufs.length - 1] = last; |
|||
|
|||
var buf = Buffer.concat(blockbufs); |
|||
|
|||
return buf; |
|||
}; |
|||
|
|||
CBC.encrypt = function(messagebuf, ivbuf, blockcipher, cipherkeybuf) { |
|||
var blocksize = ivbuf.length * 8; |
|||
var blockbufs = CBC.buf2blockbufs(messagebuf, blocksize); |
|||
var encbufs = CBC.encryptblocks(blockbufs, ivbuf, blockcipher, cipherkeybuf); |
|||
var encbuf = Buffer.concat(encbufs); |
|||
return encbuf; |
|||
}; |
|||
|
|||
CBC.decrypt = function(encbuf, ivbuf, blockcipher, cipherkeybuf) { |
|||
var blocksize = ivbuf.length * 8; |
|||
var bytesize = ivbuf.length; |
|||
var encbufs = []; |
|||
for (var i = 0; i < encbuf.length / bytesize; i++) { |
|||
encbufs.push(encbuf.slice(i * bytesize, i * bytesize + bytesize)); |
|||
} |
|||
var blockbufs = CBC.decryptblocks(encbufs, ivbuf, blockcipher, cipherkeybuf); |
|||
var buf = CBC.blockbufs2buf(blockbufs, blocksize); |
|||
return buf; |
|||
}; |
|||
|
|||
CBC.encryptblock = function(blockbuf, ivbuf, blockcipher, cipherkeybuf) { |
|||
var xorbuf = CBC.xorbufs(blockbuf, ivbuf); |
|||
var encbuf = blockcipher.encrypt(xorbuf, cipherkeybuf); |
|||
return encbuf; |
|||
}; |
|||
|
|||
CBC.decryptblock = function(encbuf, ivbuf, blockcipher, cipherkeybuf) { |
|||
var xorbuf = blockcipher.decrypt(encbuf, cipherkeybuf); |
|||
var blockbuf = CBC.xorbufs(xorbuf, ivbuf); |
|||
return blockbuf; |
|||
}; |
|||
|
|||
CBC.encryptblocks = function(blockbufs, ivbuf, blockcipher, cipherkeybuf) { |
|||
var encbufs = []; |
|||
|
|||
for (var i = 0; i < blockbufs.length; i++) { |
|||
var blockbuf = blockbufs[i]; |
|||
var encbuf = CBC.encryptblock(blockbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
|
|||
encbufs.push(encbuf); |
|||
|
|||
ivbuf = encbuf; |
|||
} |
|||
|
|||
return encbufs; |
|||
}; |
|||
|
|||
CBC.decryptblocks = function(encbufs, ivbuf, blockcipher, cipherkeybuf) { |
|||
var blockbufs = []; |
|||
|
|||
for (var i = 0; i < encbufs.length; i++) { |
|||
var encbuf = encbufs[i]; |
|||
var blockbuf = CBC.decryptblock(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
|
|||
blockbufs.push(blockbuf); |
|||
|
|||
ivbuf = encbuf; |
|||
} |
|||
|
|||
return blockbufs; |
|||
}; |
|||
|
|||
CBC.pkcs7pad = function(buf, blocksize) { |
|||
var bytesize = blocksize / 8; |
|||
var padbytesize = bytesize - buf.length; |
|||
var pad = new Buffer(padbytesize); |
|||
pad.fill(padbytesize); |
|||
var paddedbuf = Buffer.concat([buf, pad]); |
|||
return paddedbuf; |
|||
}; |
|||
|
|||
CBC.pkcs7unpad = function(paddedbuf, blocksize) { |
|||
var bytesize = blocksize / 8; |
|||
var padbytesize = bytesize - paddedbuf.length; |
|||
var padlength = paddedbuf[paddedbuf.length - 1]; |
|||
var padbuf = paddedbuf.slice(paddedbuf.length - padlength, paddedbuf.length); |
|||
var padbuf2 = new Buffer(padlength); |
|||
padbuf2.fill(padlength); |
|||
if (padbuf.toString('hex') !== padbuf2.toString('hex')) |
|||
throw new Error('invalid padding'); |
|||
return paddedbuf.slice(0, paddedbuf.length - padlength); |
|||
}; |
|||
|
|||
CBC.xorbufs = function(buf1, buf2) { |
|||
if (buf1.length !== buf2.length) |
|||
throw new Error('bufs must have the same length'); |
|||
|
|||
var buf = new Buffer(buf1.length); |
|||
|
|||
for (var i = 0; i < buf1.length; i++) { |
|||
buf[i] = buf1[i] ^ buf2[i]; |
|||
} |
|||
|
|||
return buf; |
|||
}; |
|||
|
|||
module.exports = CBC; |
@ -0,0 +1,55 @@ |
|||
var AESCBC = require('./aescbc'); |
|||
var Keypair = require('../keypair'); |
|||
var Point = require('../point'); |
|||
var Hash = require('../hash'); |
|||
var Pubkey = require('../pubkey'); |
|||
var Privkey = require('../privkey'); |
|||
|
|||
// http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme
|
|||
var ECIES = function ECIES() { |
|||
if (!(this instanceof ECIES)) |
|||
return new ECIES(); |
|||
}; |
|||
|
|||
ECIES.encrypt = function(messagebuf, topubkey, fromkeypair, ivbuf) { |
|||
if (!fromkeypair) |
|||
fromkeypair = Keypair().fromRandom(); |
|||
var r = fromkeypair.privkey.bn; |
|||
var R = fromkeypair.pubkey.point; |
|||
var Rpubkey = fromkeypair.pubkey; |
|||
var Rbuf = Rpubkey.toDER(true); |
|||
var KB = topubkey.point; |
|||
var P = KB.mul(r); |
|||
var S = P.getX(); |
|||
var Sbuf = S.toBuffer({size: 32}); |
|||
var kEkM = Hash.sha512(Sbuf); |
|||
var kE = kEkM.slice(0, 32); |
|||
var kM = kEkM.slice(32, 64); |
|||
var c = AESCBC.encryptCipherkey(messagebuf, kE, ivbuf); |
|||
var d = Hash.sha256hmac(c, kM); |
|||
var encbuf = Buffer.concat([Rbuf, c, d]); |
|||
return encbuf; |
|||
}; |
|||
|
|||
ECIES.decrypt = function(encbuf, toprivkey) { |
|||
var kB = toprivkey.bn; |
|||
var frompubkey = Pubkey().fromDER(encbuf.slice(0, 33)); |
|||
var R = frompubkey.point; |
|||
var P = R.mul(kB); |
|||
if (P.eq(new Point())) |
|||
throw new Error('P equals 0'); |
|||
var S = P.getX(); |
|||
var Sbuf = S.toBuffer({size: 32}); |
|||
var kEkM = Hash.sha512(Sbuf); |
|||
var kE = kEkM.slice(0, 32); |
|||
var kM = kEkM.slice(32, 64); |
|||
var c = encbuf.slice(33, encbuf.length - 32); |
|||
var d = encbuf.slice(encbuf.length - 32, encbuf.length); |
|||
var d2 = Hash.sha256hmac(c, kM); |
|||
if (d.toString('hex') !== d2.toString('hex')) |
|||
throw new Error('Invalid checksum'); |
|||
var messagebuf = AESCBC.decryptCipherkey(c, kE); |
|||
return messagebuf; |
|||
}; |
|||
|
|||
module.exports = ECIES; |
@ -0,0 +1,127 @@ |
|||
var Stealthkey = require('./stealthkey'); |
|||
var Base58check = require('../base58check'); |
|||
var Pubkey = require('../pubkey'); |
|||
var KDF = require('../kdf'); |
|||
var BufferWriter = require('../bufferwriter'); |
|||
var BufferReader = require('../bufferreader'); |
|||
|
|||
var StealthAddress = function StealthAddress(addrstr) { |
|||
if (!(this instanceof StealthAddress)) |
|||
return new StealthAddress(addrstr); |
|||
|
|||
if (typeof addrstr === 'string') { |
|||
this.fromString(addrstr) |
|||
} |
|||
else if (Buffer.isBuffer(addrstr)) { |
|||
var buf = addrstr; |
|||
this.fromBuffer(buf); |
|||
} |
|||
else if (addrstr) { |
|||
var obj = addrstr; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
StealthAddress.mainver = 42; |
|||
StealthAddress.testver = 43; |
|||
|
|||
StealthAddress.prototype.set = function(obj) { |
|||
this.payloadPubkey = obj.payloadPubkey || this.payloadPubkey; |
|||
this.scanPubkey = obj.scanPubkey || this.scanPubkey; |
|||
return this; |
|||
}; |
|||
|
|||
StealthAddress.prototype.fromJSON = function(json) { |
|||
this.fromString(json); |
|||
return this; |
|||
}; |
|||
|
|||
StealthAddress.prototype.toJSON = function() { |
|||
return this.toString(); |
|||
}; |
|||
|
|||
StealthAddress.prototype.fromStealthkey = function(stealthkey) { |
|||
this.set({ |
|||
payloadPubkey: stealthkey.payloadKeypair.pubkey, |
|||
scanPubkey: stealthkey.scanKeypair.pubkey |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
StealthAddress.prototype.fromBuffer = function(buf) { |
|||
var parsed = StealthAddress.parseDWBuffer(buf); |
|||
if ((parsed.version !== StealthAddress.mainver) && (parsed.version !== StealthAddress.testver)) |
|||
throw new Error('Invalid version'); |
|||
if (parsed.options !== 0) |
|||
throw new Error('Invalid options'); |
|||
if (!parsed.scanPubkey) |
|||
throw new Error('Invalid scanPubkey'); |
|||
if (parsed.payloadPubkeys.length !== 1) |
|||
throw new Error('Must have exactly one payloadPubkey'); |
|||
if (parsed.nSigs !== 1) |
|||
throw new Error('Must require exactly one signature'); |
|||
if (parsed.prefix.toString() !== "") |
|||
throw new Error('Only blank prefixes supported'); |
|||
this.scanPubkey = parsed.scanPubkey; |
|||
this.payloadPubkey = parsed.payloadPubkeys[0]; |
|||
return this; |
|||
}; |
|||
|
|||
StealthAddress.prototype.fromString = function(str) { |
|||
return this.fromBuffer(Base58check(str).toBuffer()); |
|||
}; |
|||
|
|||
StealthAddress.prototype.getSharedKeypair = function(senderKeypair) { |
|||
var sharedSecretPoint = this.scanPubkey.point.mul(senderKeypair.privkey.bn); |
|||
var sharedSecretPubkey = Pubkey(sharedSecretPoint); |
|||
var buf = sharedSecretPubkey.toDER(true); |
|||
var sharedKeypair = KDF.sha256hmac2keypair(buf); |
|||
|
|||
return sharedKeypair; |
|||
}; |
|||
|
|||
StealthAddress.prototype.getReceivePubkey = function(senderKeypair) { |
|||
var sharedKeypair = this.getSharedKeypair(senderKeypair); |
|||
var pubkey = Pubkey(this.payloadPubkey.point.add(sharedKeypair.pubkey.point)); |
|||
|
|||
return pubkey; |
|||
}; |
|||
|
|||
StealthAddress.prototype.toBuffer = function(networkstr) { |
|||
if (networkstr === 'testnet') |
|||
var version = StealthAddress.testver; |
|||
else |
|||
var version = StealthAddress.mainver; |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt8(version); |
|||
bw.writeUInt8(0); //options
|
|||
bw.write(this.scanPubkey.toDER(true)); |
|||
bw.writeUInt8(1); //number of payload keys - we only support 1 (not multisig)
|
|||
bw.write(this.payloadPubkey.toDER(true)); |
|||
bw.writeUInt8(1); //number of signatures - we only support 1 (not multisig)
|
|||
bw.writeUInt8(0); //prefix length - we do not support prefix yet
|
|||
var buf = bw.concat(); |
|||
return buf; |
|||
}; |
|||
|
|||
StealthAddress.prototype.toString = function(networkstr) { |
|||
return Base58check(this.toBuffer(networkstr)).toString(); |
|||
}; |
|||
|
|||
StealthAddress.parseDWBuffer = function(buf) { |
|||
var br = new BufferReader(buf); |
|||
var parsed = {}; |
|||
parsed.version = br.readUInt8(); |
|||
parsed.options = br.readUInt8(); |
|||
parsed.scanPubkey = Pubkey().fromBuffer(br.read(33)); |
|||
parsed.nPayloadPubkeys = br.readUInt8(); |
|||
parsed.payloadPubkeys = []; |
|||
for (var i = 0; i < parsed.nPayloadPubkeys; i++) |
|||
parsed.payloadPubkeys.push(Pubkey().fromBuffer(br.read(33))); |
|||
parsed.nSigs = br.readUInt8(); |
|||
parsed.nPrefix = br.readUInt8(); |
|||
parsed.prefix = br.read(parsed.nPrefix / 8); |
|||
return parsed; |
|||
}; |
|||
|
|||
module.exports = StealthAddress; |
@ -0,0 +1,88 @@ |
|||
var Keypair = require('../keypair'); |
|||
var Privkey = require('../privkey'); |
|||
var Pubkey = require('../pubkey'); |
|||
var Point = require('../point'); |
|||
var Hash = require('../hash'); |
|||
var KDF = require('../kdf'); |
|||
|
|||
var Stealthkey = function Stealthkey(payloadKeypair, scanKeypair) { |
|||
if (!(this instanceof Stealthkey)) |
|||
return new Stealthkey(payloadKeypair, scanKeypair); |
|||
|
|||
if (payloadKeypair instanceof Keypair) { |
|||
this.set({ |
|||
payloadKeypair: payloadKeypair, |
|||
scanKeypair: scanKeypair |
|||
}); |
|||
} |
|||
else if (payloadKeypair) { |
|||
var obj = payloadKeypair; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Stealthkey.prototype.set = function(obj) { |
|||
this.payloadKeypair = obj.payloadKeypair || this.payloadKeypair; |
|||
this.scanKeypair = obj.scanKeypair || this.scanKeypair; |
|||
return this; |
|||
}; |
|||
|
|||
Stealthkey.prototype.fromJSON = function(json) { |
|||
this.set({ |
|||
payloadKeypair: Keypair().fromJSON(json.payloadKeypair), |
|||
scanKeypair: Keypair().fromJSON(json.scanKeypair) |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Stealthkey.prototype.toJSON = function() { |
|||
return { |
|||
payloadKeypair: this.payloadKeypair.toJSON(), |
|||
scanKeypair: this.scanKeypair.toJSON() |
|||
}; |
|||
}; |
|||
|
|||
Stealthkey.prototype.fromRandom = function() { |
|||
this.payloadKeypair = Keypair().fromRandom(); |
|||
this.scanKeypair = Keypair().fromRandom(); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
Stealthkey.prototype.getSharedKeypair = function(senderPubkey) { |
|||
var sharedSecretPoint = senderPubkey.point.mul(this.scanKeypair.privkey.bn); |
|||
var sharedSecretPubkey = Pubkey({point: sharedSecretPoint}); |
|||
var buf = sharedSecretPubkey.toDER(true); |
|||
var sharedKeypair = KDF.sha256hmac2keypair(buf); |
|||
|
|||
return sharedKeypair; |
|||
}; |
|||
|
|||
Stealthkey.prototype.getReceivePubkey = function(senderPubkey) { |
|||
var sharedKeypair = this.getSharedKeypair(senderPubkey); |
|||
var pubkey = Pubkey({point: this.payloadKeypair.pubkey.point.add(sharedKeypair.pubkey.point)}); |
|||
|
|||
return pubkey; |
|||
}; |
|||
|
|||
Stealthkey.prototype.getReceiveKeypair = function(senderPubkey) { |
|||
var sharedKeypair = this.getSharedKeypair(senderPubkey); |
|||
var privkey = Privkey({bn: this.payloadKeypair.privkey.bn.add(sharedKeypair.privkey.bn).mod(Point.getN())}); |
|||
var key = Keypair({privkey: privkey}); |
|||
key.privkey2pubkey(); |
|||
|
|||
return key; |
|||
}; |
|||
|
|||
Stealthkey.prototype.isForMe = function(senderPubkey, myPossiblePubkeyhashbuf) { |
|||
var pubkey = this.getReceivePubkey(senderPubkey); |
|||
var pubkeybuf = pubkey.toDER(true); |
|||
var pubkeyhash = Hash.sha256ripemd160(pubkeybuf); |
|||
|
|||
if (pubkeyhash.toString('hex') === myPossiblePubkeyhashbuf.toString('hex')) |
|||
return true; |
|||
else |
|||
return false; |
|||
}; |
|||
|
|||
module.exports = Stealthkey; |
@ -0,0 +1,85 @@ |
|||
var Stealthkey = require('./stealthkey'); |
|||
var StealthAddress = require('./stealthaddress'); |
|||
var ECIES = require('./ecies'); |
|||
var Message = require('../message'); |
|||
var Keypair = require('../keypair'); |
|||
var Address = require('../address'); |
|||
var Pubkey = require('../pubkey'); |
|||
|
|||
var StealthMessage = function StealthMessage(obj) { |
|||
if (!(this instanceof StealthMessage)) |
|||
return new StealthMessage(obj); |
|||
if (obj) |
|||
this.set(obj); |
|||
}; |
|||
|
|||
StealthMessage.prototype.set = function(obj) { |
|||
this.messagebuf = obj.messagebuf || this.messagebuf; |
|||
this.encbuf = obj.encbuf || this.encbuf; |
|||
this.toStealthAddress = obj.toStealthAddress || this.toStealthAddress; |
|||
this.toStealthkey = obj.toStealthkey || this.toStealthkey; |
|||
this.fromKeypair = obj.fromKeypair || this.fromKeypair; |
|||
this.receiveAddress = obj.receiveAddress || this.receiveAddress; |
|||
return this; |
|||
}; |
|||
|
|||
StealthMessage.encrypt = function(messagebuf, toStealthAddress, fromKeypair, ivbuf) { |
|||
var sm = StealthMessage().set({ |
|||
messagebuf: messagebuf, |
|||
toStealthAddress: toStealthAddress, |
|||
fromKeypair: fromKeypair |
|||
}); |
|||
sm.encrypt(ivbuf); |
|||
var buf = Buffer.concat([ |
|||
sm.receiveAddress.hashbuf, |
|||
sm.fromKeypair.pubkey.toDER(true), |
|||
sm.encbuf |
|||
]); |
|||
return buf; |
|||
}; |
|||
|
|||
StealthMessage.decrypt = function(buf, toStealthkey) { |
|||
var sm = StealthMessage().set({ |
|||
toStealthkey: toStealthkey, |
|||
receiveAddress: Address().set({hashbuf: buf.slice(0, 20)}), |
|||
fromKeypair: Keypair().set({pubkey: Pubkey().fromDER(buf.slice(20, 20 + 33))}), |
|||
encbuf: buf.slice(20 + 33) |
|||
}); |
|||
return sm.decrypt().messagebuf; |
|||
}; |
|||
|
|||
StealthMessage.isForMe = function(buf, toStealthkey) { |
|||
var sm = StealthMessage().set({ |
|||
toStealthkey: toStealthkey, |
|||
receiveAddress: Address().set({hashbuf: buf.slice(0, 20)}), |
|||
fromKeypair: Keypair().set({pubkey: Pubkey().fromDER(buf.slice(20, 20 + 33))}), |
|||
encbuf: buf.slice(20 + 33) |
|||
}); |
|||
return sm.isForMe(); |
|||
}; |
|||
|
|||
StealthMessage.prototype.encrypt = function(ivbuf) { |
|||
if (!this.fromKeypair) |
|||
this.fromKeypair = Keypair().fromRandom(); |
|||
var receivePubkey = this.toStealthAddress.getReceivePubkey(this.fromKeypair); |
|||
this.receiveAddress = Address().fromPubkey(receivePubkey); |
|||
this.encbuf = ECIES.encrypt(this.messagebuf, receivePubkey, this.fromKeypair, ivbuf); |
|||
return this; |
|||
}; |
|||
|
|||
StealthMessage.prototype.decrypt = function() { |
|||
var receiveKeypair = this.toStealthkey.getReceiveKeypair(this.fromKeypair.pubkey); |
|||
this.messagebuf = ECIES.decrypt(this.encbuf, receiveKeypair.privkey); |
|||
return this; |
|||
}; |
|||
|
|||
StealthMessage.prototype.isForMe = function() { |
|||
var receivePubkey = this.toStealthkey.getReceivePubkey(this.fromKeypair.pubkey); |
|||
var receiveAddress = Address().fromPubkey(receivePubkey); |
|||
if (receiveAddress.toString('hex') === this.receiveAddress.toString('hex')) |
|||
return true; |
|||
else |
|||
return false; |
|||
}; |
|||
|
|||
module.exports = StealthMessage; |
@ -0,0 +1,69 @@ |
|||
var StealthAddress = require('./stealthaddress'); |
|||
var StealthKey = require('./stealthkey'); |
|||
var Transaction = require('../transaction'); |
|||
var Pubkey = require('../pubkey'); |
|||
|
|||
var StealthTx = function StealthTx(tx, sa, sk) { |
|||
if (!(this instanceof StealthTx)) |
|||
return new StealthTx(tx, sa, sk); |
|||
if (tx instanceof Transaction) { |
|||
this.tx = tx; |
|||
this.sa = sa; |
|||
this.sk = sk; |
|||
} else if (tx) { |
|||
var obj = tx; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
StealthTx.prototype.set = function(obj) { |
|||
this.sk = obj.sk || this.sk; |
|||
this.sa = obj.sa || this.sa; |
|||
this.tx = obj.tx || this.tx; |
|||
return this; |
|||
}; |
|||
|
|||
StealthTx.prototype.isForMe = function() { |
|||
if (!this.notMine()) |
|||
return true; |
|||
else |
|||
return false; |
|||
}; |
|||
|
|||
StealthTx.prototype.notMine = function() { |
|||
var err; |
|||
if (err = this.notStealth()) |
|||
return "Not stealth: " + err; |
|||
var txopbuf = this.tx.txouts[0].script.chunks[1].buf; |
|||
var parsed = StealthTx.parseOpReturnData(txopbuf); |
|||
var pubkey = parsed.pubkey; |
|||
var pubkeyhashbuf = this.tx.txouts[1].script.chunks[2].buf; |
|||
var sk = this.sk; |
|||
if (sk.isForMe(pubkey, pubkeyhashbuf)) { |
|||
return false; |
|||
} else { |
|||
return "StealthTx not mine"; |
|||
} |
|||
}; |
|||
|
|||
//For now, we only support a very limited variety of stealth tx
|
|||
StealthTx.prototype.notStealth = function() { |
|||
var txouts = this.tx.txouts; |
|||
if (!(txouts.length >= 2)) |
|||
return "Not enough txouts"; |
|||
if (!txouts[0].script.isOpReturn()) |
|||
return "First txout is not OP_RETURN"; |
|||
if (!txouts[1].script.isPubkeyhashOut()) |
|||
return "Second txout is not pubkeyhash"; |
|||
return false; |
|||
}; |
|||
|
|||
StealthTx.parseOpReturnData = function(buf) { |
|||
var parsed = {}; |
|||
parsed.version = buf[0]; |
|||
parsed.noncebuf = buf.slice(1, 5); |
|||
parsed.pubkey = Pubkey().fromBuffer(buf.slice(5, 5 + 33)); |
|||
return parsed; |
|||
}; |
|||
|
|||
module.exports = StealthTx; |
@ -0,0 +1,89 @@ |
|||
var hashjs = require('hash.js'); |
|||
var sha512 = require('sha512'); |
|||
|
|||
var Hash = module.exports; |
|||
|
|||
Hash.sha256 = function(buf) { |
|||
if (!Buffer.isBuffer(buf)) |
|||
throw new Error('sha256 hash must be of a buffer'); |
|||
var hash = (new hashjs.sha256()).update(buf).digest(); |
|||
return new Buffer(hash); |
|||
}; |
|||
|
|||
Hash.sha256.blocksize = 512; |
|||
|
|||
Hash.sha256sha256 = function(buf) { |
|||
try { |
|||
return Hash.sha256(Hash.sha256(buf)); |
|||
} catch (e) { |
|||
throw new Error('sha256sha256 hash must be of a buffer'); |
|||
} |
|||
}; |
|||
|
|||
Hash.ripemd160 = function(buf) { |
|||
if (!Buffer.isBuffer(buf)) |
|||
throw new Error('ripemd160 hash must be of a buffer'); |
|||
var hash = (new hashjs.ripemd160()).update(buf).digest(); |
|||
return new Buffer(hash); |
|||
}; |
|||
|
|||
Hash.sha256ripemd160 = function(buf) { |
|||
try { |
|||
return Hash.ripemd160(Hash.sha256(buf)); |
|||
} catch (e) { |
|||
throw new Error('sha256ripemd160 hash must be of a buffer'); |
|||
} |
|||
}; |
|||
|
|||
Hash.sha512 = function(buf) { |
|||
if (!Buffer.isBuffer(buf)) |
|||
throw new Error('sha512 hash must be of a buffer'); |
|||
var hash = sha512(buf); |
|||
return new Buffer(hash); |
|||
}; |
|||
|
|||
Hash.sha512.blocksize = 1024; |
|||
|
|||
Hash.hmac = function(hashf, data, key) { |
|||
if (!Buffer.isBuffer(data) || !Buffer.isBuffer(key)) |
|||
throw new Error('data and key must be buffers'); |
|||
|
|||
//http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
|
|||
//http://tools.ietf.org/html/rfc4868#section-2
|
|||
if (!hashf.blocksize) |
|||
throw new Error('Blocksize for hash function unknown'); |
|||
|
|||
var blocksize = hashf.blocksize/8; |
|||
|
|||
if (key.length > blocksize) |
|||
key = hashf(key); |
|||
else if (key < blocksize) { |
|||
var fill = new Buffer(blocksize); |
|||
fill.fill(0); |
|||
key.copy(fill); |
|||
key = fill; |
|||
} |
|||
|
|||
var o_key = new Buffer(blocksize); |
|||
o_key.fill(0x5c); |
|||
|
|||
var i_key = new Buffer(blocksize); |
|||
i_key.fill(0x36); |
|||
|
|||
var o_key_pad = new Buffer(blocksize); |
|||
var i_key_pad = new Buffer(blocksize); |
|||
for (var i = 0; i < blocksize; i++) { |
|||
o_key_pad[i] = o_key[i] ^ key[i]; |
|||
i_key_pad[i] = i_key[i] ^ key[i]; |
|||
} |
|||
|
|||
return hashf(Buffer.concat([o_key_pad, hashf(Buffer.concat([i_key_pad, data]))])); |
|||
}; |
|||
|
|||
Hash.sha256hmac = function(data, key) { |
|||
return Hash.hmac(Hash.sha256, data, key); |
|||
}; |
|||
|
|||
Hash.sha512hmac = function(data, key) { |
|||
return Hash.hmac(Hash.sha512, data, key); |
|||
}; |
@ -0,0 +1,32 @@ |
|||
var Bn = require('./bn'); |
|||
var Privkey = require('./privkey'); |
|||
var Point = require('./point'); |
|||
var Pubkey = require('./pubkey'); |
|||
var Keypair = require('./keypair'); |
|||
var Hash = require('./hash'); |
|||
|
|||
function KDF() { |
|||
}; |
|||
|
|||
KDF.buf2keypair = function(buf) { |
|||
return KDF.sha256hmac2keypair(buf); |
|||
}; |
|||
|
|||
KDF.sha256hmac2keypair = function(buf) { |
|||
var privkey = KDF.sha256hmac2privkey(buf); |
|||
var keypair = Keypair().fromPrivkey(privkey); |
|||
return keypair; |
|||
}; |
|||
|
|||
KDF.sha256hmac2privkey = function(buf) { |
|||
var bn; |
|||
var concat = new Buffer([]); |
|||
do { |
|||
var hash = Hash.sha256hmac(buf, concat); |
|||
var bn = Bn.fromBuffer(hash); |
|||
concat = Buffer.concat([concat, new Buffer(0)]); |
|||
} while(!bn.lt(Point.getN())); |
|||
return new Privkey({bn: bn}); |
|||
}; |
|||
|
|||
module.exports = KDF; |
@ -0,0 +1,73 @@ |
|||
var Privkey = require('./privkey'); |
|||
var Pubkey = require('./pubkey'); |
|||
var BN = require('./bn'); |
|||
var point = require('./point'); |
|||
|
|||
var Keypair = function Keypair(obj) { |
|||
if (!(this instanceof Keypair)) |
|||
return new Keypair(obj); |
|||
if (obj) |
|||
this.set(obj); |
|||
}; |
|||
|
|||
Keypair.prototype.set = function(obj) { |
|||
this.privkey = obj.privkey || this.privkey || undefined; |
|||
this.pubkey = obj.pubkey || this.pubkey || undefined; |
|||
return this; |
|||
}; |
|||
|
|||
Keypair.prototype.fromJSON = function(json) { |
|||
if (json.privkey) |
|||
this.set({privkey: Privkey().fromJSON(json.privkey)}); |
|||
if (json.pubkey) |
|||
this.set({pubkey: Pubkey().fromJSON(json.pubkey)}); |
|||
return this; |
|||
}; |
|||
|
|||
Keypair.prototype.toJSON = function() { |
|||
var json = {}; |
|||
if (this.privkey) |
|||
json.privkey = this.privkey.toJSON(); |
|||
if (this.pubkey) |
|||
json.pubkey = this.pubkey.toJSON(); |
|||
return json; |
|||
}; |
|||
|
|||
Keypair.prototype.fromPrivkey = function(privkey) { |
|||
this.privkey = privkey; |
|||
this.privkey2pubkey(); |
|||
return this; |
|||
}; |
|||
|
|||
Keypair.prototype.fromRandom = function() { |
|||
this.privkey = Privkey().fromRandom(); |
|||
this.privkey2pubkey(); |
|||
return this; |
|||
}; |
|||
|
|||
Keypair.prototype.fromString = function(str) { |
|||
var obj = JSON.parse(str); |
|||
if (obj.privkey) { |
|||
this.privkey = new Privkey(); |
|||
this.privkey.fromString(obj.privkey); |
|||
} |
|||
if (obj.pubkey) { |
|||
this.pubkey = new Pubkey(); |
|||
this.pubkey.fromString(obj.pubkey); |
|||
} |
|||
}; |
|||
|
|||
Keypair.prototype.privkey2pubkey = function() { |
|||
this.pubkey = Pubkey().fromPrivkey(this.privkey); |
|||
}; |
|||
|
|||
Keypair.prototype.toString = function() { |
|||
var obj = {}; |
|||
if (this.privkey) |
|||
obj.privkey = this.privkey.toString(); |
|||
if (this.pubkey) |
|||
obj.pubkey = this.pubkey.toString(); |
|||
return JSON.stringify(obj); |
|||
}; |
|||
|
|||
module.exports = Keypair; |
@ -0,0 +1,94 @@ |
|||
var ECDSA = require('./ecdsa'); |
|||
var Keypair = require('./keypair'); |
|||
var Privkey = require('./privkey'); |
|||
var Pubkey = require('./pubkey'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var Hash = require('./hash'); |
|||
var Address = require('./address'); |
|||
var Signature = require('./signature'); |
|||
|
|||
var Message = function Message(obj) { |
|||
if (!(this instanceof Message)) |
|||
return new Message(obj); |
|||
if (obj) |
|||
this.set(obj); |
|||
}; |
|||
|
|||
Message.prototype.set = function(obj) { |
|||
this.messagebuf = obj.messagebuf || this.messagebuf; |
|||
this.keypair = obj.keypair || this.keypair; |
|||
this.sig = obj.sig || this.sig; |
|||
this.address = obj.address || this.address; |
|||
this.verified = typeof obj.verified !== 'undefined' ? obj.verified : this.verified; |
|||
return this; |
|||
}; |
|||
|
|||
Message.magicBytes = new Buffer('Bitcoin Signed Message:\n'); |
|||
|
|||
Message.magicHash = function(messagebuf) { |
|||
if (!Buffer.isBuffer(messagebuf)) |
|||
throw new Error('messagebuf must be a buffer'); |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintNum(Message.magicBytes.length); |
|||
bw.write(Message.magicBytes); |
|||
bw.writeVarintNum(messagebuf.length); |
|||
bw.write(messagebuf); |
|||
var buf = bw.concat(); |
|||
|
|||
var hashbuf = Hash.sha256sha256(buf); |
|||
|
|||
return hashbuf; |
|||
}; |
|||
|
|||
Message.sign = function(messagebuf, keypair) { |
|||
var m = Message({messagebuf: messagebuf, keypair: keypair}); |
|||
m.sign(); |
|||
var sigbuf = m.sig.toCompact(); |
|||
var sigstr = sigbuf.toString('base64'); |
|||
return sigstr; |
|||
}; |
|||
|
|||
Message.verify = function(messagebuf, sigstr, address) { |
|||
var sigbuf = new Buffer(sigstr, 'base64'); |
|||
var message = new Message(); |
|||
message.messagebuf = messagebuf; |
|||
message.sig = Signature().fromCompact(sigbuf); |
|||
message.address = address; |
|||
|
|||
return message.verify().verified; |
|||
}; |
|||
|
|||
Message.prototype.sign = function() { |
|||
var hashbuf = Message.magicHash(this.messagebuf); |
|||
var ecdsa = ECDSA({hashbuf: hashbuf, keypair: this.keypair}); |
|||
ecdsa.signRandomK(); |
|||
ecdsa.calci(); |
|||
this.sig = ecdsa.sig; |
|||
return this; |
|||
}; |
|||
|
|||
Message.prototype.verify = function() { |
|||
var hashbuf = Message.magicHash(this.messagebuf); |
|||
|
|||
var ecdsa = new ECDSA(); |
|||
ecdsa.hashbuf = hashbuf; |
|||
ecdsa.sig = this.sig; |
|||
ecdsa.keypair = new Keypair(); |
|||
ecdsa.keypair.pubkey = ecdsa.sig2pubkey(); |
|||
|
|||
if (!ecdsa.verify()) { |
|||
this.verified = false; |
|||
return this; |
|||
} |
|||
|
|||
var address = Address().fromPubkey(ecdsa.keypair.pubkey, undefined, this.sig.compressed); |
|||
//TODO: what if livenet/testnet mismatch?
|
|||
if (address.hashbuf.toString('hex') === this.address.hashbuf.toString('hex')) |
|||
this.verified = true; |
|||
else |
|||
this.verified = false; |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
module.exports = Message; |
@ -0,0 +1,192 @@ |
|||
function Opcode(num) { |
|||
if (!(this instanceof Opcode)) |
|||
return new Opcode(num); |
|||
|
|||
if (typeof num === 'number') { |
|||
this.num = num; |
|||
} else if (typeof num === 'string') { |
|||
var str = num; |
|||
this.num = Opcode.map[str]; |
|||
} else if (num) { |
|||
var obj = num; |
|||
this.set(obj); |
|||
} |
|||
} |
|||
|
|||
Opcode.prototype.set = function(obj) { |
|||
this.num = typeof obj.num !== 'undefined' ? obj.num : this.num; |
|||
return this; |
|||
}; |
|||
|
|||
Opcode.prototype.fromNumber = function(num) { |
|||
this.num = num; |
|||
return this; |
|||
}; |
|||
|
|||
Opcode.prototype.toNumber = function() { |
|||
return this.num; |
|||
}; |
|||
|
|||
Opcode.prototype.fromString = function(str) { |
|||
var num = Opcode.map[str]; |
|||
if (typeof num === 'undefined') |
|||
throw new Error('Invalid opcodestr'); |
|||
this.num = num; |
|||
return this; |
|||
}; |
|||
|
|||
Opcode.prototype.toString = function() { |
|||
var str = Opcode.reverseMap[this.num]; |
|||
if (typeof str === 'undefined') |
|||
throw new Error('Opcode does not have a string representation'); |
|||
return str; |
|||
}; |
|||
|
|||
Opcode.map = { |
|||
// push value
|
|||
OP_FALSE: 0, |
|||
OP_0: 0, |
|||
OP_PUSHDATA1: 76, |
|||
OP_PUSHDATA2: 77, |
|||
OP_PUSHDATA4: 78, |
|||
OP_1NEGATE: 79, |
|||
OP_RESERVED: 80, |
|||
OP_TRUE: 81, |
|||
OP_1: 81, |
|||
OP_2: 82, |
|||
OP_3: 83, |
|||
OP_4: 84, |
|||
OP_5: 85, |
|||
OP_6: 86, |
|||
OP_7: 87, |
|||
OP_8: 88, |
|||
OP_9: 89, |
|||
OP_10: 90, |
|||
OP_11: 91, |
|||
OP_12: 92, |
|||
OP_13: 93, |
|||
OP_14: 94, |
|||
OP_15: 95, |
|||
OP_16: 96, |
|||
|
|||
// control
|
|||
OP_NOP: 97, |
|||
OP_VER: 98, |
|||
OP_IF: 99, |
|||
OP_NOTIF: 100, |
|||
OP_VERIF: 101, |
|||
OP_VERNOTIF: 102, |
|||
OP_ELSE: 103, |
|||
OP_ENDIF: 104, |
|||
OP_VERIFY: 105, |
|||
OP_RETURN: 106, |
|||
|
|||
// stack ops
|
|||
OP_TOALTSTACK: 107, |
|||
OP_FROMALTSTACK: 108, |
|||
OP_2DROP: 109, |
|||
OP_2DUP: 110, |
|||
OP_3DUP: 111, |
|||
OP_2OVER: 112, |
|||
OP_2ROT: 113, |
|||
OP_2SWAP: 114, |
|||
OP_IFDUP: 115, |
|||
OP_DEPTH: 116, |
|||
OP_DROP: 117, |
|||
OP_DUP: 118, |
|||
OP_NIP: 119, |
|||
OP_OVER: 120, |
|||
OP_PICK: 121, |
|||
OP_ROLL: 122, |
|||
OP_ROT: 123, |
|||
OP_SWAP: 124, |
|||
OP_TUCK: 125, |
|||
|
|||
// splice ops
|
|||
OP_CAT: 126, |
|||
OP_SUBSTR: 127, |
|||
OP_LEFT: 128, |
|||
OP_RIGHT: 129, |
|||
OP_SIZE: 130, |
|||
|
|||
// bit logic
|
|||
OP_INVERT: 131, |
|||
OP_AND: 132, |
|||
OP_OR: 133, |
|||
OP_XOR: 134, |
|||
OP_EQUAL: 135, |
|||
OP_EQUALVERIFY: 136, |
|||
OP_RESERVED1: 137, |
|||
OP_RESERVED2: 138, |
|||
|
|||
// numeric
|
|||
OP_1ADD: 139, |
|||
OP_1SUB: 140, |
|||
OP_2MUL: 141, |
|||
OP_2DIV: 142, |
|||
OP_NEGATE: 143, |
|||
OP_ABS: 144, |
|||
OP_NOT: 145, |
|||
OP_0NOTEQUAL: 146, |
|||
|
|||
OP_ADD: 147, |
|||
OP_SUB: 148, |
|||
OP_MUL: 149, |
|||
OP_DIV: 150, |
|||
OP_MOD: 151, |
|||
OP_LSHIFT: 152, |
|||
OP_RSHIFT: 153, |
|||
|
|||
OP_BOOLAND: 154, |
|||
OP_BOOLOR: 155, |
|||
OP_NUMEQUAL: 156, |
|||
OP_NUMEQUALVERIFY: 157, |
|||
OP_NUMNOTEQUAL: 158, |
|||
OP_LESSTHAN: 159, |
|||
OP_GREATERTHAN: 160, |
|||
OP_LESSTHANOREQUAL: 161, |
|||
OP_GREATERTHANOREQUAL: 162, |
|||
OP_MIN: 163, |
|||
OP_MAX: 164, |
|||
|
|||
OP_WITHIN: 165, |
|||
|
|||
// crypto
|
|||
OP_RIPEMD160: 166, |
|||
OP_SHA1: 167, |
|||
OP_SHA256: 168, |
|||
OP_HASH160: 169, |
|||
OP_HASH256: 170, |
|||
OP_CODESEPARATOR: 171, |
|||
OP_CHECKSIG: 172, |
|||
OP_CHECKSIGVERIFY: 173, |
|||
OP_CHECKMULTISIG: 174, |
|||
OP_CHECKMULTISIGVERIFY: 175, |
|||
|
|||
// expansion
|
|||
OP_NOP1: 176, |
|||
OP_NOP2: 177, |
|||
OP_NOP3: 178, |
|||
OP_NOP4: 179, |
|||
OP_NOP5: 180, |
|||
OP_NOP6: 181, |
|||
OP_NOP7: 182, |
|||
OP_NOP8: 183, |
|||
OP_NOP9: 184, |
|||
OP_NOP10: 185, |
|||
|
|||
// template matching params
|
|||
OP_PUBKEYHASH: 253, |
|||
OP_PUBKEY: 254, |
|||
OP_INVALIDOPCODE: 255 |
|||
}; |
|||
|
|||
Opcode.reverseMap = []; |
|||
|
|||
for (var k in Opcode.map) { |
|||
if (Opcode.map.hasOwnProperty(k)) { |
|||
Opcode.reverseMap[Opcode.map[k]] = k; |
|||
} |
|||
} |
|||
|
|||
module.exports = Opcode; |
@ -0,0 +1,50 @@ |
|||
var BN = require('./bn'); |
|||
var elliptic = require('elliptic'); |
|||
|
|||
var ec = elliptic.curves.secp256k1; |
|||
var ecpoint = ec.curve.point.bind(ec.curve) |
|||
var p = ec.curve.point(); |
|||
var Curve = Object.getPrototypeOf(ec.curve); |
|||
|
|||
var Point = function Point(x, y, isRed) { |
|||
return ecpoint(x, y, isRed); |
|||
}; |
|||
|
|||
Point.prototype = Object.getPrototypeOf(p); |
|||
|
|||
Point.fromX = ec.curve.pointFromX.bind(ec.curve); |
|||
|
|||
Point.getG = function() { |
|||
var p = Point(ec.curve.g.getX(), ec.curve.g.getY()); |
|||
return p; |
|||
}; |
|||
|
|||
Point.getN = function() { |
|||
return BN(ec.curve.n.toArray()); |
|||
}; |
|||
|
|||
Point.prototype._getX = Point.prototype.getX; |
|||
Point.prototype.getX = function() { |
|||
var n = BN(this._getX().toArray()); |
|||
return BN(this._getX().toArray()); |
|||
}; |
|||
|
|||
Point.prototype._getY = Point.prototype.getY; |
|||
Point.prototype.getY = function() { |
|||
return BN(this._getY().toArray()); |
|||
}; |
|||
|
|||
//https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
|
|||
Point.prototype.validate = function() { |
|||
var p2 = Point.fromX(this.getY().isOdd(), this.getX()); |
|||
if (!(p2.y.cmp(this.y) === 0)) |
|||
throw new Error('Invalid y value of public key'); |
|||
if (!(this.getX().gt(-1) && this.getX().lt(Point.getN())) |
|||
||!(this.getY().gt(-1) && this.getY().lt(Point.getN()))) |
|||
throw new Error('Point does not lie on the curve'); |
|||
if (!(this.mul(Point.getN()).isInfinity())) |
|||
throw new Error('Point times N must be infinity'); |
|||
return this; |
|||
}; |
|||
|
|||
module.exports = Point; |
@ -0,0 +1,104 @@ |
|||
var BN = require('./bn'); |
|||
var Point = require('./point'); |
|||
var constants = require('./constants'); |
|||
var base58check = require('./base58check'); |
|||
var Random = require('./random'); |
|||
|
|||
var Privkey = function Privkey(bn) { |
|||
if (!(this instanceof Privkey)) |
|||
return new Privkey(bn); |
|||
if (bn instanceof BN) |
|||
this.bn = bn; |
|||
else if (bn) { |
|||
var obj = bn; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Privkey.prototype.set = function(obj) { |
|||
this.bn = obj.bn || this.bn; |
|||
this.networkstr = obj.networkstr || this.networkstr; |
|||
this.compressed = typeof obj.compressed !== 'undefined' ? obj.compressed : this.compressed; |
|||
return this; |
|||
}; |
|||
|
|||
Privkey.prototype.fromJSON = function(json) { |
|||
this.fromString(json); |
|||
return this; |
|||
}; |
|||
|
|||
Privkey.prototype.toJSON = function() { |
|||
return this.toString(); |
|||
}; |
|||
|
|||
Privkey.prototype.fromRandom = function() { |
|||
do { |
|||
var privbuf = Random.getRandomBuffer(32); |
|||
var bn = BN().fromBuffer(privbuf); |
|||
var condition = bn.lt(Point.getN()); |
|||
} while (!condition); |
|||
this.set({ |
|||
bn: bn, |
|||
networkstr: 'mainnet', |
|||
compressed: true |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Privkey.prototype.validate = function() { |
|||
if (!this.bn.lt(Point.getN())) |
|||
throw new Error('Number must be less than N'); |
|||
if (typeof constants[this.networkstr] === undefined) |
|||
throw new Error('Must specify the networkstr ("mainnet" or "testnet")'); |
|||
if (typeof this.compressed !== 'boolean') |
|||
throw new Error('Must specify whether the corresponding public key is compressed or not (true or false)'); |
|||
}; |
|||
|
|||
Privkey.prototype.toWIF = function() { |
|||
var networkstr = this.networkstr; |
|||
var compressed = this.compressed; |
|||
|
|||
if (typeof this.networkstr === 'undefined') |
|||
networkstr = 'mainnet'; |
|||
if (typeof this.compressed === 'undefined') |
|||
compressed = true; |
|||
|
|||
var privbuf = this.bn.toBuffer({size: 32}); |
|||
var buf; |
|||
if (compressed) |
|||
buf = Buffer.concat([new Buffer([constants[networkstr].privkey]), this.bn.toBuffer({size: 32}), new Buffer([0x01])]); |
|||
else |
|||
buf = Buffer.concat([new Buffer([constants[networkstr].privkey]), this.bn.toBuffer({size: 32})]); |
|||
|
|||
return base58check.encode(buf); |
|||
}; |
|||
|
|||
Privkey.prototype.fromWIF = function(str) { |
|||
var buf = base58check.decode(str); |
|||
|
|||
if (buf.length === 1 + 32 + 1 && buf[1 + 32 + 1 - 1] == 1) |
|||
this.compressed = true; |
|||
else if (buf.length === 1 + 32) |
|||
this.compressed = false; |
|||
else |
|||
throw new Error('Length of buffer must be 33 (uncompressed) or 34 (compressed)'); |
|||
|
|||
if (buf[0] === constants.mainnet.privkey) |
|||
this.networkstr = 'mainnet'; |
|||
else if (buf[0] === constants.testnet.privkey) |
|||
this.networkstr = 'testnet'; |
|||
else |
|||
throw new Error('Invalid networkstr'); |
|||
|
|||
this.bn = BN.fromBuffer(buf.slice(1, 32 + 1)); |
|||
}; |
|||
|
|||
Privkey.prototype.toString = function() { |
|||
return this.toWIF(); |
|||
}; |
|||
|
|||
Privkey.prototype.fromString = function(str) { |
|||
this.fromWIF(str); |
|||
}; |
|||
|
|||
module.exports = Privkey; |
@ -0,0 +1,125 @@ |
|||
var Point = require('./point'); |
|||
var bn = require('./bn'); |
|||
var privkey = require('./privkey'); |
|||
|
|||
var Pubkey = function Pubkey(point) { |
|||
if (!(this instanceof Pubkey)) |
|||
return new Pubkey(point); |
|||
if (point instanceof Point) |
|||
this.point = point; |
|||
else if (point) { |
|||
var obj = point; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Pubkey.prototype.set = function(obj) { |
|||
if (obj.point && !obj.point.getX() && !obj.point.getY()) |
|||
throw new Error('Invalid point'); |
|||
this.point = obj.point || this.point; |
|||
this.compressed = typeof obj.compressed !== 'undefined' ? obj.compressed : this.compressed; |
|||
return this; |
|||
}; |
|||
|
|||
Pubkey.prototype.fromJSON = function(json) { |
|||
this.fromBuffer(new Buffer(json, 'hex')); |
|||
return this; |
|||
}; |
|||
|
|||
Pubkey.prototype.toJSON = function() { |
|||
return this.toBuffer().toString('hex'); |
|||
}; |
|||
|
|||
Pubkey.prototype.fromPrivkey = function(privkey) { |
|||
this.set({ |
|||
point: Point.getG().mul(privkey.bn), |
|||
compressed: privkey.compressed} |
|||
); |
|||
return this; |
|||
}; |
|||
|
|||
Pubkey.prototype.fromBuffer = function(buf) { |
|||
return this.fromDER(buf); |
|||
}; |
|||
|
|||
Pubkey.prototype.fromDER = function(buf) { |
|||
if (buf[0] == 0x04) { |
|||
var xbuf = buf.slice(1, 33); |
|||
var ybuf = buf.slice(33, 65); |
|||
if (xbuf.length !== 32 || ybuf.length !== 32 || buf.length !== 65) |
|||
throw new Error('Length of x and y must be 32 bytes'); |
|||
var x = bn(xbuf); |
|||
var y = bn(ybuf); |
|||
this.point = Point(x, y); |
|||
this.compressed = false; |
|||
} else if (buf[0] == 0x03) { |
|||
var xbuf = buf.slice(1); |
|||
var x = bn(xbuf); |
|||
this.fromX(true, x); |
|||
this.compressed = true; |
|||
} else if (buf[0] == 0x02) { |
|||
var xbuf = buf.slice(1); |
|||
var x = bn(xbuf); |
|||
this.fromX(false, x); |
|||
this.compressed = true; |
|||
} else { |
|||
throw new Error('Invalid DER format pubkey'); |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
Pubkey.prototype.fromString = function(str) { |
|||
this.fromDER(new Buffer(str, 'hex')); |
|||
}; |
|||
|
|||
Pubkey.prototype.fromX = function(odd, x) { |
|||
if (typeof odd !== 'boolean') |
|||
throw new Error('Must specify whether y is odd or not (true or false)'); |
|||
this.point = Point.fromX(odd, x); |
|||
}; |
|||
|
|||
Pubkey.prototype.toBuffer = function() { |
|||
var compressed = typeof this.compressed === 'undefined' ? true : this.compressed; |
|||
return this.toDER(compressed); |
|||
}; |
|||
|
|||
Pubkey.prototype.toDER = function(compressed) { |
|||
compressed = typeof this.compressed === 'undefined' ? compressed : this.compressed; |
|||
if (typeof compressed !== 'boolean') |
|||
throw new Error('Must specify whether the public key is compressed or not (true or false)'); |
|||
|
|||
var x = this.point.getX(); |
|||
var y = this.point.getY(); |
|||
|
|||
var xbuf = x.toBuffer({size: 32}); |
|||
var ybuf = y.toBuffer({size: 32}); |
|||
|
|||
if (!compressed) { |
|||
var prefix = new Buffer([0x04]); |
|||
return Buffer.concat([prefix, xbuf, ybuf]); |
|||
} else { |
|||
var odd = ybuf[ybuf.length - 1] % 2; |
|||
if (odd) |
|||
var prefix = new Buffer([0x03]); |
|||
else |
|||
var prefix = new Buffer([0x02]); |
|||
return Buffer.concat([prefix, xbuf]); |
|||
} |
|||
}; |
|||
|
|||
Pubkey.prototype.toString = function() { |
|||
var compressed = typeof this.compressed === 'undefined' ? true : this.compressed; |
|||
return this.toDER(compressed).toString('hex'); |
|||
}; |
|||
|
|||
//https://www.iacr.org/archive/pkc2003/25670211/25670211.pdf
|
|||
Pubkey.prototype.validate = function() { |
|||
if (this.point.isInfinity()) |
|||
throw new Error('point: Point cannot be equal to Infinity'); |
|||
if (this.point.eq(Point(bn(0), bn(0)))) |
|||
throw new Error('point: Point cannot be equal to 0, 0'); |
|||
this.point.validate(); |
|||
return this; |
|||
}; |
|||
|
|||
module.exports = Pubkey; |
@ -0,0 +1,54 @@ |
|||
function Random() { |
|||
}; |
|||
|
|||
/* secure random bytes that sometimes throws an error due to lack of entropy */ |
|||
Random.getRandomBuffer = function(size) { |
|||
if (process.browser) |
|||
return Random.getRandomBufferBrowser(size); |
|||
else |
|||
return Random.getRandomBufferNode(size); |
|||
}; |
|||
|
|||
Random.getRandomBufferNode = function(size) { |
|||
var crypto = require('crypto'); |
|||
return crypto.randomBytes(size); |
|||
} |
|||
|
|||
Random.getRandomBufferBrowser = function(size) { |
|||
if (!window.crypto && !window.msCrypto) |
|||
throw new Error('window.crypto not available'); |
|||
|
|||
if (window.crypto && window.crypto.getRandomValues) |
|||
var crypto = window.crypto; |
|||
else if (window.msCrypto && window.msCrypto.getRandomValues) //internet explorer
|
|||
var crypto = window.msCrypto; |
|||
else |
|||
throw new Error('window.crypto.getRandomValues not available'); |
|||
|
|||
var bbuf = new Uint8Array(size); |
|||
crypto.getRandomValues(bbuf); |
|||
var buf = new Buffer(bbuf); |
|||
|
|||
return buf; |
|||
}; |
|||
|
|||
/* insecure random bytes, but it never fails */ |
|||
Random.getPseudoRandomBuffer = function(size) { |
|||
var b32 = 0x100000000; |
|||
var b = new Buffer(size); |
|||
|
|||
for (var i = 0; i <= size; i++) { |
|||
var j = Math.floor(i / 4); |
|||
var k = i - j * 4; |
|||
if (k == 0) { |
|||
r = Math.random() * b32; |
|||
b[i] = r & 0xff; |
|||
} else { |
|||
b[i] = (r = r >>> 8) & 0xff; |
|||
} |
|||
} |
|||
|
|||
return b; |
|||
}; |
|||
|
|||
module.exports = Random; |
@ -0,0 +1,281 @@ |
|||
var BufferReader = require('./bufferreader'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var Opcode = require('./opcode'); |
|||
|
|||
var Script = function Script(buf) { |
|||
if (!(this instanceof Script)) |
|||
return new Script(buf); |
|||
|
|||
this.chunks = []; |
|||
|
|||
if (Buffer.isBuffer(buf)) { |
|||
this.fromBuffer(buf); |
|||
} |
|||
else if (typeof buf === 'string') { |
|||
var str = buf; |
|||
this.fromString(str); |
|||
} |
|||
else if (typeof buf !== 'undefined') { |
|||
var obj = buf; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.set = function(obj) { |
|||
this.chunks = obj.chunks || this.chunks; |
|||
return this; |
|||
}; |
|||
|
|||
Script.prototype.fromJSON = function(json) { |
|||
return this.fromString(json); |
|||
}; |
|||
|
|||
Script.prototype.toJSON = function() { |
|||
return this.toString(); |
|||
}; |
|||
|
|||
Script.prototype.fromBuffer = function(buf) { |
|||
this.chunks = []; |
|||
|
|||
var br = new BufferReader(buf); |
|||
while (!br.eof()) { |
|||
var opcodenum = br.readUInt8(); |
|||
|
|||
var len, buf; |
|||
if (opcodenum > 0 && opcodenum < Opcode.map.OP_PUSHDATA1) { |
|||
len = opcodenum; |
|||
this.chunks.push({ |
|||
buf: br.read(len), |
|||
len: len, |
|||
opcodenum: opcodenum |
|||
}); |
|||
} else if (opcodenum === Opcode.map.OP_PUSHDATA1) { |
|||
len = br.readUInt8(); |
|||
var buf = br.read(len); |
|||
this.chunks.push({ |
|||
buf: buf, |
|||
len: len, |
|||
opcodenum: opcodenum |
|||
}); |
|||
} else if (opcodenum === Opcode.map.OP_PUSHDATA2) { |
|||
len = br.readUInt16LE(); |
|||
buf = br.read(len); |
|||
this.chunks.push({ |
|||
buf: buf, |
|||
len: len, |
|||
opcodenum: opcodenum |
|||
}); |
|||
} else if (opcodenum === Opcode.map.OP_PUSHDATA4) { |
|||
len = br.readUInt32LE(); |
|||
buf = br.read(len); |
|||
this.chunks.push({ |
|||
buf: buf, |
|||
len: len, |
|||
opcodenum: opcodenum |
|||
}); |
|||
} else { |
|||
this.chunks.push(opcodenum); |
|||
} |
|||
} |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
Script.prototype.toBuffer = function() { |
|||
var bw = new BufferWriter(); |
|||
|
|||
for (var i = 0; i < this.chunks.length; i++) { |
|||
var chunk = this.chunks[i]; |
|||
if (typeof chunk === 'number') { |
|||
var opcodenum = chunk; |
|||
bw.writeUInt8(opcodenum); |
|||
} else { |
|||
var opcodenum = chunk.opcodenum; |
|||
bw.writeUInt8(chunk.opcodenum); |
|||
if (opcodenum < Opcode.map.OP_PUSHDATA1) { |
|||
bw.write(chunk.buf); |
|||
} |
|||
else if (opcodenum === Opcode.map.OP_PUSHDATA1) { |
|||
bw.writeUInt8(chunk.len); |
|||
bw.write(chunk.buf); |
|||
} |
|||
else if (opcodenum === Opcode.map.OP_PUSHDATA2) { |
|||
bw.writeUInt16LE(chunk.len); |
|||
bw.write(chunk.buf); |
|||
} |
|||
else if (opcodenum === Opcode.map.OP_PUSHDATA4) { |
|||
bw.writeUInt32LE(chunk.len); |
|||
bw.write(chunk.buf); |
|||
} |
|||
} |
|||
} |
|||
|
|||
return bw.concat(); |
|||
}; |
|||
|
|||
Script.prototype.fromString = function(str) { |
|||
this.chunks = []; |
|||
|
|||
var tokens = str.split(' '); |
|||
var i = 0; |
|||
while (i < tokens.length) { |
|||
var token = tokens[i]; |
|||
var opcode = Opcode(token); |
|||
var opcodenum = opcode.toNumber(); |
|||
|
|||
if (typeof opcodenum === 'undefined') { |
|||
opcodenum = parseInt(token); |
|||
if (opcodenum > 0 && opcodenum < Opcode.map.OP_PUSHDATA1) { |
|||
this.chunks.push({ |
|||
buf: new Buffer(tokens[i + 1].slice(2), 'hex'), |
|||
len: opcodenum, |
|||
opcodenum: opcodenum |
|||
}); |
|||
i = i + 2; |
|||
} |
|||
else { |
|||
throw new Error('Invalid script'); |
|||
} |
|||
} else if (opcodenum === Opcode.map.OP_PUSHDATA1 || opcodenum === Opcode.map.OP_PUSHDATA2 || opcodenum === Opcode.map.OP_PUSHDATA4) { |
|||
if (tokens[i + 2].slice(0, 2) != '0x') |
|||
throw new Error('Pushdata data must start with 0x'); |
|||
this.chunks.push({ |
|||
buf: new Buffer(tokens[i + 2].slice(2), 'hex'), |
|||
len: parseInt(tokens[i + 1]), |
|||
opcodenum: opcodenum |
|||
}); |
|||
i = i + 3; |
|||
} else { |
|||
this.chunks.push(opcodenum); |
|||
i = i + 1; |
|||
} |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
Script.prototype.toString = function() { |
|||
var str = ""; |
|||
|
|||
for (var i = 0; i < this.chunks.length; i++) { |
|||
var chunk = this.chunks[i]; |
|||
if (typeof chunk === 'number') { |
|||
var opcodenum = chunk; |
|||
str = str + Opcode(opcodenum).toString() + " "; |
|||
} else { |
|||
var opcodenum = chunk.opcodenum; |
|||
if (opcodenum === Opcode.map.OP_PUSHDATA1 || opcodenum === Opcode.map.OP_PUSHDATA2 || opcodenum === Opcode.map.OP_PUSHDATA4) |
|||
str = str + Opcode(opcodenum).toString() + " " ; |
|||
str = str + chunk.len + " " ; |
|||
str = str + "0x" + chunk.buf.toString('hex') + " "; |
|||
} |
|||
} |
|||
|
|||
return str.substr(0, str.length - 1); |
|||
}; |
|||
|
|||
Script.prototype.isOpReturn = function() { |
|||
if (this.chunks[0] === Opcode('OP_RETURN').toNumber() |
|||
&& |
|||
(this.chunks.length === 1 |
|||
|| |
|||
(this.chunks.length === 2 |
|||
&& this.chunks[1].buf |
|||
&& this.chunks[1].buf.length <= 40 |
|||
&& this.chunks[1].length === this.chunks.len))) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.isPubkeyhashOut = function() { |
|||
if (this.chunks[0] === Opcode('OP_DUP').toNumber() |
|||
&& this.chunks[1] === Opcode('OP_HASH160').toNumber() |
|||
&& this.chunks[2].buf |
|||
&& this.chunks[3] === Opcode('OP_EQUALVERIFY').toNumber() |
|||
&& this.chunks[4] === Opcode('OP_CHECKSIG').toNumber()) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.isPubkeyhashIn = function() { |
|||
if (this.chunks.length === 2 |
|||
&& this.chunks[0].buf |
|||
&& this.chunks[1].buf) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.isScripthashOut = function() { |
|||
if (this.chunks.length === 3 |
|||
&& this.chunks[0] === Opcode('OP_HASH160').toNumber() |
|||
&& this.chunks[1].buf |
|||
&& this.chunks[1].buf.length === 20 |
|||
&& this.chunks[2] === Opcode('OP_EQUAL').toNumber()) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
//note that these are frequently indistinguishable from pubkeyhashin
|
|||
Script.prototype.isScripthashIn = function() { |
|||
var allpush = this.chunks.every(function(chunk) { |
|||
return Buffer.isBuffer(chunk.buf); |
|||
}); |
|||
if (allpush) { |
|||
return true; |
|||
} else { |
|||
return false; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.write = function(obj) { |
|||
if (typeof obj === 'string') |
|||
this.writeOp(obj); |
|||
else if (typeof obj === 'number') |
|||
this.writeOp(obj); |
|||
else if (Buffer.isBuffer(obj)) |
|||
this.writeBuffer(obj); |
|||
else if (typeof obj === 'object') |
|||
this.chunks.push(obj); |
|||
else |
|||
throw new Error('Invalid script chunk'); |
|||
return this; |
|||
}; |
|||
|
|||
Script.prototype.writeOp = function(str) { |
|||
if (typeof str === 'number') |
|||
this.chunks.push(str); |
|||
else |
|||
this.chunks.push(Opcode(str).toNumber()); |
|||
return this; |
|||
}; |
|||
|
|||
Script.prototype.writeBuffer = function(buf) { |
|||
var opcodenum; |
|||
var len = buf.length; |
|||
if (buf.length > 0 && buf.length < Opcode.map.OP_PUSHDATA1) { |
|||
opcodenum = buf.length; |
|||
} else if (buf.length < Math.pow(2, 8)) { |
|||
opcodenum = Opcode.map.OP_PUSHDATA1; |
|||
} else if (buf.length < Math.pow(2, 16)) { |
|||
opcodenum = Opcode.map.OP_PUSHDATA2; |
|||
} else if (buf.length < Math.pow(2, 32)) { |
|||
opcodenum = Opcode.map.OP_PUSHDATA4; |
|||
} else { |
|||
throw new Error("You can't push that much data"); |
|||
} |
|||
this.chunks.push({ |
|||
buf: buf, |
|||
len: len, |
|||
opcodenum: opcodenum |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
module.exports = Script; |
@ -0,0 +1,169 @@ |
|||
var BN = require('./bn'); |
|||
var Point = require('./point'); |
|||
var Pubkey = require('./pubkey'); |
|||
|
|||
var Signature = function Signature(r, s) { |
|||
if (!(this instanceof Signature)) |
|||
return new Signature(r, s); |
|||
if (r instanceof BN) { |
|||
this.set({ |
|||
r: r, |
|||
s: s |
|||
}); |
|||
} |
|||
else if (r) { |
|||
var obj = r; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Signature.prototype.set = function(obj) { |
|||
this.r = obj.r || this.r || undefined; |
|||
this.s = obj.s || this.s || undefined; |
|||
this.i = typeof obj.i !== 'undefined' ? obj.i : this.i; //public key recovery parameter in range [0, 3]
|
|||
this.compressed = typeof obj.compressed !== 'undefined' ? obj.compressed : this.compressed; //whether the recovered pubkey is compressed
|
|||
return this; |
|||
}; |
|||
|
|||
Signature.prototype.fromCompact = function(buf) { |
|||
var compressed = true; |
|||
if (i < 0) { |
|||
var compressed = false; |
|||
i = i + 4; |
|||
} |
|||
|
|||
var i = buf.slice(0, 1)[0] - 27 - 4; //TODO: handle uncompressed pubkeys
|
|||
|
|||
var b2 = buf.slice(1, 33); |
|||
var b3 = buf.slice(33, 65); |
|||
|
|||
if (!(i === 0 || i === 1 || i === 2 || i === 3)) |
|||
throw new Error('i must be 0, 1, 2, or 3'); |
|||
if (b2.length !== 32) |
|||
throw new Error('r must be 32 bytes'); |
|||
if (b3.length !== 32) |
|||
throw new Error('s must be 32 bytes'); |
|||
|
|||
this.compressed = compressed; |
|||
this.i = i; |
|||
this.r = BN().fromBuffer(b2); |
|||
this.s = BN().fromBuffer(b3); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
Signature.prototype.fromDER = function(buf) { |
|||
var obj = Signature.parseDER(buf); |
|||
this.r = obj.r; |
|||
this.s = obj.s; |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
Signature.prototype.fromString = function(str) { |
|||
var buf = new Buffer(str, 'hex'); |
|||
this.fromDER(buf); |
|||
|
|||
return this; |
|||
}; |
|||
|
|||
Signature.parseDER = function(buf) { |
|||
if (!Buffer.isBuffer(buf)) |
|||
throw new Error('DER formatted signature should be a buffer'); |
|||
|
|||
var header = buf[0]; |
|||
|
|||
if (header !== 0x30) |
|||
throw new Error('Header byte should be 0x30'); |
|||
|
|||
var length = buf[1]; |
|||
if (length !== buf.slice(2).length) |
|||
throw new Error('Length byte should length of what follows'); |
|||
|
|||
var rheader = buf[2 + 0]; |
|||
if (rheader !== 0x02) |
|||
throw new Error('Integer byte for r should be 0x02'); |
|||
|
|||
var rlength = buf[2 + 1]; |
|||
var rbuf = buf.slice(2 + 2, 2 + 2 + rlength); |
|||
var r = BN().fromBuffer(rbuf); |
|||
var rneg = buf[2 + 1 + 1] === 0x00 ? true : false; |
|||
if (rlength !== rbuf.length) |
|||
throw new Error('Length of r incorrect'); |
|||
|
|||
var sheader = buf[2 + 2 + rlength + 0]; |
|||
if (sheader !== 0x02) |
|||
throw new Error('Integer byte for s should be 0x02'); |
|||
|
|||
var slength = buf[2 + 2 + rlength + 1]; |
|||
var sbuf = buf.slice(2 + 2 + rlength + 2, 2 + 2 + rlength + 2 + slength); |
|||
var s = BN().fromBuffer(sbuf); |
|||
var sneg = buf[2 + 2 + rlength + 2 + 2] === 0x00 ? true : false; |
|||
if (slength !== sbuf.length) |
|||
throw new Error('Length of s incorrect'); |
|||
|
|||
var sumlength = 2 + 2 + rlength + 2 + slength; |
|||
if (length !== sumlength - 2) |
|||
throw new Error('Length of signature incorrect'); |
|||
|
|||
var obj = { |
|||
header: header, |
|||
length: length, |
|||
rheader: rheader, |
|||
rlength: rlength, |
|||
rneg: rneg, |
|||
rbuf: rbuf, |
|||
r: r, |
|||
sheader: sheader, |
|||
slength: slength, |
|||
sneg: sneg, |
|||
sbuf: sbuf, |
|||
s: s |
|||
}; |
|||
|
|||
return obj; |
|||
}; |
|||
|
|||
Signature.prototype.toCompact = function(i, compressed) { |
|||
i = typeof i === 'number' ? i : this.i; |
|||
compressed = typeof compressed === 'boolean' ? compressed : this.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}); |
|||
return Buffer.concat([b1, b2, b3]); |
|||
}; |
|||
|
|||
Signature.prototype.toDER = function() { |
|||
var rnbuf = this.r.toBuffer(); |
|||
var snbuf = this.s.toBuffer(); |
|||
|
|||
var rneg = rnbuf[0] & 0x80 ? true : false; |
|||
var sneg = snbuf[0] & 0x80 ? true : false; |
|||
|
|||
var rbuf = rneg ? Buffer.concat([new Buffer([0x00]), rnbuf]) : rnbuf; |
|||
var sbuf = sneg ? Buffer.concat([new Buffer([0x00]), snbuf]) : snbuf; |
|||
|
|||
var length = 2 + rbuf.length + 2 + sbuf.length; |
|||
var rlength = rbuf.length; |
|||
var slength = sbuf.length; |
|||
var rheader = 0x02; |
|||
var sheader = 0x02; |
|||
var header = 0x30; |
|||
|
|||
var der = Buffer.concat([new Buffer([header, length, rheader, rlength]), rbuf, new Buffer([sheader, slength]), sbuf]); |
|||
return der; |
|||
}; |
|||
|
|||
Signature.prototype.toString = function() { |
|||
var buf = this.toDER(); |
|||
return buf.toString('hex'); |
|||
}; |
|||
|
|||
module.exports = Signature; |
@ -0,0 +1,155 @@ |
|||
var Txin = require('./txin'); |
|||
var Txout = require('./txout'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var BufferReader = require('./bufferreader'); |
|||
var Varint = require('./varint'); |
|||
var Hash = require('./hash'); |
|||
|
|||
var Transaction = function Transaction(version, txinsvi, txins, txoutsvi, txouts, nlocktime) { |
|||
if (!(this instanceof Transaction)) |
|||
return new Transaction(version, txinsvi, txins, txoutsvi, txouts, nlocktime); |
|||
if (typeof version === 'number') { |
|||
this.initialize(); |
|||
this.set({ |
|||
version: version, |
|||
txinsvi: txinsvi, |
|||
txins: txins, |
|||
txoutsvi: txoutsvi, |
|||
txouts: txouts, |
|||
nlocktime: nlocktime |
|||
}); |
|||
} else if (Buffer.isBuffer(version)) { |
|||
//not necessary to initialize, since everything should be overwritten
|
|||
var txbuf = version; |
|||
this.fromBuffer(txbuf); |
|||
} else if (version) { |
|||
this.initialize(); |
|||
var obj = version; |
|||
this.set(obj); |
|||
} else { |
|||
this.initialize(); |
|||
} |
|||
}; |
|||
|
|||
Transaction.prototype.initialize = function() { |
|||
this.version = 1; |
|||
this.txinsvi = Varint(0); |
|||
this.txins = []; |
|||
this.txoutsvi = Varint(0); |
|||
this.txouts = []; |
|||
this.nlocktime = 0xffffffff; |
|||
return this; |
|||
}; |
|||
|
|||
Transaction.prototype.set = function(obj) { |
|||
this.version = typeof obj.version !== 'undefined' ? obj.version : this.version; |
|||
this.txinsvi = obj.txinsvi || this.txinsvi; |
|||
this.txins = obj.txins || this.txins; |
|||
this.txoutsvi = obj.txoutsvi || this.txoutsvi; |
|||
this.txouts = obj.txouts || this.txouts; |
|||
this.nlocktime = typeof obj.nlocktime !== 'undefined' ? obj.nlocktime : this.nlocktime; |
|||
return this; |
|||
}; |
|||
|
|||
Transaction.prototype.fromJSON = function(json) { |
|||
var txins = []; |
|||
json.txins.forEach(function(txin) { |
|||
txins.push(Txin().fromJSON(txin)); |
|||
}); |
|||
var txouts = []; |
|||
json.txouts.forEach(function(txout) { |
|||
txouts.push(Txout().fromJSON(txout)); |
|||
}); |
|||
this.set({ |
|||
version: json.version, |
|||
txinsvi: Varint().fromJSON(json.txinsvi), |
|||
txins: txins, |
|||
txoutsvi: Varint().fromJSON(json.txoutsvi), |
|||
txouts: txouts, |
|||
nlocktime: json.nlocktime |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Transaction.prototype.toJSON = function() { |
|||
var txins = []; |
|||
this.txins.forEach(function(txin) { |
|||
txins.push(txin.toJSON()); |
|||
}); |
|||
var txouts = []; |
|||
this.txouts.forEach(function(txout) { |
|||
txouts.push(txout.toJSON()); |
|||
}); |
|||
return { |
|||
version: this.version, |
|||
txinsvi: this.txinsvi.toJSON(), |
|||
txins: txins, |
|||
txoutsvi: this.txoutsvi.toJSON(), |
|||
txouts: txouts, |
|||
nlocktime: this.nlocktime |
|||
}; |
|||
}; |
|||
|
|||
Transaction.prototype.fromBuffer = function(buf) { |
|||
return this.fromBufferReader(BufferReader(buf)); |
|||
}; |
|||
|
|||
Transaction.prototype.fromBufferReader = function(br) { |
|||
this.version = br.readUInt32LE(); |
|||
this.txinsvi = Varint(br.readVarintBuf()); |
|||
var txinsnum = this.txinsvi.toNumber(); |
|||
this.txins = []; |
|||
for (var i = 0; i < txinsnum; i++) { |
|||
this.txins.push(Txin().fromBufferReader(br)); |
|||
} |
|||
this.txoutsvi = Varint(br.readVarintBuf()); |
|||
var txoutsnum = this.txoutsvi.toNumber(); |
|||
this.txouts = []; |
|||
for (var i = 0; i < txoutsnum; i++) { |
|||
this.txouts.push(Txout().fromBufferReader(br)); |
|||
} |
|||
this.nlocktime = br.readUInt32LE(); |
|||
return this; |
|||
}; |
|||
|
|||
Transaction.prototype.toBuffer = function() { |
|||
return this.toBufferWriter().concat(); |
|||
}; |
|||
|
|||
Transaction.prototype.toBufferWriter = function(bw) { |
|||
if (!bw) |
|||
bw = new BufferWriter(); |
|||
bw.writeUInt32LE(this.version); |
|||
bw.write(this.txinsvi.buf); |
|||
for (var i = 0; i < this.txins.length; i++) { |
|||
this.txins[i].toBufferWriter(bw); |
|||
} |
|||
bw.write(this.txoutsvi.buf) |
|||
for (var i = 0; i < this.txouts.length; i++) { |
|||
this.txouts[i].toBufferWriter(bw); |
|||
} |
|||
bw.writeUInt32LE(this.nlocktime); |
|||
return bw; |
|||
}; |
|||
|
|||
Transaction.prototype.hash = function() { |
|||
return Hash.sha256sha256(this.toBuffer()); |
|||
}; |
|||
|
|||
Transaction.prototype.id = function() { |
|||
return BufferReader(this.hash()).reverse().read(); |
|||
}; |
|||
|
|||
Transaction.prototype.pushin = function(txin) { |
|||
this.txins.push(txin); |
|||
this.txinsvi = Varint(this.txinsvi.toNumber() + 1); |
|||
return this; |
|||
}; |
|||
|
|||
Transaction.prototype.pushout = function(txout) { |
|||
this.txouts.push(txout); |
|||
this.txoutsvi = Varint(this.txoutsvi.toNumber() + 1); |
|||
return this; |
|||
}; |
|||
|
|||
module.exports = Transaction; |
@ -0,0 +1,81 @@ |
|||
var BufferReader = require('./bufferreader'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var Varint = require('./varint'); |
|||
var Script = require('./script'); |
|||
|
|||
var Txin = function Txin(txidbuf, txoutnum, scriptvi, script, seqnum) { |
|||
if (!(this instanceof Txin)) |
|||
return new Txin(txidbuf, txoutnum, scriptvi, script, seqnum); |
|||
if (Buffer.isBuffer(txidbuf)) { |
|||
if (txidbuf.length !== 32) |
|||
throw new Error('txidbuf must be 32 bytes'); |
|||
this.txidbuf = txidbuf; |
|||
this.txoutnum = txoutnum; |
|||
this.scriptvi = scriptvi; |
|||
this.script = script; |
|||
this.seqnum = seqnum; |
|||
} else if (txidbuf) { |
|||
var obj = txidbuf; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Txin.prototype.set = function(obj) { |
|||
this.txidbuf = obj.txidbuf || this.txidbuf; |
|||
this.txoutnum = typeof obj.txoutnum !== 'undefined' ? obj.txoutnum : this.txoutnum; |
|||
this.scriptvi = typeof obj.scriptvi !== 'undefined' ? obj.scriptvi : this.scriptvi; |
|||
this.script = obj.script || this.script; |
|||
this.seqnum = typeof obj.seqnum !== 'undefined' ? obj.seqnum : this.seqnum; |
|||
return this; |
|||
}; |
|||
|
|||
Txin.prototype.fromJSON = function(json) { |
|||
this.set({ |
|||
txidbuf: new Buffer(json.txidbuf, 'hex'), |
|||
txoutnum: json.txoutnum, |
|||
scriptvi: Varint().fromJSON(json.scriptvi), |
|||
script: Script().fromJSON(json.script), |
|||
seqnum: json.seqnum |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Txin.prototype.toJSON = function() { |
|||
return { |
|||
txidbuf: this.txidbuf.toString('hex'), |
|||
txoutnum: this.txoutnum, |
|||
scriptvi: this.scriptvi.toJSON(), |
|||
script: this.script.toJSON(), |
|||
seqnum: this.seqnum |
|||
}; |
|||
}; |
|||
|
|||
Txin.prototype.fromBuffer = function(buf) { |
|||
return this.fromBufferReader(BufferReader(buf)); |
|||
}; |
|||
|
|||
Txin.prototype.fromBufferReader = function(br) { |
|||
this.txidbuf = br.read(32); |
|||
this.txoutnum = br.readUInt32LE(); |
|||
this.scriptvi = Varint(br.readVarintBuf()); |
|||
this.script = Script().fromBuffer(br.read(this.scriptvi.toNumber())); |
|||
this.seqnum = br.readUInt32LE(); |
|||
return this; |
|||
}; |
|||
|
|||
Txin.prototype.toBuffer = function() { |
|||
return this.toBufferWriter().concat(); |
|||
}; |
|||
|
|||
Txin.prototype.toBufferWriter = function(bw) { |
|||
if (!bw) |
|||
bw = new BufferWriter(); |
|||
bw.write(this.txidbuf); |
|||
bw.writeUInt32LE(this.txoutnum); |
|||
bw.write(this.scriptvi.buf); |
|||
bw.write(this.script.toBuffer()); |
|||
bw.writeUInt32LE(this.seqnum); |
|||
return bw; |
|||
}; |
|||
|
|||
module.exports = Txin; |
@ -0,0 +1,71 @@ |
|||
var BN = require('./bn'); |
|||
var BufferReader = require('./bufferreader'); |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var Varint = require('./varint'); |
|||
var Script = require('./script'); |
|||
|
|||
var Txout = function Txout(valuebn, scriptvi, script) { |
|||
if (!(this instanceof Txout)) |
|||
return new Txout(valuebn, scriptvi, script); |
|||
if (valuebn instanceof BN) { |
|||
this.set({ |
|||
valuebn: valuebn, |
|||
scriptvi: scriptvi, |
|||
script: script |
|||
}); |
|||
} else if (valuebn) { |
|||
var obj = valuebn; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Txout.prototype.set = function(obj) { |
|||
this.valuebn = obj.valuebn || this.valuebn; |
|||
this.scriptvi = obj.scriptvi || this.scriptvi; |
|||
this.script = obj.script || this.script; |
|||
return this; |
|||
}; |
|||
|
|||
Txout.prototype.fromJSON = function(json) { |
|||
this.set({ |
|||
valuebn: BN().fromJSON(json.valuebn), |
|||
scriptvi: Varint().fromJSON(json.scriptvi), |
|||
script: Script().fromJSON(json.script) |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Txout.prototype.toJSON = function() { |
|||
return { |
|||
valuebn: this.valuebn.toJSON(), |
|||
scriptvi: this.scriptvi.toJSON(), |
|||
script: this.script.toJSON() |
|||
}; |
|||
}; |
|||
|
|||
Txout.prototype.fromBuffer = function(buf) { |
|||
return this.fromBufferReader(BufferReader(buf)); |
|||
}; |
|||
|
|||
Txout.prototype.fromBufferReader = function(br) { |
|||
this.valuebn = br.readUInt64LEBN(); |
|||
this.scriptvi = Varint(br.readVarintNum()); |
|||
this.script = Script().fromBuffer(br.read(this.scriptvi.toNumber())); |
|||
return this; |
|||
}; |
|||
|
|||
Txout.prototype.toBuffer = function() { |
|||
var bw = new BufferWriter(); |
|||
return this.toBufferWriter(bw).concat(); |
|||
}; |
|||
|
|||
Txout.prototype.toBufferWriter = function(bw) { |
|||
if (!bw) |
|||
bw = new BufferWriter(); |
|||
bw.writeUInt64LEBN(this.valuebn); |
|||
bw.write(this.scriptvi.buf); |
|||
bw.write(this.script.toBuffer()); |
|||
return bw; |
|||
}; |
|||
|
|||
module.exports = Txout; |
@ -0,0 +1,70 @@ |
|||
var BufferWriter = require('./bufferwriter'); |
|||
var BufferReader = require('./bufferreader'); |
|||
var BN = require('./bn'); |
|||
|
|||
var Varint = function Varint(buf) { |
|||
if (!(this instanceof Varint)) |
|||
return new Varint(buf); |
|||
if (Buffer.isBuffer(buf)) { |
|||
this.buf = buf; |
|||
} else if (typeof buf === 'number') { |
|||
var num = buf; |
|||
this.fromNumber(num); |
|||
} else if (buf instanceof BN) { |
|||
var bn = buf; |
|||
this.fromBN(bn); |
|||
} else if (buf) { |
|||
var obj = buf; |
|||
this.set(obj); |
|||
} |
|||
}; |
|||
|
|||
Varint.prototype.set = function(obj) { |
|||
this.buf = obj.buf || this.buf; |
|||
return this; |
|||
}; |
|||
|
|||
Varint.prototype.fromJSON = function(json) { |
|||
this.set({ |
|||
buf: new Buffer(json, 'hex') |
|||
}); |
|||
return this; |
|||
}; |
|||
|
|||
Varint.prototype.toJSON = function() { |
|||
return this.buf.toString('hex'); |
|||
}; |
|||
|
|||
Varint.prototype.fromBuffer = function(buf) { |
|||
this.buf = buf; |
|||
return this; |
|||
}; |
|||
|
|||
Varint.prototype.fromBufferReader = function(br) { |
|||
this.buf = br.readVarintBuf(); |
|||
return this; |
|||
}; |
|||
|
|||
Varint.prototype.fromBN = function(bn) { |
|||
this.buf = BufferWriter().writeVarintBN(bn).concat(); |
|||
return this; |
|||
}; |
|||
|
|||
Varint.prototype.fromNumber = function(num) { |
|||
this.buf = BufferWriter().writeVarintNum(num).concat(); |
|||
return this; |
|||
}; |
|||
|
|||
Varint.prototype.toBuffer = function() { |
|||
return this.buf; |
|||
}; |
|||
|
|||
Varint.prototype.toBN = function() { |
|||
return BufferReader(this.buf).readVarintBN(); |
|||
}; |
|||
|
|||
Varint.prototype.toNumber = function() { |
|||
return BufferReader(this.buf).readVarintNum(); |
|||
}; |
|||
|
|||
module.exports = Varint; |
@ -0,0 +1,58 @@ |
|||
{ |
|||
"name": "bitcore2", |
|||
"version": "0.0.0", |
|||
"dependencies": { |
|||
"aes": { |
|||
"version": "0.1.0", |
|||
"from": "aes@=0.1.0", |
|||
"resolved": "https://registry.npmjs.org/aes/-/aes-0.1.0.tgz" |
|||
}, |
|||
"bn.js": { |
|||
"version": "0.14.0", |
|||
"from": "bn.js@0.14.0", |
|||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-0.14.0.tgz" |
|||
}, |
|||
"bs58": { |
|||
"version": "1.2.1", |
|||
"from": "bs58@=1.2.1", |
|||
"resolved": "https://registry.npmjs.org/bs58/-/bs58-1.2.1.tgz" |
|||
}, |
|||
"elliptic": { |
|||
"version": "0.15.10", |
|||
"from": "elliptic@0.15.10", |
|||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-0.15.10.tgz", |
|||
"dependencies": { |
|||
"bn.js": { |
|||
"version": "0.11.7", |
|||
"from": "bn.js@0.11.7", |
|||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-0.11.7.tgz" |
|||
}, |
|||
"hash.js": { |
|||
"version": "0.2.1", |
|||
"from": "hash.js@0.2.1", |
|||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-0.2.1.tgz" |
|||
}, |
|||
"inherits": { |
|||
"version": "2.0.1", |
|||
"from": "inherits@^2.0.1" |
|||
} |
|||
} |
|||
}, |
|||
"hash.js": { |
|||
"version": "0.3.1", |
|||
"from": "hash.js@0.3.1", |
|||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-0.3.1.tgz", |
|||
"dependencies": { |
|||
"inherits": { |
|||
"version": "2.0.1", |
|||
"from": "inherits@^2.0.1" |
|||
} |
|||
} |
|||
}, |
|||
"sha512": { |
|||
"version": "0.0.1", |
|||
"from": "sha512@=0.0.1", |
|||
"resolved": "https://registry.npmjs.org/sha512/-/sha512-0.0.1.tgz" |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,79 @@ |
|||
{ |
|||
"name": "fullnode", |
|||
"version": "0.0.0", |
|||
"description": "Bitcoin library, CLI and API.", |
|||
"author": "Ryan X. Charles <ryanxcharles@gmail.com>", |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"test": "mocha" |
|||
}, |
|||
"contributors": [ |
|||
{ |
|||
"name": "Daniel Cousens", |
|||
"email": "bitcoin@dcousens.com" |
|||
}, |
|||
{ |
|||
"name": "Gordon Hall", |
|||
"email": "gordon@bitpay.com" |
|||
}, |
|||
{ |
|||
"name": "Jeff Garzik", |
|||
"email": "jgarzik@bitpay.com" |
|||
}, |
|||
{ |
|||
"name": "Kyle Drake", |
|||
"email": "kyle@kyledrake.net" |
|||
}, |
|||
{ |
|||
"name": "Manuel Araoz", |
|||
"email": "manuelaraoz@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "Matias Alejo Garcia", |
|||
"email": "ematiu@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "Ryan X. Charles", |
|||
"email": "ryanxcharles@gmail.com" |
|||
}, |
|||
{ |
|||
"name": "Stefan Thomas", |
|||
"email": "moon@justmoon.net" |
|||
}, |
|||
{ |
|||
"name": "Stephen Pair", |
|||
"email": "stephen@bitpay.com" |
|||
}, |
|||
{ |
|||
"name": "Wei Lu", |
|||
"email": "luwei.here@gmail.com" |
|||
} |
|||
], |
|||
"keywords": [ |
|||
"bitcoin", |
|||
"bip32", |
|||
"bip37", |
|||
"bip70", |
|||
"stealth", |
|||
"merge", |
|||
"multisig" |
|||
], |
|||
"repository": { |
|||
"type": "git", |
|||
"url": "https://github.com/ryanxcharles/fullnode.git" |
|||
}, |
|||
"dependencies": { |
|||
"aes": "=0.1.0", |
|||
"bn.js": "=0.14.0", |
|||
"bs58": "=1.2.1", |
|||
"elliptic": "=0.15.10", |
|||
"hash.js": "=0.3.1", |
|||
"sha512": "=0.0.1" |
|||
}, |
|||
"devDependencies": { |
|||
"chai": "~1.9.1", |
|||
"mocha": "~1.21.0", |
|||
"browserify": "~5.9.1" |
|||
}, |
|||
"license": "MIT" |
|||
} |
@ -0,0 +1,203 @@ |
|||
var should = require('chai').should(); |
|||
var constants = require('../lib/constants'); |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var Address = require('../lib/address'); |
|||
var Script = require('../lib/script'); |
|||
|
|||
describe('Address', function() { |
|||
var pubkeyhash = new Buffer('3c3fa3d4adcaf8f52d5b1843975e122548269937', 'hex'); |
|||
var buf = Buffer.concat([new Buffer([0]), pubkeyhash]); |
|||
var str = '16VZnHwRhwrExfeHFHGjwrgEMq8VcYPs9r'; |
|||
|
|||
it('should create a new address object', function() { |
|||
var address = new Address(); |
|||
should.exist(address); |
|||
address = Address(buf); |
|||
should.exist(address); |
|||
address = Address(str); |
|||
should.exist(address); |
|||
}); |
|||
|
|||
describe('@isValid', function() { |
|||
|
|||
it('should validate this valid address string', function() { |
|||
Address.isValid(str).should.equal(true); |
|||
}); |
|||
|
|||
it('should invalidate this valid address string', function() { |
|||
Address.isValid(str.substr(1)).should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should make an address from a buffer', function() { |
|||
Address().fromBuffer(buf).toString().should.equal(str); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromHashbuf', function() { |
|||
|
|||
it('should make an address from a hashbuf', function() { |
|||
Address().fromHashbuf(pubkeyhash).toString().should.equal(str); |
|||
var a = Address().fromHashbuf(pubkeyhash, 'testnet', 'scripthash'); |
|||
a.networkstr.should.equal('testnet'); |
|||
a.typestr.should.equal('scripthash'); |
|||
}); |
|||
|
|||
it('should throw an error for invalid length hashbuf', function() { |
|||
(function() { |
|||
Address().fromHashbuf(buf); |
|||
}).should.throw('hashbuf must be exactly 20 bytes'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromPubkey', function() { |
|||
|
|||
it('should make this address from a compressed pubkey', function() { |
|||
var pubkey = new Pubkey(); |
|||
pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004', 'hex')); |
|||
var address = new Address(); |
|||
address.fromPubkey(pubkey); |
|||
address.toString().should.equal('19gH5uhqY6DKrtkU66PsZPUZdzTd11Y7ke'); |
|||
}); |
|||
|
|||
it('should make this address from an uncompressed pubkey', function() { |
|||
var pubkey = new Pubkey(); |
|||
pubkey.fromDER(new Buffer('0285e9737a74c30a873f74df05124f2aa6f53042c2fc0a130d6cbd7d16b944b004', 'hex')); |
|||
var address = new Address(); |
|||
pubkey.compressed = false; |
|||
address.fromPubkey(pubkey, 'mainnet'); |
|||
address.toString().should.equal('16JXnhxjJUhxfyx4y6H4sFcxrgt8kQ8ewX'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromScript', function() { |
|||
|
|||
it('should make this address from a script', function() { |
|||
var script = Script().fromString("OP_CHECKMULTISIG"); |
|||
var address = Address().fromScript(script); |
|||
address.toString().should.equal('3BYmEwgV2vANrmfRymr1mFnHXgLjD6gAWm'); |
|||
}); |
|||
|
|||
it('should make this address from other script', function() { |
|||
var script = Script().fromString("OP_CHECKSIG OP_HASH160"); |
|||
var address = Address().fromScript(script); |
|||
address.toString().should.equal('347iRqVwks5r493N1rsLN4k9J7Ljg488W7'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should derive from this known address string mainnet', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex')); |
|||
}); |
|||
|
|||
it('should derive from this known address string testnet', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.networkstr = 'testnet'; |
|||
address.fromString(address.toString()); |
|||
address.toString().should.equal('mm1X5M2QWyHVjn7txrF7mmtZDpjCXzoa98'); |
|||
}); |
|||
|
|||
it('should derive from this known address string mainnet scripthash', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.networkstr = 'mainnet'; |
|||
address.typestr = 'scripthash'; |
|||
address.fromString(address.toString()); |
|||
address.toString().should.equal('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); |
|||
}); |
|||
|
|||
it('should derive from this known address string testnet scripthash', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.networkstr = 'testnet'; |
|||
address.typestr = 'scripthash'; |
|||
address.fromString(address.toString()); |
|||
address.toString().should.equal('2MxjnmaMtsJfyFcyG3WZCzS2RihdNuWqeX4'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isValid', function() { |
|||
|
|||
it('should describe this valid address as valid', function() { |
|||
var address = new Address(); |
|||
address.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); |
|||
address.isValid().should.equal(true); |
|||
}); |
|||
|
|||
it('should describe this address with unknown network as invalid', function() { |
|||
var address = new Address(); |
|||
address.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); |
|||
address.networkstr = 'unknown'; |
|||
address.isValid().should.equal(false); |
|||
}); |
|||
|
|||
it('should describe this address with unknown type as invalid', function() { |
|||
var address = new Address(); |
|||
address.fromString('37BahqRsFrAd3qLiNNwLNV3AWMRD7itxTo'); |
|||
address.typestr = 'unknown'; |
|||
address.isValid().should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should output this known hash', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.toBuffer().slice(1).toString('hex').should.equal(pubkeyhash.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should output the same thing that was input', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.toString().should.equal(str); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#validate', function() { |
|||
|
|||
it('should not throw an error on this valid address', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
should.exist(address.validate()); |
|||
}); |
|||
|
|||
it('should throw an error on this invalid network', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.networkstr = 'unknown'; |
|||
(function() { |
|||
address.validate(); |
|||
}).should.throw('networkstr must be "mainnet" or "testnet"'); |
|||
}); |
|||
|
|||
it('should throw an error on this invalid type', function() { |
|||
var address = new Address(); |
|||
address.fromString(str); |
|||
address.typestr = 'unknown'; |
|||
(function() { |
|||
address.validate(); |
|||
}).should.throw('typestr must be "pubkeyhash" or "scripthash"'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,85 @@ |
|||
var should = require('chai').should(); |
|||
var Hash = require('../lib/hash'); |
|||
var AES = require('../lib/expmt/aes'); |
|||
|
|||
describe('AES', function() { |
|||
var m128 = Hash.sha256(new Buffer('test1')).slice(0, 128 / 8); |
|||
|
|||
var k128 = Hash.sha256(new Buffer('test2')).slice(0, 128 / 8); |
|||
var k192 = Hash.sha256(new Buffer('test2')).slice(0, 192 / 8); |
|||
var k256 = Hash.sha256(new Buffer('test2')).slice(0, 256 / 8); |
|||
|
|||
var e128 = new Buffer('3477e13884125038f4dc24e9d2cfbbc7', 'hex'); |
|||
var e192 = new Buffer('b670954c0e2da1aaa5f9063de04eb961', 'hex'); |
|||
var e256 = new Buffer('dd2ce24581183a4a7c0b1068f8bc79f0', 'hex'); |
|||
|
|||
|
|||
describe('@encrypt', function() { |
|||
|
|||
it('should encrypt with a 128 bit key', function() { |
|||
var encbuf = AES.encrypt(m128, k128); |
|||
encbuf.toString('hex').should.equal(e128.toString('hex')); |
|||
}); |
|||
|
|||
it('should encrypt with a 192 bit key', function() { |
|||
var encbuf = AES.encrypt(m128, k192); |
|||
encbuf.toString('hex').should.equal(e192.toString('hex')); |
|||
}); |
|||
|
|||
it('should encrypt with a 256 bit key', function() { |
|||
var encbuf = AES.encrypt(m128, k256); |
|||
encbuf.toString('hex').should.equal(e256.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decrypt', function() { |
|||
|
|||
it('should encrypt/decrypt with a 128 bit key', function() { |
|||
var encbuf = AES.encrypt(m128, k128); |
|||
var m = AES.decrypt(encbuf, k128); |
|||
m.toString('hex').should.equal(m128.toString('hex')); |
|||
}); |
|||
|
|||
it('should encrypt/decrypt with a 192 bit key', function() { |
|||
var encbuf = AES.encrypt(m128, k192); |
|||
var m = AES.decrypt(encbuf, k192); |
|||
m.toString('hex').should.equal(m128.toString('hex')); |
|||
}); |
|||
|
|||
it('should encrypt/decrypt with a 256 bit key', function() { |
|||
var encbuf = AES.encrypt(m128, k256); |
|||
var m = AES.decrypt(encbuf, k256); |
|||
m.toString('hex').should.equal(m128.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@buf2words', function() { |
|||
|
|||
it('should convert this 4 length buffer into an array', function() { |
|||
var buf = new Buffer([0, 0, 0, 0]); |
|||
var words = AES.buf2words(buf); |
|||
words.length.should.equal(1); |
|||
}); |
|||
|
|||
it('should throw an error on this 5 length buffer', function() { |
|||
var buf = new Buffer([0, 0, 0, 0, 0]); |
|||
(function() { |
|||
var words = AES.buf2words(buf); |
|||
}).should.throw(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@words2buf', function() { |
|||
|
|||
it('should convert this array into a buffer', function() { |
|||
var a = [100, 0]; |
|||
var buf = AES.words2buf(a); |
|||
buf.length.should.equal(8); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,73 @@ |
|||
var should = require('chai').should(); |
|||
var AESCBC = require('../lib/expmt/aescbc'); |
|||
|
|||
describe('AESCBC', function() { |
|||
|
|||
describe('@encrypt', function() { |
|||
|
|||
it('should return encrypt one block', function() { |
|||
var password = "password"; |
|||
var messagebuf = new Buffer(128 / 8 - 1); |
|||
messagebuf.fill(0); |
|||
var encbuf = AESCBC.encrypt(messagebuf, password); |
|||
encbuf.length.should.equal(128 / 8 + 128 / 8); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decrypt', function() { |
|||
|
|||
it('should decrypt that which was encrypted', function() { |
|||
var password = "password"; |
|||
var messagebuf = new Buffer(128 / 8 - 1); |
|||
messagebuf.fill(0); |
|||
var encbuf = AESCBC.encrypt(messagebuf, password); |
|||
var messagebuf2 = AESCBC.decrypt(encbuf, password); |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encryptCipherkey', function() { |
|||
|
|||
it('should return encrypt one block', function() { |
|||
var cipherkeybuf = new Buffer(256 / 8); |
|||
cipherkeybuf.fill(0x10); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0); |
|||
var messagebuf = new Buffer(128 / 8 - 1); |
|||
messagebuf.fill(0); |
|||
var encbuf = AESCBC.encryptCipherkey(messagebuf, cipherkeybuf, ivbuf); |
|||
encbuf.length.should.equal(128 / 8 + 128 / 8); |
|||
}); |
|||
|
|||
it('should return encrypt two blocks', function() { |
|||
var cipherkeybuf = new Buffer(256 / 8); |
|||
cipherkeybuf.fill(0x10); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0); |
|||
var messagebuf = new Buffer(128 / 8); |
|||
messagebuf.fill(0); |
|||
var encbuf = AESCBC.encryptCipherkey(messagebuf, cipherkeybuf, ivbuf); |
|||
encbuf.length.should.equal(128 / 8 + 128 / 8 + 128 / 8); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decryptCipherkey', function() { |
|||
|
|||
it('should decrypt that which was encrypted', function() { |
|||
var cipherkeybuf = new Buffer(256 / 8); |
|||
cipherkeybuf.fill(0x10); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0); |
|||
var messagebuf = new Buffer(128 / 8); |
|||
messagebuf.fill(0); |
|||
var encbuf = AESCBC.encryptCipherkey(messagebuf, cipherkeybuf, ivbuf); |
|||
var messagebuf2 = AESCBC.decryptCipherkey(encbuf, cipherkeybuf); |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,98 @@ |
|||
var Base58 = require('../lib/base58'); |
|||
var should = require('chai').should(); |
|||
|
|||
describe('Base58', function() { |
|||
var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]); |
|||
var enc = "1W7N4RuG"; |
|||
|
|||
it('should make an instance with "new"', function() { |
|||
var b58 = new Base58(); |
|||
should.exist(b58); |
|||
}); |
|||
|
|||
it('should make an instance without "new"', function() { |
|||
var b58 = Base58(); |
|||
should.exist(b58); |
|||
}); |
|||
|
|||
it('should allow this handy syntax', function() { |
|||
Base58(buf).toString().should.equal(enc); |
|||
Base58(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')) |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set a blank buffer', function() { |
|||
Base58().set({buf: new Buffer([])}); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encode', function() { |
|||
|
|||
it('should encode the buffer accurately', function() { |
|||
Base58.encode(buf).should.equal(enc); |
|||
}); |
|||
|
|||
it('should throw an error when the Input is not a buffer', function() { |
|||
(function() { |
|||
Base58.encode("string") |
|||
}).should.throw('Input should be a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decode', function() { |
|||
|
|||
it('should decode this encoded value correctly', function() { |
|||
Base58.decode(enc).toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should throw an error when Input is not a string', function() { |
|||
(function() { |
|||
Base58.decode(5); |
|||
}).should.throw('Input should be a string'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should not fail', function() { |
|||
should.exist(Base58().fromBuffer(buf)); |
|||
}); |
|||
|
|||
it('should set buffer', function() { |
|||
var b58 = Base58().fromBuffer(buf); |
|||
b58.buf.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should convert this known string to a buffer', function() { |
|||
Base58().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should return the buffer', function() { |
|||
var b58 = Base58({buf: buf}); |
|||
b58.buf.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should return the buffer', function() { |
|||
var b58 = Base58({buf: buf}); |
|||
b58.toString().should.equal(enc); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,114 @@ |
|||
var should = require('chai').should(); |
|||
var Base58Check = require('../lib/base58check'); |
|||
var base58 = require('../lib/base58'); |
|||
|
|||
describe('Base58Check', function() { |
|||
var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]); |
|||
var enc = "14HV44ipwoaqfg"; |
|||
|
|||
it('should make an instance with "new"', function() { |
|||
var b58 = new Base58Check(); |
|||
should.exist(b58); |
|||
}); |
|||
|
|||
it('should make an instance without "new"', function() { |
|||
var b58 = Base58Check(); |
|||
should.exist(b58); |
|||
}); |
|||
|
|||
it('should allow this handy syntax', function() { |
|||
Base58Check(buf).toString().should.equal(enc); |
|||
Base58Check(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set a buf', function() { |
|||
should.exist(Base58Check().set({buf: buf}).buf); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encode', function() { |
|||
|
|||
it('should encode the buffer accurately', function() { |
|||
Base58Check.encode(buf).should.equal(enc); |
|||
}); |
|||
|
|||
it('should throw an error when the input is not a buffer', function() { |
|||
(function() { |
|||
Base58Check.encode("string") |
|||
}).should.throw('Input must be a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decode', function() { |
|||
|
|||
it('should decode this encoded value correctly', function() { |
|||
Base58Check.decode(enc).toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should throw an error when input is not a string', function() { |
|||
(function() { |
|||
Base58Check.decode(5); |
|||
}).should.throw('Input must be a string'); |
|||
}); |
|||
|
|||
it('should throw an error when input is too short', function() { |
|||
(function() { |
|||
Base58Check.decode(enc.slice(0, 1)); |
|||
}).should.throw('Input string too short'); |
|||
}); |
|||
|
|||
it('should throw an error when there is a checksum mismatch', function() { |
|||
var buf2 = base58.decode(enc); |
|||
buf2[0] = buf2[0] + 1; |
|||
var enc2 = base58.encode(buf2); |
|||
(function() { |
|||
Base58Check.decode(enc2); |
|||
}).should.throw('Checksum mismatch'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should not fail', function() { |
|||
should.exist(Base58Check().fromBuffer(buf)); |
|||
}); |
|||
|
|||
it('should set buffer', function() { |
|||
var b58 = Base58Check().fromBuffer(buf); |
|||
b58.buf.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should convert this known string to a buffer', function() { |
|||
Base58Check().fromString(enc).toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should return the buffer', function() { |
|||
var b58 = Base58Check({buf: buf}); |
|||
b58.buf.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should return the buffer', function() { |
|||
var b58 = Base58Check({buf: buf}); |
|||
b58.toString().should.equal(enc); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,359 @@ |
|||
var should = require('chai').should(); |
|||
var constants = require('../lib/constants'); |
|||
var BIP32 = require('../lib/bip32'); |
|||
|
|||
describe('BIP32', function() { |
|||
|
|||
//test vectors: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
|
|||
var vector1_master = '000102030405060708090a0b0c0d0e0f'; |
|||
var vector1_m_public = 'xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8' |
|||
var vector1_m_private = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'; |
|||
var vector1_m0h_public = 'xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw'; |
|||
var vector1_m0h_private = 'xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7'; |
|||
var vector1_m0h1_public = 'xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ'; |
|||
var vector1_m0h1_private = 'xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs'; |
|||
var vector1_m0h12h_public = 'xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5'; |
|||
var vector1_m0h12h_private = 'xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM'; |
|||
var vector1_m0h12h2_public = 'xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV'; |
|||
var vector1_m0h12h2_private = 'xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334'; |
|||
var vector1_m0h12h21000000000_public = 'xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy'; |
|||
var vector1_m0h12h21000000000_private = 'xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76'; |
|||
var vector2_master = 'fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542'; |
|||
var vector2_m_public = 'xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB'; |
|||
var vector2_m_private = 'xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U'; |
|||
var vector2_m0_public = 'xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH'; |
|||
var vector2_m0_private = 'xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt'; |
|||
var vector2_m02147483647h_public = 'xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a'; |
|||
var vector2_m02147483647h_private = 'xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9'; |
|||
var vector2_m02147483647h1_public = 'xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon'; |
|||
var vector2_m02147483647h1_private = 'xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef'; |
|||
var vector2_m02147483647h12147483646h_public = 'xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL'; |
|||
var vector2_m02147483647h12147483646h_private = 'xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc'; |
|||
var vector2_m02147483647h12147483646h2_public = 'xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt'; |
|||
var vector2_m02147483647h12147483646h2_private = 'xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j'; |
|||
|
|||
it('should make a new a bip32', function() { |
|||
var bip32; |
|||
bip32 = new BIP32(); |
|||
should.exist(bip32); |
|||
bip32 = BIP32(); |
|||
should.exist(bip32); |
|||
new BIP32(vector1_m_private).toString().should.equal(vector1_m_private); |
|||
BIP32(vector1_m_private).toString().should.equal(vector1_m_private); |
|||
BIP32(BIP32(vector1_m_private)).toString().should.equal(vector1_m_private); |
|||
}); |
|||
|
|||
it('should initialize test vector 1 from the extended public key', function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_public); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should initialize test vector 1 from the extended private key', function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should get the extended public key from the extended private key for test vector 1', function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
bip32.xpubkeyString().should.equal(vector1_m_public); |
|||
}); |
|||
|
|||
it("should get m/0' ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector1_m0h_private); |
|||
}); |
|||
|
|||
it("should get m/0' ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector1_m0h_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1 ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector1_m0h1_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1 ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector1_m0h1_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1 ext. public key from m/0' public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'"); |
|||
var child_pub = new BIP32().fromString(child.xpubkeyString()); |
|||
var child2 = child_pub.derive("m/1"); |
|||
should.exist(child2); |
|||
child2.xpubkeyString().should.equal(vector1_m0h1_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector1_m0h12h_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector1_m0h12h_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2 ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector1_m0h12h2_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2'/2 ext. public key from m/0'/1/2' public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'"); |
|||
var child_pub = new BIP32().fromString(child.xpubkeyString()); |
|||
var child2 = child_pub.derive("m/2"); |
|||
should.exist(child2); |
|||
child2.xpubkeyString().should.equal(vector1_m0h12h2_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2 ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector1_m0h12h2_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2/1000000000 ext. private key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2/1000000000"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector1_m0h12h21000000000_private); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2h/2/1000000000 ext. public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2/1000000000"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector1_m0h12h21000000000_public); |
|||
}); |
|||
|
|||
it("should get m/0'/1/2'/2/1000000000 ext. public key from m/0'/1/2'/2 public key from test vector 1", function() { |
|||
var bip32 = new BIP32().fromString(vector1_m_private); |
|||
var child = bip32.derive("m/0'/1/2'/2"); |
|||
var child_pub = new BIP32().fromString(child.xpubkeyString()); |
|||
var child2 = child_pub.derive("m/1000000000"); |
|||
should.exist(child2); |
|||
child2.xpubkeyString().should.equal(vector1_m0h12h21000000000_public); |
|||
}); |
|||
|
|||
it('should initialize test vector 2 from the extended public key', function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_public); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should initialize test vector 2 from the extended private key', function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
should.exist(bip32); |
|||
}); |
|||
|
|||
it('should get the extended public key from the extended private key for test vector 2', function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
bip32.xpubkeyString().should.equal(vector2_m_public); |
|||
}); |
|||
|
|||
it("should get m/0 ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector2_m0_private); |
|||
}); |
|||
|
|||
it("should get m/0 ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector2_m0_public); |
|||
}); |
|||
|
|||
it("should get m/0 ext. public key from m public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m"); |
|||
var child_pub = new BIP32().fromString(child.xpubkeyString()); |
|||
var child2 = child_pub.derive("m/0"); |
|||
should.exist(child2); |
|||
child2.xpubkeyString().should.equal(vector2_m0_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector2_m02147483647h_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector2_m02147483647h_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1 ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector2_m02147483647h1_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1 ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector2_m02147483647h1_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1 ext. public key from m/0/2147483647h public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'"); |
|||
var child_pub = new BIP32().fromString(child.xpubkeyString()); |
|||
var child2 = child_pub.derive("m/1"); |
|||
should.exist(child2); |
|||
child2.xpubkeyString().should.equal(vector2_m02147483647h1_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector2_m02147483647h12147483646h_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector2_m02147483647h12147483646h_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h/2 ext. private key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'/2"); |
|||
should.exist(child); |
|||
child.xprivkeyString().should.equal(vector2_m02147483647h12147483646h2_private); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h/2 ext. public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'/2"); |
|||
should.exist(child); |
|||
child.xpubkeyString().should.equal(vector2_m02147483647h12147483646h2_public); |
|||
}); |
|||
|
|||
it("should get m/0/2147483647h/1/2147483646h/2 ext. public key from m/0/2147483647h/2147483646h public key from test vector 2", function() { |
|||
var bip32 = new BIP32().fromString(vector2_m_private); |
|||
var child = bip32.derive("m/0/2147483647'/1/2147483646'"); |
|||
var child_pub = new BIP32().fromString(child.xpubkeyString()); |
|||
var child2 = child_pub.derive("m/2"); |
|||
should.exist(child2); |
|||
child2.xpubkeyString().should.equal(vector2_m02147483647h12147483646h2_public); |
|||
}); |
|||
|
|||
describe('testnet', function() { |
|||
it('should initialize a new BIP32 correctly from a random BIP32', function() { |
|||
var b1 = new BIP32(); |
|||
b1.fromRandom('testnet'); |
|||
var b2 = new BIP32().fromString(b1.xpubkeyString()); |
|||
b2.xpubkeyString().should.equal(b1.xpubkeyString()); |
|||
}); |
|||
|
|||
it('should generate valid ext pub key for testnet', function() { |
|||
var b = new BIP32(); |
|||
b.fromRandom('testnet'); |
|||
b.xpubkeyString().substring(0,4).should.equal('tpub'); |
|||
}); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
var bip32 = BIP32(vector1_m_private); |
|||
var bip322 = BIP32().set({ |
|||
version: bip32.version, |
|||
depth: bip32.depth, |
|||
parentfingerprint: bip32.parentfingerprint, |
|||
childindex: bip32.childindex, |
|||
chaincode: bip32.chaincode, |
|||
key: bip32.key, |
|||
hasprivkey: bip32.hasprivkey, |
|||
pubkeyhash: bip32.pubKeyhash, |
|||
xpubkey: bip32.xpubkey, |
|||
xprivkey: bip32.xprivkey |
|||
}); |
|||
bip322.toString().should.equal(bip32.toString()); |
|||
bip322.set({}).toString().should.equal(bip32.toString()); |
|||
}); |
|||
|
|||
describe('#seed', function() { |
|||
|
|||
it('should initialize a new BIP32 correctly from test vector 1 seed', function() { |
|||
var hex = vector1_master; |
|||
var bip32 = (new BIP32()).fromSeed(new Buffer(hex, 'hex'), 'mainnet'); |
|||
should.exist(bip32); |
|||
bip32.xprivkeyString().should.equal(vector1_m_private); |
|||
bip32.xpubkeyString().should.equal(vector1_m_public); |
|||
}); |
|||
|
|||
it('should initialize a new BIP32 correctly from test vector 2 seed', function() { |
|||
var hex = vector2_master; |
|||
var bip32 = (new BIP32()).fromSeed(new Buffer(hex, 'hex'), 'mainnet'); |
|||
should.exist(bip32); |
|||
bip32.xprivkeyString().should.equal(vector2_m_private); |
|||
bip32.xpubkeyString().should.equal(vector2_m_public); |
|||
}); |
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should make a bip32 from a string', function() { |
|||
var str = 'xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi'; |
|||
var bip32 = new BIP32().fromString(str); |
|||
should.exist(bip32); |
|||
bip32.toString().should.equal(str); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
var bip32 = new BIP32(); |
|||
bip32.fromRandom('mainnet'); |
|||
var tip32 = new BIP32(); |
|||
tip32.fromRandom('testnet'); |
|||
|
|||
it('should return an xprv string', function() { |
|||
bip32.toString().slice(0, 4).should.equal('xprv'); |
|||
}); |
|||
|
|||
it('should return an xpub string', function() { |
|||
var bip32b = new BIP32().fromString(bip32.xpubkeyString()); |
|||
bip32b.toString().slice(0, 4).should.equal('xpub'); |
|||
}); |
|||
|
|||
it('should return a tprv string', function() { |
|||
tip32.toString().slice(0, 4).should.equal('tprv'); |
|||
}); |
|||
|
|||
it('should return a tpub string', function() { |
|||
var tip32b = new BIP32().fromString(tip32.xpubkeyString()); |
|||
tip32b.toString().slice(0, 4).should.equal('tpub'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,151 @@ |
|||
var Blockheader = require('../lib/blockheader'); |
|||
var Block = require('../lib/block'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var Varint = require('../lib/varint'); |
|||
var should = require('chai').should(); |
|||
var Transaction = require('../lib/transaction'); |
|||
|
|||
describe('Block', function() { |
|||
|
|||
var txidhex = '8c9aa966d35bfeaf031409e0001b90ccdafd8d859799eb945a3c515b8260bcf2'; |
|||
var txhex = '01000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000'; |
|||
var txbuf = new Buffer(txhex, 'hex'); |
|||
var tx = Transaction().fromBuffer(txbuf); |
|||
var magicnum = 0xd9b4bef9; |
|||
var blocksize = 50; |
|||
bhhex = '0100000005050505050505050505050505050505050505050505050505050505050505050909090909090909090909090909090909090909090909090909090909090909020000000300000004000000'; |
|||
bhbuf = new Buffer(bhhex, 'hex'); |
|||
var bh = Blockheader().fromBuffer(bhbuf); |
|||
var txsvi = Varint(1); |
|||
var txs = [Transaction().fromBuffer(txbuf)]; |
|||
var block = Block().set({ |
|||
magicnum: magicnum, |
|||
blocksize: blocksize, |
|||
blockheader: bh, |
|||
txsvi: txsvi, |
|||
txs: txs |
|||
}); |
|||
var blockhex = 'f9beb4d93200000001000000050505050505050505050505050505050505050505050505050505050505050509090909090909090909090909090909090909090909090909090909090909090200000003000000040000000101000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000'; |
|||
var blockbuf = new Buffer(blockhex, 'hex'); |
|||
|
|||
var genesishex = 'f9beb4d91d0100000100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000'; |
|||
var genesisbuf = new Buffer(genesishex, 'hex'); |
|||
var genesisidhex = '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'; |
|||
|
|||
it('should make a new block', function() { |
|||
var block = new Block(); |
|||
should.exist(block); |
|||
block = Block(); |
|||
should.exist(block); |
|||
block = Block(blockbuf); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set these known values', function() { |
|||
var block = Block().set({ |
|||
magicnum: magicnum, |
|||
blocksize: blocksize, |
|||
blockheader: bh, |
|||
txsvi: txsvi, |
|||
txs: txs |
|||
}); |
|||
should.exist(block.magicnum); |
|||
should.exist(block.blocksize); |
|||
should.exist(block.blockheader); |
|||
should.exist(block.txsvi); |
|||
should.exist(block.txs); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set these known values', function() { |
|||
var block = Block().set({ |
|||
magicnum: magicnum, |
|||
blocksize: blocksize, |
|||
blockheader: bh.toJSON(), |
|||
txsvi: txsvi.toJSON(), |
|||
txs: [txs[0].toJSON()] |
|||
}); |
|||
should.exist(block.magicnum); |
|||
should.exist(block.blocksize); |
|||
should.exist(block.blockheader); |
|||
should.exist(block.txsvi); |
|||
should.exist(block.txs); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should recover these known values', function() { |
|||
var json = block.toJSON(); |
|||
should.exist(json.magicnum); |
|||
should.exist(json.blocksize); |
|||
should.exist(json.blockheader); |
|||
should.exist(json.txsvi); |
|||
should.exist(json.txs); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should make a block from this known buffer', function() { |
|||
var block = Block().fromBuffer(blockbuf); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should make a block from this known buffer', function() { |
|||
var block = Block().fromBufferReader(BufferReader(blockbuf)); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should recover a block from this known buffer', function() { |
|||
var block = Block().fromBuffer(blockbuf); |
|||
block.toBuffer().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBufferWriter', function() { |
|||
|
|||
it('should recover a block from this known buffer', function() { |
|||
var block = Block().fromBuffer(blockbuf); |
|||
block.toBufferWriter().concat().toString('hex').should.equal(blockhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#hash', function() { |
|||
|
|||
it('should return the correct hash of the genesis block', function() { |
|||
var block = Block().fromBuffer(genesisbuf); |
|||
var blockhash = new Buffer(Array.apply([], new Buffer(genesisidhex, 'hex')).reverse()); |
|||
block.hash().toString('hex').should.equal(blockhash.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#id', function() { |
|||
|
|||
it('should return the correct id of the genesis block', function() { |
|||
var block = Block().fromBuffer(genesisbuf); |
|||
block.id().toString('hex').should.equal(genesisidhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,124 @@ |
|||
var Blockheader = require('../lib/blockheader'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var should = require('chai').should(); |
|||
|
|||
describe('Blockheader', function() { |
|||
|
|||
var bh = new Blockheader(); |
|||
var version = 1; |
|||
var prevblockidbuf = new Buffer(32); |
|||
prevblockidbuf.fill(5); |
|||
var merklerootbuf = new Buffer(32); |
|||
merklerootbuf.fill(9); |
|||
var time = 2; |
|||
var bits = 3; |
|||
var nonce = 4; |
|||
bh.set({ |
|||
version: version, |
|||
prevblockidbuf: prevblockidbuf, |
|||
merklerootbuf: merklerootbuf, |
|||
time: time, |
|||
bits: bits, |
|||
nonce: nonce |
|||
}); |
|||
bhhex = '0100000005050505050505050505050505050505050505050505050505050505050505050909090909090909090909090909090909090909090909090909090909090909020000000300000004000000'; |
|||
bhbuf = new Buffer(bhhex, 'hex'); |
|||
|
|||
it('should make a new blockheader', function() { |
|||
var blockheader = new Blockheader(); |
|||
should.exist(blockheader); |
|||
blockheader = Blockheader(); |
|||
should.exist(blockheader); |
|||
Blockheader(bhbuf).toBuffer().toString('hex').should.equal(bhhex); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set all the variables', function() { |
|||
bh.set({ |
|||
version: version, |
|||
prevblockidbuf: prevblockidbuf, |
|||
merklerootbuf: merklerootbuf, |
|||
time: time, |
|||
bits: bits, |
|||
nonce: nonce |
|||
}); |
|||
should.exist(bh.version); |
|||
should.exist(bh.prevblockidbuf); |
|||
should.exist(bh.merklerootbuf); |
|||
should.exist(bh.time); |
|||
should.exist(bh.bits); |
|||
should.exist(bh.nonce); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set all the variables', function() { |
|||
var bh = Blockheader().fromJSON({ |
|||
version: version, |
|||
prevblockidbuf: prevblockidbuf.toString('hex'), |
|||
merklerootbuf: merklerootbuf.toString('hex'), |
|||
time: time, |
|||
bits: bits, |
|||
nonce: nonce |
|||
}); |
|||
should.exist(bh.version); |
|||
should.exist(bh.prevblockidbuf); |
|||
should.exist(bh.merklerootbuf); |
|||
should.exist(bh.time); |
|||
should.exist(bh.bits); |
|||
should.exist(bh.nonce); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should set all the variables', function() { |
|||
var json = bh.toJSON(); |
|||
should.exist(json.version); |
|||
should.exist(json.prevblockidbuf); |
|||
should.exist(json.merklerootbuf); |
|||
should.exist(json.time); |
|||
should.exist(json.bits); |
|||
should.exist(json.nonce); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should parse this known buffer', function() { |
|||
Blockheader().fromBuffer(bhbuf).toBuffer().toString('hex').should.equal(bhhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should parse this known buffer', function() { |
|||
Blockheader().fromBufferReader(BufferReader(bhbuf)).toBuffer().toString('hex').should.equal(bhhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should output this known buffer', function() { |
|||
Blockheader().fromBuffer(bhbuf).toBuffer().toString('hex').should.equal(bhhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBufferWriter', function() { |
|||
|
|||
it('should output this known buffer', function() { |
|||
Blockheader().fromBuffer(bhbuf).toBufferWriter().concat().toString('hex').should.equal(bhhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,154 @@ |
|||
var chai = chai || require('chai'); |
|||
var should = chai.should(); |
|||
var assert = chai.assert; |
|||
var BN = require('../lib/bn'); |
|||
|
|||
describe('BN', function() { |
|||
it('should create a bn', function() { |
|||
var bn = new BN(50); |
|||
should.exist(bn); |
|||
bn.toString().should.equal('50'); |
|||
}); |
|||
|
|||
it('should parse this number', function() { |
|||
var bn = new BN(999970000); |
|||
bn.toString().should.equal('999970000'); |
|||
}); |
|||
|
|||
it('should parse numbers below and at bn.js internal word size', function() { |
|||
var bn = new BN(Math.pow(2, 26) - 1); |
|||
bn.toString().should.equal((Math.pow(2, 26) - 1).toString()); |
|||
var bn = new BN(Math.pow(2, 26)); |
|||
bn.toString().should.equal((Math.pow(2, 26)).toString()); |
|||
}); |
|||
|
|||
describe('#add', function() { |
|||
|
|||
it('should add two small numbers together', function() { |
|||
var bn1 = new BN(50); |
|||
var bn2 = new BN(75); |
|||
var bn3 = bn1.add(bn2); |
|||
bn3.toString().should.equal('125'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sub', function() { |
|||
|
|||
it('should subtract a small number', function() { |
|||
var bn1 = new BN(50); |
|||
var bn2 = new BN(25); |
|||
var bn3 = bn1.sub(bn2); |
|||
bn3.toString().should.equal('25'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#gt', function() { |
|||
|
|||
it('should say 1 is greater than 0', function() { |
|||
var bn1 = new BN(1); |
|||
var bn0 = new BN(0); |
|||
bn1.gt(bn0).should.equal(true); |
|||
}); |
|||
|
|||
it('should say a big number is greater than a small big number', function() { |
|||
var bn1 = new BN('24023452345398529485723980457'); |
|||
var bn0 = new BN('34098234283412341234049357'); |
|||
bn1.gt(bn0).should.equal(true); |
|||
}); |
|||
|
|||
it('should say a big number is great than a standard number', function() { |
|||
var bn1 = new BN('24023452345398529485723980457'); |
|||
var bn0 = new BN(5); |
|||
bn1.gt(bn0).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should make BN from a string', function() { |
|||
BN().fromJSON('5').toString().should.equal('5'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should make string from a BN', function() { |
|||
BN(5).toJSON().should.equal('5'); |
|||
BN().fromJSON('5').toJSON().should.equal('5'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should make BN from a string', function() { |
|||
BN().fromString('5').toString().should.equal('5'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should make a string', function() { |
|||
BN(5).toString().should.equal('5'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@fromBuffer', function() { |
|||
|
|||
it('should work with big endian', function() { |
|||
var bn = BN.fromBuffer(new Buffer('0001', 'hex'), {endian: 'big'}); |
|||
bn.toString().should.equal('1'); |
|||
}); |
|||
|
|||
it('should work with big endian 256', function() { |
|||
var bn = BN.fromBuffer(new Buffer('0100', 'hex'), {endian: 'big'}); |
|||
bn.toString().should.equal('256'); |
|||
}); |
|||
|
|||
it('should work with little endian if we specify the size', function() { |
|||
var bn = BN.fromBuffer(new Buffer('0100', 'hex'), {size: 2, endian: 'little'}); |
|||
bn.toString().should.equal('1'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should work as a prototype method', function() { |
|||
var bn = BN().fromBuffer(new Buffer('0100', 'hex'), {size: 2, endian: 'little'}); |
|||
bn.toString().should.equal('1'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should create a 4 byte buffer', function() { |
|||
var bn = new BN(1); |
|||
bn.toBuffer({size: 4}).toString('hex').should.equal('00000001'); |
|||
}); |
|||
|
|||
it('should create a 4 byte buffer in little endian', function() { |
|||
var bn = new BN(1); |
|||
bn.toBuffer({size: 4, endian: 'little'}).toString('hex').should.equal('01000000'); |
|||
}); |
|||
|
|||
it('should create a 2 byte buffer even if you ask for a 1 byte', function() { |
|||
var bn = new BN('ff00', 16); |
|||
bn.toBuffer({size: 1}).toString('hex').should.equal('ff00'); |
|||
}); |
|||
|
|||
it('should create a 4 byte buffer even if you ask for a 1 byte', function() { |
|||
var bn = new BN('ffffff00', 16); |
|||
bn.toBuffer({size: 4}).toString('hex').should.equal('ffffff00'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,274 @@ |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var should = require('chai').should(); |
|||
var BN = require('../lib/bn'); |
|||
|
|||
describe('BufferReader', function() { |
|||
|
|||
it('should make a new BufferReader', function() { |
|||
var br = new BufferReader(); |
|||
should.exist(br); |
|||
br = BufferReader(); |
|||
should.exist(br); |
|||
}); |
|||
|
|||
it('should create a new bufferreader with a buffer', function() { |
|||
var buf = new Buffer(0); |
|||
var br = new BufferReader(buf); |
|||
should.exist(br); |
|||
Buffer.isBuffer(br.buf).should.equal(true); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set pos', function() { |
|||
should.exist(BufferReader().set({pos: 1}).pos); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#eof', function() { |
|||
|
|||
it('should return true for a blank br', function() { |
|||
var br = new BufferReader({buf: new Buffer([])}); |
|||
br.eof().should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('read', function() { |
|||
|
|||
it('should return the same buffer', function() { |
|||
var buf = new Buffer([0]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.read().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should return a buffer of this length', function() { |
|||
var buf = new Buffer(10); |
|||
buf.fill(0); |
|||
var br = new BufferReader(buf); |
|||
var buf2 = br.read(2); |
|||
buf2.length.should.equal(2); |
|||
br.eof().should.equal(false); |
|||
br.pos.should.equal(2); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt8', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(1); |
|||
buf.writeUInt8(1, 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt8().should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt16BE', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(2); |
|||
buf.writeUInt16BE(1, 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt16BE().should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt16LE', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(2); |
|||
buf.writeUInt16LE(1, 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt16LE().should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt32BE', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(4); |
|||
buf.writeUInt32BE(1, 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt32BE().should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt32LE', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(4); |
|||
buf.writeUInt32LE(1, 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt32LE().should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt64BEBN', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(8); |
|||
buf.fill(0); |
|||
buf.writeUInt32BE(1, 4); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt64BEBN().toNumber().should.equal(1); |
|||
}); |
|||
|
|||
it('should return 2^64', function() { |
|||
var buf = new Buffer(8); |
|||
buf.fill(0xff); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt64BEBN().toNumber().should.equal(Math.pow(2, 64)); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readUInt64LEBN', function() { |
|||
|
|||
it('should return 1', function() { |
|||
var buf = new Buffer(8); |
|||
buf.fill(0); |
|||
buf.writeUInt32LE(1, 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt64LEBN().toNumber().should.equal(1); |
|||
}); |
|||
|
|||
it('should return 2^30', function() { |
|||
var buf = new Buffer(8); |
|||
buf.fill(0); |
|||
buf.writeUInt32LE(Math.pow(2, 30), 0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt64LEBN().toNumber().should.equal(Math.pow(2, 30)); |
|||
}); |
|||
|
|||
it('should return 0', function() { |
|||
var buf = new Buffer(8); |
|||
buf.fill(0); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt64LEBN().toNumber().should.equal(0); |
|||
}); |
|||
|
|||
it('should return 2^64', function() { |
|||
var buf = new Buffer(8); |
|||
buf.fill(0xff); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readUInt64LEBN().toNumber().should.equal(Math.pow(2, 64)); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readVarintBuf', function() { |
|||
|
|||
it('should read a 1 byte varint', function() { |
|||
var buf = new Buffer([50]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBuf().length.should.equal(1); |
|||
}); |
|||
|
|||
it('should read a 3 byte varint', function() { |
|||
var buf = new Buffer([253, 253, 0]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBuf().length.should.equal(3); |
|||
}); |
|||
|
|||
it('should read a 5 byte varint', function() { |
|||
var buf = new Buffer([254, 0, 0, 0, 0]); |
|||
buf.writeUInt32LE(50000, 1); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBuf().length.should.equal(5); |
|||
}); |
|||
|
|||
it('should read a 9 byte varint', function() { |
|||
var buf = BufferWriter().writeVarintBN(BN(Math.pow(2, 54).toString())).concat(); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBuf().length.should.equal(9); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readVarintNum', function() { |
|||
|
|||
it('should read a 1 byte varint', function() { |
|||
var buf = new Buffer([50]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintNum().should.equal(50); |
|||
}); |
|||
|
|||
it('should read a 3 byte varint', function() { |
|||
var buf = new Buffer([253, 253, 0]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintNum().should.equal(253); |
|||
}); |
|||
|
|||
it('should read a 5 byte varint', function() { |
|||
var buf = new Buffer([254, 0, 0, 0, 0]); |
|||
buf.writeUInt32LE(50000, 1); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintNum().should.equal(50000); |
|||
}); |
|||
|
|||
it('should throw an error on a 9 byte varint over the javascript uint precision limit', function() { |
|||
var buf = BufferWriter().writeVarintBN(BN(Math.pow(2, 54).toString())).concat(); |
|||
var br = new BufferReader({buf: buf}); |
|||
(function() { |
|||
br.readVarintNum(); |
|||
}).should.throw('number too large to retain precision - use readVarintBN'); |
|||
}); |
|||
|
|||
it('should not throw an error on a 9 byte varint not over the javascript uint precision limit', function() { |
|||
var buf = BufferWriter().writeVarintBN(BN(Math.pow(2, 53).toString())).concat(); |
|||
var br = new BufferReader({buf: buf}); |
|||
(function() { |
|||
br.readVarintNum(); |
|||
}).should.not.throw('number too large to retain precision - use readVarintBN'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#readVarintBN', function() { |
|||
|
|||
it('should read a 1 byte varint', function() { |
|||
var buf = new Buffer([50]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBN().toNumber().should.equal(50); |
|||
}); |
|||
|
|||
it('should read a 3 byte varint', function() { |
|||
var buf = new Buffer([253, 253, 0]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBN().toNumber().should.equal(253); |
|||
}); |
|||
|
|||
it('should read a 5 byte varint', function() { |
|||
var buf = new Buffer([254, 0, 0, 0, 0]); |
|||
buf.writeUInt32LE(50000, 1); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBN().toNumber().should.equal(50000); |
|||
}); |
|||
|
|||
it('should read a 9 byte varint', function() { |
|||
var buf = Buffer.concat([new Buffer([255]), new Buffer('ffffffffffffffff', 'hex')]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.readVarintBN().toNumber().should.equal(Math.pow(2, 64)); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#reverse', function() { |
|||
|
|||
it('should reverse this [0, 1]', function() { |
|||
var buf = new Buffer([0, 1]); |
|||
var br = new BufferReader({buf: buf}); |
|||
br.reverse().read().toString('hex').should.equal('0100'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,186 @@ |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var BN = require('../lib/bn'); |
|||
var should = require('chai').should(); |
|||
|
|||
describe('BufferWriter', function() { |
|||
|
|||
it('should create a new buffer writer', function() { |
|||
var bw = new BufferWriter(); |
|||
should.exist(bw); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('set bufs', function() { |
|||
var buf1 = new Buffer([0]); |
|||
var buf2 = new Buffer([1]); |
|||
var bufs = [buf1, buf2]; |
|||
var bw = new BufferWriter().set({bufs: [buf1, buf2]}); |
|||
bw.concat().toString('hex').should.equal('0001'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should concat these two bufs', function() { |
|||
var buf1 = new Buffer([0]); |
|||
var buf2 = new Buffer([1]); |
|||
var bw = new BufferWriter({bufs: [buf1, buf2]}); |
|||
bw.toBuffer().toString('hex').should.equal('0001'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#concat', function() { |
|||
|
|||
it('should concat these two bufs', function() { |
|||
var buf1 = new Buffer([0]); |
|||
var buf2 = new Buffer([1]); |
|||
var bw = new BufferWriter({bufs: [buf1, buf2]}); |
|||
bw.concat().toString('hex').should.equal('0001'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#write', function() { |
|||
|
|||
it('should write a buffer', function() { |
|||
var buf = new Buffer([0]); |
|||
var bw = new BufferWriter(); |
|||
bw.write(buf); |
|||
bw.concat().toString('hex').should.equal('00'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt8', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt8(1).concat().toString('hex').should.equal('01'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt16BE', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt16BE(1).concat().toString('hex').should.equal('0001'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt16LE', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt16LE(1).concat().toString('hex').should.equal('0100'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt32BE', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt32BE(1).concat().toString('hex').should.equal('00000001'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt32LE', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt32LE(1).concat().toString('hex').should.equal('01000000'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt64BEBN', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt64BEBN(BN(1)).concat().toString('hex').should.equal('0000000000000001'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeUInt64LEBN', function() { |
|||
|
|||
it('should write 1', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeUInt64LEBN(BN(1)).concat().toString('hex').should.equal('0100000000000000'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeVarint', function() { |
|||
|
|||
it('should write a 1 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintNum(1); |
|||
bw.concat().length.should.equal(1); |
|||
}); |
|||
|
|||
it('should write a 3 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintNum(1000); |
|||
bw.concat().length.should.equal(3); |
|||
}); |
|||
|
|||
it('should write a 5 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintNum(Math.pow(2, 16 + 1)); |
|||
bw.concat().length.should.equal(5); |
|||
}); |
|||
|
|||
it('should write a 9 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintNum(Math.pow(2, 32 + 1)); |
|||
bw.concat().length.should.equal(9); |
|||
}); |
|||
|
|||
it('should read back the same value it wrote for a 9 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
var n = Math.pow(2, 53); |
|||
n.should.equal(n + 1); //javascript number precision limit
|
|||
bw.writeVarintNum(n); |
|||
var br = new BufferReader({buf: bw.concat()}); |
|||
br.readVarintBN().toNumber().should.equal(n); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeVarintBN', function() { |
|||
|
|||
it('should write a 1 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintBN(BN(1)); |
|||
bw.concat().length.should.equal(1); |
|||
}); |
|||
|
|||
it('should write a 3 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintBN(BN(1000)); |
|||
bw.concat().length.should.equal(3); |
|||
}); |
|||
|
|||
it('should write a 5 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintBN(BN(Math.pow(2, 16 + 1))); |
|||
bw.concat().length.should.equal(5); |
|||
}); |
|||
|
|||
it('should write a 9 byte varint', function() { |
|||
var bw = new BufferWriter(); |
|||
bw.writeVarintBN(BN(Math.pow(2, 32 + 1))); |
|||
bw.concat().length.should.equal(9); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,317 @@ |
|||
var AES = require('../lib/expmt/aes'); |
|||
var should = require('chai').should(); |
|||
var CBC = require('../lib/expmt/cbc'); |
|||
|
|||
describe('CBC', function() { |
|||
|
|||
it('should return a new CBC', function() { |
|||
var cbc = new CBC(); |
|||
should.exist(cbc); |
|||
}) |
|||
|
|||
it('should return a new CBC when called without "new"', function() { |
|||
var cbc = new CBC(); |
|||
should.exist(cbc); |
|||
}); |
|||
|
|||
describe('@buf2blockbufs', function() { |
|||
|
|||
it('should convert this buffer into one block', function() { |
|||
var buf = new Buffer(16 - 1); |
|||
buf.fill(0); |
|||
var blockbufs = CBC.buf2blockbufs(buf, 16 * 8); |
|||
blockbufs.length.should.equal(1); |
|||
blockbufs[0].toString('hex').should.equal('00000000000000000000000000000001'); |
|||
}); |
|||
|
|||
it('should convert this buffer into two blocks', function() { |
|||
var buf = new Buffer(16); |
|||
buf.fill(0); |
|||
var blockbufs = CBC.buf2blockbufs(buf, 16 * 8); |
|||
blockbufs.length.should.equal(2); |
|||
blockbufs[0].toString('hex').should.equal('00000000000000000000000000000000'); |
|||
blockbufs[1].toString('hex').should.equal('10101010101010101010101010101010'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@buf2blockbufs', function() { |
|||
|
|||
it('should convert this buffer into one block and back into the same buffer', function() { |
|||
var buf = new Buffer(16 - 1); |
|||
buf.fill(0); |
|||
var blockbufs = CBC.buf2blockbufs(buf, 16 * 8); |
|||
var buf2 = CBC.blockbufs2buf(blockbufs, 16 * 8); |
|||
buf2.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should convert this buffer into two blocks and back into the same buffer', function() { |
|||
var buf = new Buffer(16); |
|||
buf.fill(0); |
|||
var blockbufs = CBC.buf2blockbufs(buf, 16 * 8); |
|||
var buf2 = CBC.blockbufs2buf(blockbufs, 16 * 8); |
|||
buf2.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encrypt', function() { |
|||
|
|||
it('should return this known value', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(128 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var messagebuf = Buffer.concat([messagebuf1, messagebuf2]); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
blockcipher.decrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbuf = CBC.encrypt(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
var buf2 = CBC.decrypt(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
}); |
|||
|
|||
it('should return this shorter known value', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(120 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var messagebuf = Buffer.concat([messagebuf1, messagebuf2]); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
blockcipher.decrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbuf = CBC.encrypt(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
var buf2 = CBC.decrypt(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
}); |
|||
|
|||
it('should return this shorter known value', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(136 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var messagebuf = Buffer.concat([messagebuf1, messagebuf2]); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
blockcipher.decrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbuf = CBC.encrypt(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
var buf2 = CBC.decrypt(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
}); |
|||
|
|||
it('should encrypt something with AES', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(128 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var messagebuf = Buffer.concat([messagebuf1, messagebuf2]); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = AES; |
|||
var encbuf = CBC.encrypt(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
var buf2 = CBC.decrypt(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
buf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decrypt', function() { |
|||
|
|||
it('should properly decrypt an encrypted message', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(128 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var messagebuf = Buffer.concat([messagebuf1, messagebuf2]); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
blockcipher.decrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbuf = CBC.encrypt(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
var messagebuf2 = CBC.decrypt(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encryptblock', function() { |
|||
|
|||
it('should return this known value', function() { |
|||
var messagebuf = new Buffer(128 / 8); |
|||
messagebuf.fill(0); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var enc = CBC.encryptblock(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
enc.toString('hex').should.equal(ivbuf.toString('hex')); |
|||
}); |
|||
|
|||
it('should return this other known value', function() { |
|||
var messagebuf = new Buffer(128 / 8); |
|||
messagebuf.fill(0x10); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var enc = CBC.encryptblock(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
enc.toString('hex').should.equal('00000000000000000000000000000000'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decryptblock', function() { |
|||
|
|||
it('should decrypt an encrypted block', function() { |
|||
var messagebuf = new Buffer(128 / 8); |
|||
messagebuf.fill(0); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {}; |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
blockcipher.decrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbuf = CBC.encryptblock(messagebuf, ivbuf, blockcipher, cipherkeybuf); |
|||
var buf = CBC.decryptblock(encbuf, ivbuf, blockcipher, cipherkeybuf); |
|||
buf.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encryptblocks', function() { |
|||
|
|||
it('should return this known value', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(128 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {} |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbufs = CBC.encryptblocks([messagebuf1, messagebuf2], ivbuf, blockcipher, cipherkeybuf); |
|||
encbufs[0].toString('hex').should.equal('10101010101010101010101010101010'); |
|||
encbufs[1].toString('hex').should.equal('00000000000000000000000000000000'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decryptblocks', function() { |
|||
|
|||
it('should decrypt encrypted blocks', function() { |
|||
var messagebuf1 = new Buffer(128 / 8); |
|||
messagebuf1.fill(0); |
|||
var messagebuf2 = new Buffer(128 / 8); |
|||
messagebuf2.fill(0x10); |
|||
var ivbuf = new Buffer(128 / 8); |
|||
ivbuf.fill(0x10); |
|||
var cipherkeybuf = new Buffer(128 / 8); |
|||
cipherkeybuf.fill(0); |
|||
var blockcipher = {} |
|||
blockcipher.encrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
blockcipher.decrypt = function(messagebuf, cipherkeybuf) { |
|||
return messagebuf; |
|||
}; |
|||
var encbufs = CBC.encryptblocks([messagebuf1, messagebuf2], ivbuf, blockcipher, cipherkeybuf); |
|||
var bufs = CBC.decryptblocks(encbufs, ivbuf, blockcipher, cipherkeybuf); |
|||
bufs[0].toString('hex').should.equal(messagebuf1.toString('hex')); |
|||
bufs[1].toString('hex').should.equal(messagebuf2.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@pkcs7pad', function() { |
|||
|
|||
it('should pad this 32 bit buffer to 128 bits with the number 128/8 - 32/8', function() { |
|||
var buf = new Buffer(32 / 8); |
|||
buf.fill(0); |
|||
var padbuf = CBC.pkcs7pad(buf, 128); |
|||
padbuf.length.should.equal(128 / 8); |
|||
padbuf[32 / 8].should.equal(128 / 8 - 32 / 8); |
|||
padbuf[32 / 8 + 1].should.equal(128 / 8 - 32 / 8); |
|||
// ...
|
|||
padbuf[32 / 8 + 128 / 8 - 32 / 8 - 1].should.equal(128 / 8 - 32 / 8); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@pkcs7unpad', function() { |
|||
|
|||
it('should unpad this padded 32 bit buffer', function() { |
|||
var buf = new Buffer(32 / 8); |
|||
buf.fill(0); |
|||
var paddedbuf = CBC.pkcs7pad(buf, 128); |
|||
var unpaddedbuf = CBC.pkcs7unpad(paddedbuf, 128); |
|||
unpaddedbuf.toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@xorbufs', function() { |
|||
|
|||
it('should xor 1 and 0', function() { |
|||
var buf1 = new Buffer([1]); |
|||
var buf2 = new Buffer([0]); |
|||
var buf = CBC.xorbufs(buf1, buf2); |
|||
buf[0].should.equal(1); |
|||
}); |
|||
|
|||
it('should xor 1 and 1', function() { |
|||
var buf1 = new Buffer([1]); |
|||
var buf2 = new Buffer([1]); |
|||
var buf = CBC.xorbufs(buf1, buf2); |
|||
buf[0].should.equal(0); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,213 @@ |
|||
var ECDSA = require('../lib/ecdsa'); |
|||
var Hash = require('../lib/hash'); |
|||
var Keypair = require('../lib/keypair'); |
|||
var Privkey = require('../lib/privkey'); |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var Signature = require('../lib/signature'); |
|||
var BN = require('../lib/bn'); |
|||
var point = require('../lib/point'); |
|||
var should = require('chai').should(); |
|||
|
|||
describe("ECDSA", function() { |
|||
|
|||
it('should create a blank ecdsa', function() { |
|||
var ecdsa = new ECDSA(); |
|||
}); |
|||
|
|||
var ecdsa = new ECDSA(); |
|||
ecdsa.hashbuf = Hash.sha256(new Buffer('test data')); |
|||
ecdsa.keypair = new Keypair(); |
|||
ecdsa.keypair.privkey = new Privkey({bn: BN().fromBuffer(new Buffer('fee0a1f7afebf9d2a5a80c0c98a31c709681cce195cbcd06342b517970c0be1e', 'hex'))}); |
|||
ecdsa.keypair.pubkey = new Pubkey({ |
|||
point: point(BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex')), |
|||
BN().fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex'))) |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set hashbuf', function() { |
|||
should.exist(ECDSA().set({hashbuf: ecdsa.hashbuf}).hashbuf); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#calci', function() { |
|||
|
|||
it('should calculate i', function() { |
|||
ecdsa.randomK(); |
|||
ecdsa.sign(); |
|||
ecdsa.calci(); |
|||
should.exist(ecdsa.sig.i); |
|||
}); |
|||
|
|||
it('should calulate this known i', function() { |
|||
var hashbuf = Hash.sha256(new Buffer('some data')); |
|||
var r = BN('71706645040721865894779025947914615666559616020894583599959600180037551395766', 10); |
|||
var s = BN('109412465507152403114191008482955798903072313614214706891149785278625167723646', 10); |
|||
var ecdsa = new ECDSA(); |
|||
ecdsa.keypair = new Keypair(); |
|||
ecdsa.keypair.privkey = Privkey(); |
|||
ecdsa.keypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test'))); |
|||
ecdsa.keypair.privkey2pubkey(); |
|||
ecdsa.hashbuf = hashbuf; |
|||
ecdsa.sig = new Signature({r: r, s: s}); |
|||
|
|||
ecdsa.calci(); |
|||
ecdsa.sig.i.should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should to a round trip with to string', function() { |
|||
var str = ecdsa.toString(); |
|||
var ecdsa2 = new ECDSA(); |
|||
ecdsa2.fromString(str); |
|||
should.exist(ecdsa.hashbuf); |
|||
should.exist(ecdsa.keypair); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#randomK', function() { |
|||
|
|||
it('should generate a new random k when called twice in a row', function() { |
|||
ecdsa.randomK(); |
|||
var k1 = ecdsa.k; |
|||
ecdsa.randomK(); |
|||
var k2 = ecdsa.k; |
|||
(k1.cmp(k2) === 0).should.equal(false); |
|||
}); |
|||
|
|||
it('should generate a random k that is (almost always) greater than this relatively small number', function() { |
|||
ecdsa.randomK(); |
|||
var k1 = ecdsa.k; |
|||
var k2 = BN(Math.pow(2, 32)).mul(BN(Math.pow(2, 32))).mul(BN(Math.pow(2, 32))); |
|||
k2.gt(k1).should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sig2pubkey', function() { |
|||
|
|||
it('should calculate the correct public key', function() { |
|||
ecdsa.k = BN('114860389168127852803919605627759231199925249596762615988727970217268189974335', 10); |
|||
ecdsa.sign(); |
|||
ecdsa.sig.i = 1; |
|||
var pubkey = ecdsa.sig2pubkey(); |
|||
pubkey.point.eq(ecdsa.keypair.pubkey.point).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sigError', function() { |
|||
|
|||
it('should return an error if the hash is invalid', function() { |
|||
var ecdsa = new ECDSA(); |
|||
ecdsa.sigError().should.equal('hashbuf must be a 32 byte buffer'); |
|||
}); |
|||
|
|||
it('should return an error if the pubkey is invalid', function() { |
|||
var ecdsa = new ECDSA(); |
|||
ecdsa.hashbuf = Hash.sha256(new Buffer('test')); |
|||
ecdsa.sigError().indexOf("Invalid pubkey").should.equal(0); |
|||
}); |
|||
|
|||
it('should return an error if r, s are invalid', function() { |
|||
var ecdsa = new ECDSA(); |
|||
ecdsa.hashbuf = Hash.sha256(new Buffer('test')); |
|||
var pk = new Pubkey(); |
|||
pk.fromDER(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex')); |
|||
ecdsa.keypair = new Keypair(); |
|||
ecdsa.keypair.pubkey = pk; |
|||
ecdsa.sig = new Signature(); |
|||
ecdsa.sig.r = BN(0); |
|||
ecdsa.sig.s = BN(0); |
|||
ecdsa.sigError().should.equal("r and s not in range"); |
|||
}); |
|||
|
|||
it('should return an error if the signature is incorrect', function() { |
|||
ecdsa.sig = new Signature(); |
|||
ecdsa.sig.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827'); |
|||
ecdsa.sig.r = ecdsa.sig.r.add(BN(1)); |
|||
ecdsa.sigError().should.equal("Invalid signature"); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sign', function() { |
|||
|
|||
it('should create a valid signature', function() { |
|||
ecdsa.randomK(); |
|||
ecdsa.sign(); |
|||
ecdsa.verify().should.equal(true); |
|||
}); |
|||
|
|||
it('should should throw an error if hashbuf is not 32 bytes', function() { |
|||
var ecdsa2 = ECDSA().set({ |
|||
hashbuf: ecdsa.hashbuf.slice(0, 31), |
|||
keypair: ecdsa.keypair |
|||
}); |
|||
ecdsa2.randomK(); |
|||
(function() { |
|||
ecdsa2.sign(); |
|||
}).should.throw('hashbuf must be a 32 byte buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#signRandomK', function() { |
|||
|
|||
it('should produce a signature', function() { |
|||
ecdsa.signRandomK(); |
|||
should.exist(ecdsa.sig); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should convert this to a string', function() { |
|||
var str = ecdsa.toString(); |
|||
(typeof str === 'string').should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#verify', function() { |
|||
|
|||
it('should verify a signature that was just signed', function() { |
|||
ecdsa.sig = new Signature(); |
|||
ecdsa.sig.fromString('3046022100e9915e6236695f093a4128ac2a956c40ed971531de2f4f41ba05fac7e2bd019c02210094e6a4a769cc7f2a8ab3db696c7cd8d56bcdbfff860a8c81de4bc6a798b90827'); |
|||
ecdsa.verify().should.equal(true); |
|||
}); |
|||
|
|||
it('should verify this known good signature', function() { |
|||
ecdsa.signRandomK(); |
|||
ecdsa.verify().should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@sign', function() { |
|||
|
|||
it('should produce a signature', function() { |
|||
var sig = ECDSA.sign(ecdsa.hashbuf, ecdsa.keypair); |
|||
(sig instanceof Signature).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@verify', function() { |
|||
|
|||
it('should verify a valid signature, and unverify an invalid signature', function() { |
|||
var sig = ECDSA.sign(ecdsa.hashbuf, ecdsa.keypair); |
|||
ECDSA.verify(ecdsa.hashbuf, sig, ecdsa.keypair.pubkey).should.equal(true); |
|||
var fakesig = Signature(sig.r.add(1), sig.s); |
|||
ECDSA.verify(ecdsa.hashbuf, fakesig, ecdsa.keypair.pubkey).should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,52 @@ |
|||
var ECIES = require('../lib/expmt/ecies'); |
|||
var should = require('chai').should(); |
|||
var Keypair = require('../lib/keypair'); |
|||
var Hash = require('../lib/hash'); |
|||
|
|||
describe('#ECIES', function() { |
|||
|
|||
it('should make a new ECIES object', function() { |
|||
var ecies = new ECIES(); |
|||
should.exist(ecies); |
|||
}); |
|||
|
|||
it('should make a new ECIES object when called without "new"', function() { |
|||
var ecies = ECIES(); |
|||
should.exist(ecies); |
|||
}); |
|||
|
|||
var fromkey = Keypair().fromRandom(); |
|||
var tokey = Keypair().fromRandom(); |
|||
var messagebuf = Hash.sha256(new Buffer('my message is the hash of this string')); |
|||
|
|||
describe('@encrypt', function() { |
|||
|
|||
it('should return a buffer', function() { |
|||
var encbuf = ECIES.encrypt(messagebuf, tokey.pubkey, fromkey); |
|||
Buffer.isBuffer(encbuf).should.equal(true); |
|||
}); |
|||
|
|||
it('should return a buffer if fromkey is not present', function() { |
|||
var encbuf = ECIES.encrypt(messagebuf, tokey.pubkey); |
|||
Buffer.isBuffer(encbuf).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decrypt', function() { |
|||
|
|||
it('should decrypt that which was encrypted', function() { |
|||
var encbuf = ECIES.encrypt(messagebuf, tokey.pubkey, fromkey); |
|||
var messagebuf2 = ECIES.decrypt(encbuf, tokey.privkey); |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
it('should decrypt that which was encrypted if fromkeypair was randomly generated', function() { |
|||
var encbuf = ECIES.encrypt(messagebuf, tokey.pubkey); |
|||
var messagebuf2 = ECIES.decrypt(encbuf, tokey.privkey); |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,32 @@ |
|||
if (process.browser) |
|||
return; //examples are loaded from files, which doesn't work in the browser
|
|||
|
|||
var should = require('chai').should(); |
|||
var fs = require('fs'); |
|||
|
|||
describe('Examples', function() { |
|||
|
|||
var filenames = fs.readdirSync(__dirname + '/../examples/'); |
|||
|
|||
filenames.forEach(function(filename) { |
|||
|
|||
if (filename.slice(filename.length - 3) === '.js') { |
|||
|
|||
describe(filename, function() { |
|||
|
|||
it('should not throw any errors', function() { |
|||
(function() { |
|||
var save = console.log; |
|||
console.log = function() {}; |
|||
require('../examples/' + filename); |
|||
console.log = save; |
|||
}).should.not.throw(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
} |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,115 @@ |
|||
var should = require('chai').should(); |
|||
var Hash = require('../lib/hash'); |
|||
|
|||
describe('Hash', function() { |
|||
var buf = new Buffer([0, 1, 2, 3, 253, 254, 255]); |
|||
var str = "test string"; |
|||
|
|||
describe('#sha256', function() { |
|||
|
|||
it('should calculate the hash of this buffer correctly', function() { |
|||
var hash = Hash.sha256(buf); |
|||
hash.toString('hex').should.equal('6f2c7b22fd1626998287b3636089087961091de80311b9279c4033ec678a83e8'); |
|||
}); |
|||
|
|||
it('should throw an error when the input is not a buffer', function() { |
|||
(function() { |
|||
Hash.sha256(str); |
|||
}).should.throw('sha256 hash must be of a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sha256hmac', function() { |
|||
|
|||
it('should compute this known empty test vector correctly', function() { |
|||
var key = new Buffer(''); |
|||
var data = new Buffer(''); |
|||
Hash.sha256hmac(data, key).toString('hex').should.equal('b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad'); |
|||
}); |
|||
|
|||
it('should compute this known non-empty test vector correctly', function() { |
|||
var key = new Buffer('key'); |
|||
var data = new Buffer('The quick brown fox jumps over the lazy dog'); |
|||
Hash.sha256hmac(data, key).toString('hex').should.equal('f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sha256sha256', function() { |
|||
|
|||
it('should calculate the hash of this buffer correctly', function() { |
|||
var hash = Hash.sha256sha256(buf); |
|||
hash.toString('hex').should.equal('be586c8b20dee549bdd66018c7a79e2b67bb88b7c7d428fa4c970976d2bec5ba'); |
|||
}); |
|||
|
|||
it('should throw an error when the input is not a buffer', function() { |
|||
(function() { |
|||
Hash.sha256sha256(str); |
|||
}).should.throw('sha256sha256 hash must be of a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sha256ripemd160', function() { |
|||
|
|||
it('should calculate the hash of this buffer correctly', function() { |
|||
var hash = Hash.sha256ripemd160(buf); |
|||
hash.toString('hex').should.equal('7322e2bd8535e476c092934e16a6169ca9b707ec'); |
|||
}); |
|||
|
|||
it('should throw an error when the input is not a buffer', function() { |
|||
(function() { |
|||
Hash.sha256ripemd160(str); |
|||
}).should.throw('sha256ripemd160 hash must be of a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#ripemd160', function() { |
|||
|
|||
it('should calculate the hash of this buffer correctly', function() { |
|||
var hash = Hash.ripemd160(buf); |
|||
hash.toString('hex').should.equal('fa0f4565ff776fee0034c713cbf48b5ec06b7f5c'); |
|||
}); |
|||
|
|||
it('should throw an error when the input is not a buffer', function() { |
|||
(function() { |
|||
Hash.ripemd160(str); |
|||
}).should.throw('ripemd160 hash must be of a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sha512', function() { |
|||
|
|||
it('should calculate the hash of this buffer correctly', function() { |
|||
var hash = Hash.sha512(buf); |
|||
hash.toString('hex').should.equal('c0530aa32048f4904ae162bc14b9eb535eab6c465e960130005feddb71613e7d62aea75f7d3333ba06e805fc8e45681454524e3f8050969fe5a5f7f2392e31d0'); |
|||
}); |
|||
|
|||
it('should throw an error when the input is not a buffer', function() { |
|||
(function() { |
|||
Hash.sha512(str); |
|||
}).should.throw('sha512 hash must be of a buffer'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe("#sha512hmac", function() { |
|||
|
|||
it('should calculate this known empty test vector correctly', function() { |
|||
var hex = 'b936cee86c9f87aa5d3c6f2e84cb5a4239a5fe50480a6ec66b70ab5b1f4ac6730c6c515421b327ec1d69402e53dfb49ad7381eb067b338fd7b0cb22247225d47'; |
|||
Hash.sha512hmac(new Buffer([]), new Buffer([])).toString('hex').should.equal(hex); |
|||
}); |
|||
|
|||
it('should calculate this known non-empty test vector correctly', function() { |
|||
var hex = 'c40bd7c15aa493b309c940e08a73ffbd28b2e4cb729eb94480d727e4df577b13cc403a78e6150d83595f3b17c4cc331f12ca5952691de3735a63c1d4c69a2bac'; |
|||
var data = new Buffer("test1"); |
|||
var key = new Buffer("test2"); |
|||
Hash.sha512hmac(data, key).toString('hex').should.equal(hex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,18 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>Mocha</title> |
|||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|||
<link rel="stylesheet" href="../node_modules/mocha/mocha.css" /> |
|||
</head> |
|||
<body> |
|||
<div id="mocha"></div> |
|||
<script src="../node_modules/mocha/mocha.js"></script> |
|||
<script>mocha.setup('bdd')</script> |
|||
<script src="../browser/tests.js"></script> |
|||
<script> |
|||
mocha.run(); |
|||
</script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,39 @@ |
|||
var should = require('chai').should(); |
|||
var KDF = require('../lib/kdf'); |
|||
var Hash = require('../lib/hash'); |
|||
|
|||
describe('KDF', function() { |
|||
|
|||
describe('#buf2keypair', function() { |
|||
|
|||
it('should compute these known values', function() { |
|||
var buf = Hash.sha256(new Buffer('test')); |
|||
var keypair = KDF.buf2keypair(buf); |
|||
keypair.privkey.toString().should.equal('KxxVszVMFLGzmxpxR7sMSaWDmqMKLVhKebX5vZbGHyuR8spreQ7V'); |
|||
keypair.pubkey.toString().should.equal('03774f761ae89a0d2fda0d532bad62286ae8fcda9bc38c060036296085592a97c1'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sha256hmac2keypair', function() { |
|||
|
|||
it('should compute these known values', function() { |
|||
var buf = Hash.sha256(new Buffer('test')); |
|||
var keypair = KDF.sha256hmac2keypair(buf); |
|||
keypair.privkey.toString().should.equal('KxxVszVMFLGzmxpxR7sMSaWDmqMKLVhKebX5vZbGHyuR8spreQ7V'); |
|||
keypair.pubkey.toString().should.equal('03774f761ae89a0d2fda0d532bad62286ae8fcda9bc38c060036296085592a97c1'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sha256hmac2privkey', function() { |
|||
|
|||
it('should compute this known privkey', function() { |
|||
var buf = Hash.sha256(new Buffer('test')); |
|||
var privkey = KDF.sha256hmac2privkey(buf); |
|||
privkey.toString().should.equal('KxxVszVMFLGzmxpxR7sMSaWDmqMKLVhKebX5vZbGHyuR8spreQ7V'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,165 @@ |
|||
var should = require('chai').should(); |
|||
var bn = require('../lib/bn'); |
|||
var point = require('../lib/point'); |
|||
var Privkey = require('../lib/privkey'); |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var Keypair = require('../lib/keypair'); |
|||
|
|||
describe('Keypair', function() { |
|||
|
|||
it('should make a blank key', function() { |
|||
var key = new Keypair(); |
|||
should.exist(key); |
|||
}); |
|||
|
|||
it('should make a key with a priv and pub', function() { |
|||
var priv = new Privkey(); |
|||
var pub = new Pubkey(); |
|||
var key = new Keypair({privkey: priv, pubkey: pub}); |
|||
should.exist(key); |
|||
should.exist(key.privkey); |
|||
should.exist(key.pubkey); |
|||
}); |
|||
|
|||
describe("#set", function() { |
|||
|
|||
it('should make a new priv and pub', function() { |
|||
should.exist(Keypair().set({privkey: Privkey()}).privkey); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should make a keypair from this json', function() { |
|||
var privkey = Privkey().fromRandom(); |
|||
var pubkey = Pubkey().fromPrivkey(privkey); |
|||
var keypair = Keypair().fromJSON({ |
|||
privkey: privkey.toJSON(), |
|||
pubkey: pubkey.toJSON() |
|||
}) |
|||
keypair.privkey.toString().should.equal(privkey.toString()); |
|||
keypair.pubkey.toString().should.equal(pubkey.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should make json from this keypair', function() { |
|||
var json = Keypair().fromRandom().toJSON(); |
|||
should.exist(json.privkey); |
|||
should.exist(json.pubkey); |
|||
var keypair = Keypair().fromJSON(json); |
|||
keypair.toJSON().privkey.toString().should.equal(json.privkey.toString()); |
|||
keypair.toJSON().pubkey.toString().should.equal(json.pubkey.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe("#fromPrivkey", function() { |
|||
|
|||
it('should make a new key from a privkey', function() { |
|||
should.exist(Keypair().fromPrivkey(Privkey().fromRandom()).pubkey); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe("#fromRandom", function() { |
|||
|
|||
it('should make a new priv and pub, should be compressed, mainnet', function() { |
|||
var key = new Keypair(); |
|||
key.fromRandom(); |
|||
should.exist(key.privkey); |
|||
should.exist(key.pubkey); |
|||
key.privkey.bn.gt(bn(0)).should.equal(true); |
|||
key.pubkey.point.getX().gt(bn(0)).should.equal(true); |
|||
key.pubkey.point.getY().gt(bn(0)).should.equal(true); |
|||
key.privkey.compressed.should.equal(true); |
|||
key.privkey.networkstr.should.equal('mainnet'); |
|||
key.pubkey.compressed.should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe("#fromString()", function() { |
|||
|
|||
it('should recover a key creating with toString', function() { |
|||
var key = new Keypair(); |
|||
key.fromRandom(); |
|||
var priv = key.privkey; |
|||
var pub = key.pubkey; |
|||
var str = key.toString(); |
|||
key.fromString(str); |
|||
should.exist(key.privkey); |
|||
should.exist(key.pubkey); |
|||
key.privkey.toString().should.equal(priv.toString()); |
|||
key.pubkey.toString().should.equal(pub.toString()); |
|||
}); |
|||
|
|||
it('should work with only Privkey set', function() { |
|||
var key = new Keypair(); |
|||
key.fromRandom(); |
|||
key.pubkey = undefined; |
|||
var priv = key.privkey; |
|||
var str = key.toString(); |
|||
key.fromString(str); |
|||
should.exist(key.privkey); |
|||
key.privkey.toString().should.equal(priv.toString()); |
|||
}); |
|||
|
|||
it('should work with only Pubkey set', function() { |
|||
var key = new Keypair(); |
|||
key.fromRandom(); |
|||
key.privkey = undefined; |
|||
var pub = key.pubkey; |
|||
var str = key.toString(); |
|||
key.fromString(str); |
|||
should.exist(key.pubkey); |
|||
key.pubkey.toString().should.equal(pub.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe("#privkey2pubkey", function() { |
|||
|
|||
it('should convert this known Privkey to known Pubkey', function() { |
|||
var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; |
|||
var pubhex = '02a1633cafcc01ebfb6d78e39f687a1f0995c62fc95f51ead10a02ee0be551b5dc'; |
|||
var key = new Keypair(); |
|||
key.privkey = new Privkey({bn: bn(new Buffer(privhex, 'hex'))}); |
|||
key.privkey2pubkey(); |
|||
key.pubkey.toString().should.equal(pubhex); |
|||
}); |
|||
|
|||
it('should convert this known Privkey to known Pubkey and preserve compressed=true', function() { |
|||
var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; |
|||
var key = new Keypair(); |
|||
key.privkey = new Privkey({bn: bn(new Buffer(privhex, 'hex'))}); |
|||
key.privkey.compressed = true; |
|||
key.privkey2pubkey(); |
|||
key.pubkey.compressed.should.equal(true); |
|||
}); |
|||
|
|||
it('should convert this known Privkey to known Pubkey and preserve compressed=true', function() { |
|||
var privhex = '906977a061af29276e40bf377042ffbde414e496ae2260bbf1fa9d085637bfff'; |
|||
var key = new Keypair(); |
|||
key.privkey = new Privkey({bn: bn(new Buffer(privhex, 'hex'))}); |
|||
key.privkey.compressed = false; |
|||
key.privkey2pubkey(); |
|||
key.pubkey.compressed.should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe("#toString()", function() { |
|||
|
|||
it('should exist', function() { |
|||
var key = new Keypair(); |
|||
key.fromRandom(); |
|||
should.exist(key.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,107 @@ |
|||
var Address = require('../lib/address'); |
|||
var Message = require('../lib/message'); |
|||
var Keypair = require('../lib/keypair'); |
|||
var should = require('chai').should(); |
|||
|
|||
describe('Message', function() { |
|||
|
|||
it('should make a new message', function() { |
|||
var message = new Message(); |
|||
should.exist(message); |
|||
}); |
|||
|
|||
it('should make a new message when called without "new"', function() { |
|||
var message = Message(); |
|||
should.exist(message); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set the messagebuf', function() { |
|||
var messagebuf = new Buffer('message'); |
|||
should.exist(Message().set({messagebuf: messagebuf}).messagebuf); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@sign', function() { |
|||
var messagebuf = new Buffer('this is my message'); |
|||
var keypair = Keypair().fromRandom(); |
|||
|
|||
it('should return a base64 string', function() { |
|||
var sigstr = Message.sign(messagebuf, keypair); |
|||
var sigbuf = new Buffer(sigstr, 'base64'); |
|||
sigbuf.length.should.equal(1 + 32 + 32); |
|||
}); |
|||
|
|||
it('should sign with a compressed pubkey', function() { |
|||
var keypair = Keypair().fromRandom(); |
|||
keypair.pubkey.compressed = true; |
|||
var sigstr = Message.sign(messagebuf, keypair); |
|||
var sigbuf = new Buffer(sigstr, 'base64'); |
|||
sigbuf[0].should.be.above(27 + 4 - 1); |
|||
sigbuf[0].should.be.below(27 + 4 + 4 - 1); |
|||
}); |
|||
|
|||
it('should sign with an uncompressed pubkey', function() { |
|||
var keypair = Keypair().fromRandom(); |
|||
keypair.pubkey.compressed = false; |
|||
var sigstr = Message.sign(messagebuf, keypair); |
|||
var sigbuf = new Buffer(sigstr, 'base64'); |
|||
sigbuf[0].should.be.above(27 - 1); |
|||
sigbuf[0].should.be.below(27 + 4 - 1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@verify', function() { |
|||
var messagebuf = new Buffer('this is my message'); |
|||
var keypair = Keypair().fromRandom(); |
|||
|
|||
it('should verify a signed message', function() { |
|||
var sigstr = Message.sign(messagebuf, keypair); |
|||
var addr = Address().fromPubkey(keypair.pubkey); |
|||
Message.verify(messagebuf, sigstr, addr).should.equal(true); |
|||
}); |
|||
|
|||
it('should verify this known good signature', function() { |
|||
var addrstr = '1CKTmxj6DjGrGTfbZzVxnY4Besbv8oxSZb'; |
|||
var address = Address().fromString(addrstr); |
|||
var sigstr = 'IOrTlbNBI0QO990xOw4HAjnvRl/1zR+oBMS6HOjJgfJqXp/1EnFrcJly0UcNelqJNIAH4f0abxOZiSpYmenMH4M='; |
|||
Message.verify(messagebuf, sigstr, address); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#sign', function() { |
|||
var messagebuf = new Buffer('this is my message'); |
|||
var keypair = Keypair().fromRandom(); |
|||
|
|||
it('should sign a message', function() { |
|||
var message = new Message(); |
|||
message.messagebuf = messagebuf; |
|||
message.keypair = keypair; |
|||
message.sign(); |
|||
var sig = message.sig; |
|||
should.exist(sig); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#verify', function() { |
|||
var messagebuf = new Buffer('this is my message'); |
|||
var keypair = Keypair().fromRandom(); |
|||
|
|||
it('should verify a message that was just signed', function() { |
|||
var message = new Message(); |
|||
message.messagebuf = messagebuf; |
|||
message.keypair = keypair; |
|||
message.address = Address().fromPubkey(keypair.pubkey); |
|||
message.sign(); |
|||
message.verify(); |
|||
message.verified.should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,75 @@ |
|||
var should = require('chai').should(); |
|||
var Opcode = require('../lib/opcode'); |
|||
|
|||
describe('Opcode', function() { |
|||
|
|||
it('should create a new Opcode', function() { |
|||
var opcode = new Opcode(5); |
|||
}); |
|||
|
|||
it('should convert to a string with this handy syntax', function() { |
|||
Opcode(0).toString().should.equal('OP_0'); |
|||
Opcode(96).toString().should.equal('OP_16'); |
|||
Opcode(97).toString().should.equal('OP_NOP'); |
|||
}); |
|||
|
|||
it('should convert to a number with this handy syntax', function() { |
|||
Opcode('OP_0').toNumber().should.equal(0); |
|||
Opcode('OP_16').toNumber().should.equal(96); |
|||
Opcode('OP_NOP').toNumber().should.equal(97); |
|||
}); |
|||
|
|||
describe('#fromNumber', function() { |
|||
|
|||
it('should work for 0', function() { |
|||
Opcode().fromNumber(0).num.should.equal(0); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toNumber', function() { |
|||
|
|||
it('should work for 0', function() { |
|||
Opcode().fromNumber(0).toNumber().should.equal(0); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should work for OP_0', function() { |
|||
Opcode().fromString('OP_0').num.should.equal(0); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should work for OP_0', function() { |
|||
Opcode().fromString('OP_0').toString().should.equal('OP_0'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@map', function() { |
|||
|
|||
it('should have a map containing 116 elements', function() { |
|||
var i = 0; |
|||
for (var key in Opcode.map) { |
|||
i++; |
|||
} |
|||
i.should.equal(116); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@reverseMap', function() { |
|||
|
|||
it('should exist and have op 185', function() { |
|||
should.exist(Opcode.reverseMap); |
|||
Opcode.reverseMap[185].should.equal('OP_NOP10'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,117 @@ |
|||
var should = require('chai').should(); |
|||
var point = require('../lib/point'); |
|||
var BN = require('../lib/bn'); |
|||
|
|||
describe('Point', function() { |
|||
|
|||
it('should create a point', function() { |
|||
var p = point(); |
|||
should.exist(p); |
|||
}); |
|||
|
|||
it('should create a point when called with "new"', function() { |
|||
var p = new point(); |
|||
should.exist(p); |
|||
}); |
|||
|
|||
describe('#getX', function() { |
|||
|
|||
it('should return 0', function() { |
|||
var p = point(); |
|||
p.getX().toString().should.equal('0'); |
|||
}); |
|||
|
|||
it('should be convertable to a buffer', function() { |
|||
var p = point(); |
|||
p.getX().toBuffer({size: 32}).length.should.equal(32); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#getY', function() { |
|||
|
|||
it('should return 0', function() { |
|||
var p = point(); |
|||
p.getY().toString().should.equal('0'); |
|||
}); |
|||
|
|||
it('should be convertable to a buffer', function() { |
|||
var p = point(); |
|||
p.getY().toBuffer({size: 32}).length.should.equal(32); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#add', function() { |
|||
|
|||
it('should accurately add g to itself', function() { |
|||
var p1 = point.getG(); |
|||
var p2 = point.getG(); |
|||
var p3 = p1.add(p2); |
|||
p3.getX().toString().should.equal('89565891926547004231252920425935692360644145829622209833684329913297188986597'); |
|||
p3.getY().toString().should.equal('12158399299693830322967808612713398636155367887041628176798871954788371653930'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#mul', function() { |
|||
|
|||
it('should accurately multiply g by 2', function() { |
|||
var g = point.getG(); |
|||
var b = g.mul(BN(2)); |
|||
b.getX().toString().should.equal('89565891926547004231252920425935692360644145829622209833684329913297188986597'); |
|||
b.getY().toString().should.equal('12158399299693830322967808612713398636155367887041628176798871954788371653930'); |
|||
}); |
|||
|
|||
it('should accurately multiply g by n-1', function() { |
|||
var g = point.getG(); |
|||
var n = point.getN(); |
|||
var b = g.mul(n.sub(1)); |
|||
b.getX().toString().should.equal('55066263022277343669578718895168534326250603453777594175500187360389116729240'); |
|||
b.getY().toString().should.equal('83121579216557378445487899878180864668798711284981320763518679672151497189239'); |
|||
}); |
|||
|
|||
//not sure if this is technically accurate or not...
|
|||
//normally, you should always multiply g by something less than n
|
|||
//but it is the same result in OpenSSL
|
|||
it('should accurately multiply g by n+1', function() { |
|||
var g = point.getG(); |
|||
var n = point.getN(); |
|||
var b = g.mul(n.add(1)); |
|||
b.getX().toString().should.equal('55066263022277343669578718895168534326250603453777594175500187360389116729240'); |
|||
b.getY().toString().should.equal('32670510020758816978083085130507043184471273380659243275938904335757337482424'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@fromX', function() { |
|||
|
|||
it('should return g', function() { |
|||
var g = point.getG(); |
|||
var p = point.fromX(false, g.getX()); |
|||
g.eq(p).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#validate', function() { |
|||
|
|||
it('should validate this valid point', function() { |
|||
var x = BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex')); |
|||
var y = BN().fromBuffer(new Buffer('4836ab292c105a711ed10fcfd30999c31ff7c02456147747e03e739ad527c380', 'hex')); |
|||
var p = point(x, y); |
|||
should.exist(p.validate()); |
|||
}); |
|||
|
|||
it('should invalidate this invalid point', function() { |
|||
var x = BN().fromBuffer(new Buffer('ac242d242d23be966085a2b2b893d989f824e06c9ad0395a8a52f055ba39abb2', 'hex')); |
|||
var y = BN().fromBuffer(new Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex')); |
|||
var p = point(x, y); |
|||
(function() { |
|||
p.validate(); |
|||
}).should.throw('Invalid y value of public key'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,120 @@ |
|||
var Privkey = require('../lib/privkey'); |
|||
var base58check = require('../lib/base58check'); |
|||
var BN = require('../lib/bn'); |
|||
var Point = require('../lib/point'); |
|||
var should = require('chai').should(); |
|||
|
|||
describe('Privkey', function() { |
|||
var hex = '96c132224121b509b7d0a16245e957d9192609c5637c6228311287b1be21627a'; |
|||
var buf = new Buffer(hex, 'hex'); |
|||
var enctestnet = 'cSdkPxkAjA4HDr5VHgsebAPDEh9Gyub4HK8UJr2DFGGqKKy4K5sG'; |
|||
var enctu = '92jJzK4tbURm1C7udQXxeCBvXHoHJstDXRxAMouPG1k1XUaXdsu'; |
|||
var encmainnet = 'L2Gkw3kKJ6N24QcDuH4XDqt9cTqsKTVNDGz1CRZhk9cq4auDUbJy'; |
|||
var encmu = '5JxgQaFM1FMd38cd14e3mbdxsdSa9iM2BV6DHBYsvGzxkTNQ7Un'; |
|||
|
|||
it('should create an empty private key', function() { |
|||
var privkey = new Privkey(); |
|||
should.exist(privkey); |
|||
}); |
|||
|
|||
it('should create a 0 private key with this convenience method', function() { |
|||
var bn = BN(0); |
|||
var privkey = new Privkey(bn); |
|||
privkey.bn.toString().should.equal(bn.toString()); |
|||
}); |
|||
|
|||
it('should create a mainnet private key', function() { |
|||
var privkey = new Privkey({bn: BN.fromBuffer(buf), networkstr: 'mainnet', compressed: true}); |
|||
privkey.toString().should.equal(encmainnet); |
|||
}); |
|||
|
|||
it('should create an uncompressed testnet private key', function() { |
|||
var privkey = new Privkey({bn: BN.fromBuffer(buf), networkstr: 'testnet', compressed: false}); |
|||
privkey.toString().should.equal(enctu); |
|||
}); |
|||
|
|||
it('should create an uncompressed mainnet private key', function() { |
|||
var privkey = new Privkey({bn: BN.fromBuffer(buf), networkstr: 'mainnet', compressed: false}); |
|||
privkey.toString().should.equal(encmu); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set bn', function() { |
|||
should.exist(Privkey().set({bn: BN.fromBuffer(buf)}).bn); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should input this address correctly', function() { |
|||
var privkey = new Privkey(); |
|||
privkey.fromJSON(encmu); |
|||
privkey.toWIF().should.equal(encmu); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should output this address correctly', function() { |
|||
var privkey = new Privkey(); |
|||
privkey.fromJSON(encmu); |
|||
privkey.toJSON().should.equal(encmu); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromRandom', function() { |
|||
|
|||
it('should set bn gt 0 and lt n, and should be compressed', function() { |
|||
var privkey = Privkey().fromRandom(); |
|||
privkey.bn.gt(BN(0)).should.equal(true); |
|||
privkey.bn.lt(Point.getN()).should.equal(true); |
|||
privkey.compressed.should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromWIF', function() { |
|||
|
|||
it('should parse this compressed testnet address correctly', function() { |
|||
var privkey = new Privkey(); |
|||
privkey.fromWIF(encmainnet); |
|||
privkey.toWIF().should.equal(encmainnet); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toWIF', function() { |
|||
|
|||
it('should parse this compressed testnet address correctly', function() { |
|||
var privkey = new Privkey(); |
|||
privkey.fromWIF(enctestnet); |
|||
privkey.toWIF().should.equal(enctestnet); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should parse this uncompressed testnet address correctly', function() { |
|||
var privkey = new Privkey(); |
|||
privkey.fromString(enctu); |
|||
privkey.toWIF().should.equal(enctu); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should parse this uncompressed mainnet address correctly', function() { |
|||
var privkey = new Privkey(); |
|||
privkey.fromString(encmu); |
|||
privkey.toString().should.equal(encmu); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,205 @@ |
|||
var should = require('chai').should(); |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var Point = require('../lib/point'); |
|||
var Bn = require('../lib/bn'); |
|||
var Privkey = require('../lib/privkey'); |
|||
|
|||
describe('Pubkey', function() { |
|||
|
|||
it('should create a blank public key', function() { |
|||
var pk = new Pubkey(); |
|||
should.exist(pk); |
|||
}); |
|||
|
|||
it('should create a public key with a point', function() { |
|||
var p = Point(); |
|||
var pk = new Pubkey({point: p}); |
|||
should.exist(pk.point); |
|||
}); |
|||
|
|||
it('should create a public key with a point with this convenient method', function() { |
|||
var p = Point(); |
|||
var pk = new Pubkey(p); |
|||
should.exist(pk.point); |
|||
pk.point.toString().should.equal(p.toString()); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should make a public key from a point', function() { |
|||
should.exist(Pubkey().set({point: Point.getG()}).point); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should input this public key', function() { |
|||
var pk = new Pubkey(); |
|||
pk.fromJSON('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should output this pubkey', function() { |
|||
var pk = new Pubkey(); |
|||
var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'; |
|||
pk.fromJSON(hex).toJSON().should.equal(hex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromPrivkey', function() { |
|||
|
|||
it('should make a public key from a privkey', function() { |
|||
should.exist(Pubkey().fromPrivkey(Privkey().fromRandom())); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should parse this uncompressed public key', function() { |
|||
var pk = new Pubkey(); |
|||
pk.fromBuffer(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex')); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
it('should parse this compressed public key', function() { |
|||
var pk = new Pubkey(); |
|||
pk.fromBuffer(new Buffer('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
it('should throw an error on this invalid public key', function() { |
|||
var pk = new Pubkey(); |
|||
(function() { |
|||
pk.fromBuffer(new Buffer('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
}).should.throw(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromDER', function() { |
|||
|
|||
it('should parse this uncompressed public key', function() { |
|||
var pk = new Pubkey(); |
|||
pk.fromDER(new Buffer('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341', 'hex')); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
it('should parse this compressed public key', function() { |
|||
var pk = new Pubkey(); |
|||
pk.fromDER(new Buffer('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
it('should throw an error on this invalid public key', function() { |
|||
var pk = new Pubkey(); |
|||
(function() { |
|||
pk.fromDER(new Buffer('091ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
}).should.throw(); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should parse this known valid public key', function() { |
|||
pk = new Pubkey(); |
|||
pk.fromString('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromX', function() { |
|||
|
|||
it('should create this known public key', function() { |
|||
var x = Bn.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
var pk = new Pubkey(); |
|||
pk.fromX(true, x); |
|||
pk.point.getX().toString(16).should.equal('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
pk.point.getY().toString(16).should.equal('7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should return this compressed DER format', function() { |
|||
var x = Bn.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
var pk = new Pubkey(); |
|||
pk.fromX(true, x); |
|||
pk.toBuffer().toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toDER', function() { |
|||
|
|||
it('should return this compressed DER format', function() { |
|||
var x = Bn.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
var pk = new Pubkey(); |
|||
pk.fromX(true, x); |
|||
pk.toDER(true).toString('hex').should.equal('031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'); |
|||
}); |
|||
|
|||
it('should return this uncompressed DER format', function() { |
|||
var x = Bn.fromBuffer(new Buffer('1ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a', 'hex')); |
|||
var pk = new Pubkey(); |
|||
pk.fromX(true, x); |
|||
pk.toDER(false).toString('hex').should.equal('041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a7baad41d04514751e6851f5304fd243751703bed21b914f6be218c0fa354a341'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should print this known public key', function() { |
|||
var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; |
|||
var pk = new Pubkey(); |
|||
pk.fromString(hex); |
|||
pk.toString().should.equal(hex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#validate', function() { |
|||
|
|||
it('should not throw an error if pubkey is valid', function() { |
|||
var hex = '031ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a'; |
|||
var pk = new Pubkey(); |
|||
pk.fromString(hex); |
|||
should.exist(pk.validate()); |
|||
}); |
|||
|
|||
it('should not throw an error if pubkey is invalid', function() { |
|||
var hex = '041ff0fe0f7b15ffaa85ff9f4744d539139c252a49710fb053bb9f2b933173ff9a0000000000000000000000000000000000000000000000000000000000000000'; |
|||
var pk = new Pubkey(); |
|||
pk.fromString(hex); |
|||
(function() { |
|||
pk.validate(); |
|||
}).should.throw('Invalid y value of public key'); |
|||
}); |
|||
|
|||
it('should not throw an error if pubkey is infinity', function() { |
|||
var pk = new Pubkey(); |
|||
pk.point = Point.getG().mul(Point.getN()); |
|||
(function() { |
|||
pk.validate(); |
|||
}).should.throw('Point cannot be equal to Infinity'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,61 @@ |
|||
var should = require('chai').should(); |
|||
var Random = require('../lib/random'); |
|||
|
|||
describe('Random', function() { |
|||
|
|||
describe('@getRandomBuffer', function() { |
|||
|
|||
it('should return a buffer', function() { |
|||
var bytes = Random.getRandomBuffer(8); |
|||
bytes.length.should.equal(8); |
|||
Buffer.isBuffer(bytes).should.equal(true); |
|||
}); |
|||
|
|||
it('should not equate two 256 bit random buffers', function() { |
|||
var bytes1 = Random.getRandomBuffer(32); |
|||
var bytes2 = Random.getRandomBuffer(32); |
|||
bytes1.toString('hex').should.not.equal(bytes2.toString('hex')); |
|||
}); |
|||
|
|||
it('should generate 100 8 byte buffers in a row that are not equal', function() { |
|||
var hexs = []; |
|||
for (var i = 0; i < 100; i++) |
|||
hexs[i] = Random.getRandomBuffer(8).toString('hex'); |
|||
for (var i = 0; i < 100; i++) |
|||
for (var j = i + 1; j < 100; j++) |
|||
hexs[i].should.not.equal(hexs[j]); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@getPseudoRandomBuffer', function() { |
|||
|
|||
it('should generate 7 random bytes', function() { |
|||
var buf = Random.getPseudoRandomBuffer(7); |
|||
buf.length.should.equal(7); |
|||
}); |
|||
|
|||
it('should generate 8 random bytes', function() { |
|||
var buf = Random.getPseudoRandomBuffer(8); |
|||
buf.length.should.equal(8); |
|||
}); |
|||
|
|||
it('should generate 9 random bytes', function() { |
|||
var buf = Random.getPseudoRandomBuffer(9); |
|||
buf.length.should.equal(9); |
|||
}); |
|||
|
|||
it('should generate 90 random bytes', function() { |
|||
var buf = Random.getPseudoRandomBuffer(90); |
|||
buf.length.should.equal(90); |
|||
}); |
|||
|
|||
it('should generate two 8 byte buffers that are not equal', function() { |
|||
var buf1 = Random.getPseudoRandomBuffer(8); |
|||
var buf2 = Random.getPseudoRandomBuffer(8); |
|||
buf1.toString('hex').should.not.equal(buf2.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,308 @@ |
|||
var Script = require('../lib/script'); |
|||
var should = require('chai').should(); |
|||
var Opcode = require('../lib/opcode'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
|
|||
describe('Script', function() { |
|||
|
|||
it('should make a new script', function() { |
|||
var script = new Script(); |
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should parse this buffer containing an OP code', function() { |
|||
var buf = new Buffer(1); |
|||
buf[0] = Opcode('OP_0').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
}); |
|||
|
|||
it('should parse this buffer containing another OP code', function() { |
|||
var buf = new Buffer(1); |
|||
buf[0] = Opcode('OP_CHECKMULTISIG').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
}); |
|||
|
|||
it('should parse this buffer containing three bytes of data', function() { |
|||
var buf = new Buffer([3, 1, 2, 3]); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
}); |
|||
|
|||
it('should parse this buffer containing OP_PUSHDATA1 and three bytes of data', function() { |
|||
var buf = new Buffer([0, 0, 1, 2, 3]); |
|||
buf[0] = Opcode('OP_PUSHDATA1').toNumber(); |
|||
buf.writeUInt8(3, 1); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
}); |
|||
|
|||
it('should parse this buffer containing OP_PUSHDATA2 and three bytes of data', function() { |
|||
var buf = new Buffer([0, 0, 0, 1, 2, 3]); |
|||
buf[0] = Opcode('OP_PUSHDATA2').toNumber(); |
|||
buf.writeUInt16LE(3, 1); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
}); |
|||
|
|||
it('should parse this buffer containing OP_PUSHDATA4 and three bytes of data', function() { |
|||
var buf = new Buffer([0, 0, 0, 0, 0, 1, 2, 3]); |
|||
buf[0] = Opcode('OP_PUSHDATA4').toNumber(); |
|||
buf.writeUInt16LE(3, 1); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
}); |
|||
|
|||
it('should parse this buffer an OP code, data, and another OP code', function() { |
|||
var buf = new Buffer([0, 0, 0, 0, 0, 0, 1, 2, 3, 0]); |
|||
buf[0] = Opcode('OP_0').toNumber(); |
|||
buf[1] = Opcode('OP_PUSHDATA4').toNumber(); |
|||
buf.writeUInt16LE(3, 2); |
|||
buf[buf.length - 1] = Opcode('OP_0').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(3); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
script.chunks[1].buf.toString('hex').should.equal('010203'); |
|||
script.chunks[2].should.equal(buf[buf.length - 1]); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should output this buffer containing an OP code', function() { |
|||
var buf = new Buffer(1); |
|||
buf[0] = Opcode('OP_0').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should output this buffer containing another OP code', function() { |
|||
var buf = new Buffer(1); |
|||
buf[0] = Opcode('OP_CHECKMULTISIG').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should output this buffer containing three bytes of data', function() { |
|||
var buf = new Buffer([3, 1, 2, 3]); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should output this buffer containing OP_PUSHDATA1 and three bytes of data', function() { |
|||
var buf = new Buffer([0, 0, 1, 2, 3]); |
|||
buf[0] = Opcode('OP_PUSHDATA1').toNumber(); |
|||
buf.writeUInt8(3, 1); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should output this buffer containing OP_PUSHDATA2 and three bytes of data', function() { |
|||
var buf = new Buffer([0, 0, 0, 1, 2, 3]); |
|||
buf[0] = Opcode('OP_PUSHDATA2').toNumber(); |
|||
buf.writeUInt16LE(3, 1); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should output this buffer containing OP_PUSHDATA4 and three bytes of data', function() { |
|||
var buf = new Buffer([0, 0, 0, 0, 0, 1, 2, 3]); |
|||
buf[0] = Opcode('OP_PUSHDATA4').toNumber(); |
|||
buf.writeUInt16LE(3, 1); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(1); |
|||
script.chunks[0].buf.toString('hex').should.equal('010203'); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
it('should output this buffer an OP code, data, and another OP code', function() { |
|||
var buf = new Buffer([0, 0, 0, 0, 0, 0, 1, 2, 3, 0]); |
|||
buf[0] = Opcode('OP_0').toNumber(); |
|||
buf[1] = Opcode('OP_PUSHDATA4').toNumber(); |
|||
buf.writeUInt16LE(3, 2); |
|||
buf[buf.length - 1] = Opcode('OP_0').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(3); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
script.chunks[1].buf.toString('hex').should.equal('010203'); |
|||
script.chunks[2].should.equal(buf[buf.length - 1]); |
|||
script.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should parse these known scripts', function() { |
|||
Script().fromString('OP_0 OP_PUSHDATA4 3 0x010203 OP_0').toString().should.equal('OP_0 OP_PUSHDATA4 3 0x010203 OP_0'); |
|||
Script().fromString('OP_0 OP_PUSHDATA2 3 0x010203 OP_0').toString().should.equal('OP_0 OP_PUSHDATA2 3 0x010203 OP_0'); |
|||
Script().fromString('OP_0 OP_PUSHDATA1 3 0x010203 OP_0').toString().should.equal('OP_0 OP_PUSHDATA1 3 0x010203 OP_0'); |
|||
Script().fromString('OP_0 3 0x010203 OP_0').toString().should.equal('OP_0 3 0x010203 OP_0'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should output this buffer an OP code, data, and another OP code', function() { |
|||
var buf = new Buffer([0, 0, 0, 0, 0, 0, 1, 2, 3, 0]); |
|||
buf[0] = Opcode('OP_0').toNumber(); |
|||
buf[1] = Opcode('OP_PUSHDATA4').toNumber(); |
|||
buf.writeUInt16LE(3, 2); |
|||
buf[buf.length - 1] = Opcode('OP_0').toNumber(); |
|||
var script = Script().fromBuffer(buf); |
|||
script.chunks.length.should.equal(3); |
|||
script.chunks[0].should.equal(buf[0]); |
|||
script.chunks[1].buf.toString('hex').should.equal('010203'); |
|||
script.chunks[2].should.equal(buf[buf.length - 1]); |
|||
script.toString().toString('hex').should.equal('OP_0 OP_PUSHDATA4 3 0x010203 OP_0'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should parse this known script', function() { |
|||
Script().fromJSON('OP_0 OP_PUSHDATA4 3 0x010203 OP_0').toString().should.equal('OP_0 OP_PUSHDATA4 3 0x010203 OP_0'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should output this known script', function() { |
|||
Script().fromString('OP_0 OP_PUSHDATA4 3 0x010203 OP_0').toJSON().should.equal('OP_0 OP_PUSHDATA4 3 0x010203 OP_0'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isOpReturn', function() { |
|||
|
|||
it('should know this is a (blank) OP_RETURN script', function() { |
|||
Script('OP_RETURN').isOpReturn().should.equal(true); |
|||
}); |
|||
|
|||
it('should know this is an OP_RETURN script', function() { |
|||
var buf = new Buffer(40); |
|||
buf.fill(0); |
|||
Script('OP_RETURN 40 0x' + buf.toString('hex')).isOpReturn().should.equal(true); |
|||
}); |
|||
|
|||
it('should know this is not an OP_RETURN script', function() { |
|||
var buf = new Buffer(40); |
|||
buf.fill(0); |
|||
Script('OP_CHECKMULTISIG 40 0x' + buf.toString('hex')).isOpReturn().should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isPubkeyhashIn', function() { |
|||
|
|||
it('should classify this known pubkeyhashin', function() { |
|||
Script('73 0x3046022100bb3c194a30e460d81d34be0a230179c043a656f67e3c5c8bf47eceae7c4042ee0221008bf54ca11b2985285be0fd7a212873d243e6e73f5fad57e8eb14c4f39728b8c601 65 0x04e365859b3c78a8b7c202412b949ebca58e147dba297be29eee53cd3e1d300a6419bc780cc9aec0dc94ed194e91c8f6433f1b781ee00eac0ead2aae1e8e0712c6').isPubkeyhashIn().should.equal(true); |
|||
}); |
|||
|
|||
it('should classify this known non-pubkeyhashin', function() { |
|||
Script('73 0x3046022100bb3c194a30e460d81d34be0a230179c043a656f67e3c5c8bf47eceae7c4042ee0221008bf54ca11b2985285be0fd7a212873d243e6e73f5fad57e8eb14c4f39728b8c601 65 0x04e365859b3c78a8b7c202412b949ebca58e147dba297be29eee53cd3e1d300a6419bc780cc9aec0dc94ed194e91c8f6433f1b781ee00eac0ead2aae1e8e0712c6 OP_CHECKSIG').isPubkeyhashIn().should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isPubkeyhashOut', function() { |
|||
|
|||
it('should classify this known pubkeyhashout as pubkeyhashout', function() { |
|||
Script('OP_DUP OP_HASH160 20 0000000000000000000000000000000000000000 OP_EQUALVERIFY OP_CHECKSIG').isPubkeyhashOut().should.equal(true); |
|||
}); |
|||
|
|||
it('should classify this known non-pubkeyhashout as not pubkeyhashout', function() { |
|||
Script('OP_DUP OP_HASH160 20 0000000000000000000000000000000000000000').isPubkeyhashOut().should.equal(false) |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isScripthashIn', function() { |
|||
|
|||
it('should classify this known scripthashin', function() { |
|||
Script('20 0000000000000000000000000000000000000000').isScripthashIn().should.equal(true); |
|||
}); |
|||
|
|||
it('should classify this known non-scripthashin', function() { |
|||
Script('20 0000000000000000000000000000000000000000 OP_CHECKSIG').isScripthashIn().should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isScripthashOut', function() { |
|||
|
|||
it('should classify this known pubkeyhashout as pubkeyhashout', function() { |
|||
Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL').isScripthashOut().should.equal(true); |
|||
}); |
|||
|
|||
it('should classify these known non-pubkeyhashout as not pubkeyhashout', function() { |
|||
Script('OP_HASH160 20 0x0000000000000000000000000000000000000000 OP_EQUAL OP_EQUAL').isScripthashOut().should.equal(false); |
|||
Script('OP_HASH160 21 0x000000000000000000000000000000000000000000 OP_EQUAL').isScripthashOut().should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeOp', function() { |
|||
|
|||
it('should write these ops', function() { |
|||
Script().writeOp('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); |
|||
Script().writeOp(Opcode.map.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#writeBuffer', function() { |
|||
|
|||
it('should write these push data', function() { |
|||
var buf = new Buffer(1); |
|||
buf.fill(0); |
|||
Script().writeBuffer(buf).toString().should.equal('1 0x00'); |
|||
buf = new Buffer(255); |
|||
buf.fill(0); |
|||
Script().writeBuffer(buf).toString().should.equal('OP_PUSHDATA1 255 0x' + buf.toString('hex')); |
|||
buf = new Buffer(256); |
|||
buf.fill(0); |
|||
Script().writeBuffer(buf).toString().should.equal('OP_PUSHDATA2 256 0x' + buf.toString('hex')); |
|||
buf = new Buffer(Math.pow(2, 16)); |
|||
buf.fill(0); |
|||
Script().writeBuffer(buf).toString().should.equal('OP_PUSHDATA4 ' + Math.pow(2, 16) + ' 0x' + buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#write', function() { |
|||
|
|||
it('should write both pushdata and non-pushdata chunks', function() { |
|||
Script().write('OP_CHECKMULTISIG').toString().should.equal('OP_CHECKMULTISIG'); |
|||
Script().write(Opcode.map.OP_CHECKMULTISIG).toString().should.equal('OP_CHECKMULTISIG'); |
|||
var buf = new Buffer(1); |
|||
buf.fill(0); |
|||
Script().write(buf).toString().should.equal('1 0x00'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,149 @@ |
|||
var BN = require('../lib/bn'); |
|||
var should = require('chai').should(); |
|||
var Signature = require('../lib/signature'); |
|||
|
|||
describe('Signature', function() { |
|||
|
|||
it('should make a blank signature', function() { |
|||
var sig = new Signature(); |
|||
should.exist(sig); |
|||
}); |
|||
|
|||
it('should work with conveniently setting r, s', function() { |
|||
var r = BN(); |
|||
var s = BN(); |
|||
var sig = new Signature(r, s); |
|||
should.exist(sig); |
|||
sig.r.toString().should.equal(r.toString()); |
|||
sig.s.toString().should.equal(s.toString()); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set compressed', function() { |
|||
should.exist(Signature().set({compressed: true})); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromCompact', function() { |
|||
|
|||
it('should create a signature from a compressed signature', function() { |
|||
var blank = new Buffer(32); |
|||
blank.fill(0); |
|||
var compressed = Buffer.concat([ |
|||
new Buffer([0 + 27 + 4]), |
|||
blank, |
|||
blank |
|||
]); |
|||
var sig = new Signature(); |
|||
sig.fromCompact(compressed); |
|||
sig.r.cmp(0).should.equal(0); |
|||
sig.s.cmp(0).should.equal(0); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromDER', function() { |
|||
|
|||
var buf = new Buffer('3044022075fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e62770220729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2', 'hex'); |
|||
|
|||
it('should parse this DER format signature', function() { |
|||
var sig = new Signature(); |
|||
sig.fromDER(buf); |
|||
sig.r.toBuffer({size: 32}).toString('hex').should.equal('75fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e6277'); |
|||
sig.s.toBuffer({size: 32}).toString('hex').should.equal('729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
var buf = new Buffer('3044022075fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e62770220729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2', 'hex'); |
|||
|
|||
it('should parse this DER format signature in hex', function() { |
|||
var sig = new Signature(); |
|||
sig.fromString(buf.toString('hex')); |
|||
sig.r.toBuffer({size: 32}).toString('hex').should.equal('75fc517e541bd54769c080b64397e32161c850f6c1b2b67a5c433affbb3e6277'); |
|||
sig.s.toBuffer({size: 32}).toString('hex').should.equal('729e85cc46ffab881065ec07694220e71d4df9b2b8c8fd12c3122cf3a5efbcf2'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#parseDER', function() { |
|||
|
|||
it('should parse this signature generated in node', function() { |
|||
var sighex = '30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72'; |
|||
var sig = new Buffer(sighex, 'hex'); |
|||
var parsed = Signature.parseDER(sig); |
|||
parsed.header.should.equal(0x30) |
|||
parsed.length.should.equal(69) |
|||
parsed.rlength.should.equal(33); |
|||
parsed.rneg.should.equal(true); |
|||
parsed.rbuf.toString('hex').should.equal('008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa'); |
|||
parsed.r.toString().should.equal('63173831029936981022572627018246571655303050627048489594159321588908385378810'); |
|||
parsed.slength.should.equal(32); |
|||
parsed.sneg.should.equal(false); |
|||
parsed.sbuf.toString('hex').should.equal('0993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72'); |
|||
parsed.s.toString().should.equal('4331694221846364448463828256391194279133231453999942381442030409253074198130'); |
|||
}); |
|||
|
|||
it('should parse this 69 byte signature', function() { |
|||
var sighex = '3043021f59e4705959cc78acbfcf8bd0114e9cc1b389a4287fb33152b73a38c319b50302202f7428a27284c757e409bf41506183e9e49dfb54d5063796dfa0d403a4deccfa'; |
|||
var sig = new Buffer(sighex, 'hex'); |
|||
var parsed = Signature.parseDER(sig); |
|||
parsed.header.should.equal(0x30) |
|||
parsed.length.should.equal(67) |
|||
parsed.rlength.should.equal(31); |
|||
parsed.rneg.should.equal(false); |
|||
parsed.rbuf.toString('hex').should.equal('59e4705959cc78acbfcf8bd0114e9cc1b389a4287fb33152b73a38c319b503'); |
|||
parsed.r.toString().should.equal('158826015856106182499128681792325160381907915189052224498209222621383996675'); |
|||
parsed.slength.should.equal(32); |
|||
parsed.sneg.should.equal(false); |
|||
parsed.sbuf.toString('hex').should.equal('2f7428a27284c757e409bf41506183e9e49dfb54d5063796dfa0d403a4deccfa'); |
|||
parsed.s.toString().should.equal('21463938592353267769710297084836796652964571266930856168996063301532842380538'); |
|||
}); |
|||
|
|||
it('should parse this 68 byte signature', function() { |
|||
var sighex = '3042021e17cfe77536c3fb0526bd1a72d7a8e0973f463add210be14063c8a9c37632022061bfa677f825ded82ba0863fb0c46ca1388dd3e647f6a93c038168b59d131a51'; |
|||
var sig = new Buffer(sighex, 'hex'); |
|||
var parsed = Signature.parseDER(sig); |
|||
parsed.header.should.equal(0x30) |
|||
parsed.length.should.equal(66) |
|||
parsed.rlength.should.equal(30); |
|||
parsed.rneg.should.equal(false); |
|||
parsed.rbuf.toString('hex').should.equal('17cfe77536c3fb0526bd1a72d7a8e0973f463add210be14063c8a9c37632'); |
|||
parsed.r.toString().should.equal('164345250294671732127776123343329699648286106708464198588053542748255794'); |
|||
parsed.slength.should.equal(32); |
|||
parsed.sneg.should.equal(false); |
|||
parsed.sbuf.toString('hex').should.equal('61bfa677f825ded82ba0863fb0c46ca1388dd3e647f6a93c038168b59d131a51'); |
|||
parsed.s.toString().should.equal('44212963026209759051804639008236126356702363229859210154760104982946304432721'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toDER', function() { |
|||
|
|||
it('should convert these known r and s values into a known signature', function() { |
|||
var r = BN('63173831029936981022572627018246571655303050627048489594159321588908385378810'); |
|||
var s = BN('4331694221846364448463828256391194279133231453999942381442030409253074198130'); |
|||
var sig = new Signature({r: r, s: s}); |
|||
var der = sig.toDER(r, s); |
|||
der.toString('hex').should.equal('30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should convert this signature in to hex DER', function() { |
|||
var r = BN('63173831029936981022572627018246571655303050627048489594159321588908385378810'); |
|||
var s = BN('4331694221846364448463828256391194279133231453999942381442030409253074198130'); |
|||
var sig = new Signature({r: r, s: s}); |
|||
var hex = sig.toString(); |
|||
hex.should.equal('30450221008bab1f0a2ff2f9cb8992173d8ad73c229d31ea8e10b0f4d4ae1a0d8ed76021fa02200993a6ec81755b9111762fc2cf8e3ede73047515622792110867d12654275e72'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,149 @@ |
|||
var StealthAddress = require('../lib/expmt/stealthaddress'); |
|||
var should = require('chai').should(); |
|||
var Stealthkey = require('../lib/expmt/stealthkey'); |
|||
var Keypair = require('../lib/keypair'); |
|||
var Privkey = require('../lib/privkey'); |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var BN = require('../lib/bn'); |
|||
var Hash = require('../lib/hash'); |
|||
var Base58check = require('../lib/base58check'); |
|||
|
|||
describe('StealthAddress', function() { |
|||
|
|||
var stealthkey = Stealthkey(); |
|||
stealthkey.payloadKeypair = Keypair(); |
|||
stealthkey.payloadKeypair.privkey = Privkey(); |
|||
stealthkey.payloadKeypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test 1'))); |
|||
stealthkey.payloadKeypair.privkey2pubkey(); |
|||
stealthkey.scanKeypair = Keypair(); |
|||
stealthkey.scanKeypair.privkey = Privkey(); |
|||
stealthkey.scanKeypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test 2'))); |
|||
stealthkey.scanKeypair.privkey2pubkey(); |
|||
|
|||
var senderKeypair = Keypair(); |
|||
senderKeypair.privkey = Privkey(); |
|||
senderKeypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test 3'))); |
|||
senderKeypair.privkey2pubkey(); |
|||
|
|||
var addressString = 'vJmtuUb8ysKiM1HtHQF23FGfjGAKu5sM94UyyjknqhJHNdj5CZzwtpGzeyaATQ2HvuzomNVtiwsTJSWzzCBgCTtUZbRFpzKVq9MAUr'; |
|||
var dwhex = '2a0002697763d7e9becb0c180083738c32c05b0e2fee26d6278020c06bbb04d5f66b32010362408459041e0473298af3824dbabe4d2b7f846825ed4d1c2e2c670c07cb275d0100'; |
|||
var dwbuf = new Buffer(dwhex, 'hex'); |
|||
|
|||
it('should make a new stealth address', function() { |
|||
var sa = new StealthAddress(); |
|||
should.exist(sa); |
|||
sa = StealthAddress(); |
|||
should.exist(sa); |
|||
sa = StealthAddress(addressString); |
|||
should.exist(sa); |
|||
sa = StealthAddress(Base58check.decode(addressString)); |
|||
should.exist(sa); |
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should give a stealthkey address with the right pubkeys', function() { |
|||
var sa = new StealthAddress(); |
|||
sa.fromJSON(addressString); |
|||
sa.payloadPubkey.toString().should.equal(stealthkey.payloadKeypair.pubkey.toString()); |
|||
sa.scanPubkey.toString().should.equal(stealthkey.scanKeypair.pubkey.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should return this known address string', function() { |
|||
StealthAddress().fromJSON(addressString).toJSON().should.equal(addressString); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should parse this DW buffer', function() { |
|||
StealthAddress().fromBuffer(new Buffer(dwhex, 'hex')).toBuffer().toString('hex').should.equal(dwhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromString', function() { |
|||
|
|||
it('should parse this DW buffer', function() { |
|||
StealthAddress().fromString(Base58check(new Buffer(dwhex, 'hex')).toString()).toBuffer().toString('hex').should.equal(dwhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#getSharedKeypair', function() { |
|||
|
|||
it('should return a key', function() { |
|||
var sa = new StealthAddress(); |
|||
sa.payloadPubkey = stealthkey.payloadKeypair.pubkey; |
|||
sa.scanPubkey = stealthkey.scanKeypair.pubkey; |
|||
var key = sa.getSharedKeypair(senderKeypair); |
|||
(key instanceof Keypair).should.equal(true); |
|||
}); |
|||
|
|||
it('should return the same key as Stealthkey.prototype.getSharedKeypair', function() { |
|||
var sa = new StealthAddress(); |
|||
sa.payloadPubkey = stealthkey.payloadKeypair.pubkey; |
|||
sa.scanPubkey = stealthkey.scanKeypair.pubkey; |
|||
var key = sa.getSharedKeypair(senderKeypair); |
|||
|
|||
var key2 = stealthkey.getSharedKeypair(senderKeypair.pubkey); |
|||
key.toString().should.equal(key2.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#getReceivePubkey', function() { |
|||
|
|||
it('should return a pubkey', function() { |
|||
var pubkey = StealthAddress().fromStealthkey(stealthkey).getReceivePubkey(senderKeypair); |
|||
(pubkey instanceof Pubkey).should.equal(true); |
|||
}); |
|||
|
|||
it('should return the same pubkey as getReceivePubkey', function() { |
|||
var pubkey = StealthAddress().fromStealthkey(stealthkey).getReceivePubkey(senderKeypair); |
|||
var pubkey2 = stealthkey.getReceivePubkey(senderKeypair.pubkey); |
|||
pubkey2.toString().should.equal(pubkey.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should return this known address buffer', function() { |
|||
var buf = Base58check.decode(addressString); |
|||
StealthAddress().fromBuffer(dwbuf).toBuffer().toString('hex').should.equal(dwhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toString', function() { |
|||
|
|||
it('should return this known address buffer', function() { |
|||
var buf = Base58check.decode(addressString); |
|||
StealthAddress().fromBuffer(buf).toString().should.equal(Base58check(new Buffer(dwhex, 'hex')).toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@parseDWBuffer', function() { |
|||
|
|||
it('should parse this known DW buffer', function() { |
|||
var buf = new Buffer(dwhex, 'hex'); |
|||
var parsed = StealthAddress.parseDWBuffer(buf); |
|||
parsed.version.should.equal(42); |
|||
parsed.options.should.equal(0); |
|||
parsed.scanPubkey.toString().should.equal('02697763d7e9becb0c180083738c32c05b0e2fee26d6278020c06bbb04d5f66b32'); |
|||
parsed.nPayloadPubkeys.should.equal(1); |
|||
parsed.payloadPubkeys[0].toString().should.equal('0362408459041e0473298af3824dbabe4d2b7f846825ed4d1c2e2c670c07cb275d'); |
|||
parsed.nSigs.should.equal(1); |
|||
parsed.prefix.toString().should.equal(''); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,138 @@ |
|||
var should = require('chai').should(); |
|||
var Stealthkey = require('../lib/expmt/stealthkey'); |
|||
var Keypair = require('../lib/keypair'); |
|||
var Privkey = require('../lib/privkey'); |
|||
var Pubkey = require('../lib/pubkey'); |
|||
var BN = require('../lib/bn'); |
|||
var Hash = require('../lib/hash'); |
|||
|
|||
describe('Stealthkey', function() { |
|||
|
|||
var stealthkey = Stealthkey(); |
|||
stealthkey.payloadKeypair = Keypair(); |
|||
stealthkey.payloadKeypair.privkey = Privkey(); |
|||
stealthkey.payloadKeypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test 1'))); |
|||
stealthkey.payloadKeypair.privkey2pubkey(); |
|||
stealthkey.scanKeypair = Keypair(); |
|||
stealthkey.scanKeypair.privkey = Privkey(); |
|||
stealthkey.scanKeypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test 2'))); |
|||
stealthkey.scanKeypair.privkey2pubkey(); |
|||
|
|||
var senderKeypair = Keypair(); |
|||
senderKeypair.privkey = Privkey(); |
|||
senderKeypair.privkey.bn = BN().fromBuffer(Hash.sha256(new Buffer('test 3'))); |
|||
senderKeypair.privkey2pubkey(); |
|||
|
|||
it('should create a new stealthkey', function() { |
|||
var stealthkey = new Stealthkey(); |
|||
should.exist(stealthkey); |
|||
}); |
|||
|
|||
it('should create a new stealthkey without using "new"', function() { |
|||
var stealthkey = Stealthkey(); |
|||
should.exist(stealthkey); |
|||
}); |
|||
|
|||
it('should create a new stealthkey with both keypairs in the constructor', function() { |
|||
var keypair1 = Keypair(); |
|||
var keypair2 = Keypair(); |
|||
var stealthkey = Stealthkey(keypair1, keypair2); |
|||
should.exist(stealthkey.payloadKeypair); |
|||
should.exist(stealthkey.scanKeypair); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set payload key', function() { |
|||
should.exist(Stealthkey().set({payloadKeypair: stealthkey.payloadKeypair}).payloadKeypair); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should make a stealthkey from this JSON', function() { |
|||
var sk = Stealthkey().fromJSON({ |
|||
payloadKeypair: stealthkey.payloadKeypair.toJSON(), |
|||
scanKeypair: stealthkey.scanKeypair.toJSON() |
|||
}); |
|||
sk.payloadKeypair.toString().should.equal(stealthkey.payloadKeypair.toString()); |
|||
sk.scanKeypair.toString().should.equal(stealthkey.scanKeypair.toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should convert this stealthkey to json', function() { |
|||
var json = stealthkey.toJSON() |
|||
var json2 = Stealthkey().fromJSON(json).toJSON(); |
|||
json.payloadKeypair.privkey.should.equal(json2.payloadKeypair.privkey); |
|||
json.scanKeypair.privkey.should.equal(json2.scanKeypair.privkey); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromRandom', function() { |
|||
|
|||
it('should create a new stealthkey from random', function() { |
|||
var stealthkey = Stealthkey().fromRandom(); |
|||
should.exist(stealthkey.payloadKeypair.privkey.bn.gt(0)); |
|||
should.exist(stealthkey.scanKeypair.privkey.bn.gt(0)); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#getSharedKeypair', function() { |
|||
|
|||
it('should return a key', function() { |
|||
var key = stealthkey.getSharedKeypair(senderKeypair.pubkey); |
|||
(key instanceof Keypair).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#getReceivePubkey', function() { |
|||
|
|||
it('should return a pubkey', function() { |
|||
var pubkey = stealthkey.getReceivePubkey(senderKeypair.pubkey); |
|||
(pubkey instanceof Pubkey).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#getReceiveKeypair', function() { |
|||
|
|||
it('should return a key', function() { |
|||
var key = stealthkey.getReceiveKeypair(senderKeypair.pubkey); |
|||
(key instanceof Keypair).should.equal(true); |
|||
}); |
|||
|
|||
it('should return a key with the same pubkey as getReceivePubkey', function() { |
|||
var key = stealthkey.getReceiveKeypair(senderKeypair.pubkey); |
|||
var pubkey = stealthkey.getReceivePubkey(senderKeypair.pubkey); |
|||
key.pubkey.toString().should.equal(pubkey.toString()); |
|||
}); |
|||
|
|||
it('should return private key with length 32 or less', function() { |
|||
var key = stealthkey.getReceiveKeypair(senderKeypair.pubkey); |
|||
key.privkey.bn.toBuffer().length.should.be.below(33); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isForMe', function() { |
|||
|
|||
it('should return true if it (the transaction or message) is for me', function() { |
|||
var pubkeyhash = new Buffer('3cb64fa6ee9b3e8754e3e2bd033bf61048604a99', 'hex'); |
|||
stealthkey.isForMe(senderKeypair.pubkey, pubkeyhash).should.equal(true); |
|||
}); |
|||
|
|||
it('should return false if it (the transaction or message) is not for me', function() { |
|||
var pubkeyhash = new Buffer('00b64fa6ee9b3e8754e3e2bd033bf61048604a99', 'hex'); |
|||
stealthkey.isForMe(senderKeypair.pubkey, pubkeyhash).should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,139 @@ |
|||
var Keypair = require('../lib/keypair'); |
|||
var StealthMessage = require('../lib/expmt/stealthmessage'); |
|||
var Stealthkey = require('../lib/expmt/stealthkey'); |
|||
var StealthAddress = require('../lib/expmt/stealthaddress'); |
|||
var KDF = require('../lib/kdf'); |
|||
var Hash = require('../lib/hash'); |
|||
var should = require('chai').should(); |
|||
var Address = require('../lib/address'); |
|||
|
|||
describe('StealthMessage', function() { |
|||
|
|||
var payloadKeypair = KDF.buf2keypair(new Buffer('key1')); |
|||
var scanKeypair = KDF.buf2keypair(new Buffer('key2')); |
|||
var fromKeypair = KDF.buf2keypair(new Buffer('key3')); |
|||
var enchex = 'f557994f16d0d628fa4fdb4ab3d7e0bc5f2754f20381c7831a20c7c9ec88dcf092ea3683261798ccda991ed65a3a54a036d8125dec0381c7831a20c7c9ec88dcf092ea3683261798ccda991ed65a3a54a036d8125dec9f86d081884c7d659a2feaa0c55ad01560ba2904d3bc8395b6c4a6f87648edb33db6a22170e5e26f340c7ba943169210234cd6a753ad13919b0ab7d678b47b5e7d63e452382de2c2590fb57ef048f7b3'; |
|||
var encbuf = new Buffer(enchex, 'hex'); |
|||
var ivbuf = Hash.sha256(new Buffer('test')).slice(0, 128 / 8); |
|||
var sk = Stealthkey().set({payloadKeypair: payloadKeypair, scanKeypair: scanKeypair}); |
|||
var sa = StealthAddress().fromStealthkey(sk); |
|||
var messagebuf = new Buffer('this is my message'); |
|||
|
|||
it('should make a new stealthmessage', function() { |
|||
var sm = new StealthMessage(); |
|||
should.exist(sm); |
|||
sm = StealthMessage() |
|||
should.exist(sm); |
|||
}); |
|||
|
|||
it('should allow "set" style syntax', function() { |
|||
var encbuf = StealthMessage().set({ |
|||
messagebuf: messagebuf, |
|||
toStealthAddress: sa |
|||
}).encrypt().encbuf; |
|||
should.exist(encbuf); |
|||
encbuf.length.should.equal(113); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set the messagebuf', function() { |
|||
var sm = StealthMessage().set({messagebuf: messagebuf}); |
|||
should.exist(sm.messagebuf); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@encrypt', function() { |
|||
|
|||
it('should encrypt a message', function() { |
|||
var encbuf = StealthMessage.encrypt(messagebuf, sa); |
|||
encbuf.length.should.equal(166); |
|||
}); |
|||
|
|||
it('should encrypt a message with this fromKeypair and ivbuf the same each time', function() { |
|||
var encbuf = StealthMessage.encrypt(messagebuf, sa, fromKeypair, ivbuf); |
|||
encbuf.length.should.equal(166); |
|||
encbuf.toString('hex').should.equal(enchex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@decrypt', function() { |
|||
|
|||
it('should decrypt this known message correctly', function() { |
|||
var messagebuf2 = StealthMessage.decrypt(encbuf, sk); |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@isForMe', function() { |
|||
|
|||
it('should know that this message is for me', function() { |
|||
StealthMessage.isForMe(encbuf, sk).should.equal(true); |
|||
}); |
|||
|
|||
it('should know that this message is for me even if my payloadPrivkey is not present', function() { |
|||
var sk2 = new Stealthkey(); |
|||
sk2.scanKeypair = sk.scanKeypair; |
|||
sk2.payloadKeypair = Keypair().set({pubkey: sk.payloadKeypair.pubkey}); |
|||
should.not.exist(sk2.payloadKeypair.privkey); |
|||
StealthMessage.isForMe(encbuf, sk2).should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#encrypt', function() { |
|||
|
|||
it('should encrypt this message', function() { |
|||
var sm = StealthMessage().set({ |
|||
messagebuf: messagebuf, |
|||
toStealthAddress: sa, |
|||
fromKeypair: fromKeypair |
|||
}); |
|||
sm.encrypt().encbuf.length.should.equal(113); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#decrypt', function() { |
|||
|
|||
it('should decrypt that which was encrypted', function() { |
|||
var sm = StealthMessage().set({ |
|||
messagebuf: messagebuf, |
|||
toStealthAddress: sa |
|||
}).encrypt(); |
|||
var messagebuf2 = StealthMessage().set({ |
|||
encbuf: sm.encbuf, |
|||
fromKeypair: sm.fromKeypair, |
|||
toStealthkey: sk |
|||
}).decrypt().messagebuf; |
|||
messagebuf2.toString('hex').should.equal(messagebuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#isForMe', function() { |
|||
|
|||
it('should know that this message is for me', function() { |
|||
StealthMessage().set({ |
|||
encbuf: encbuf, |
|||
toStealthkey: sk, |
|||
fromKeypair: fromKeypair, |
|||
receiveAddress: Address().set({hashbuf: encbuf.slice(0, 20)}) |
|||
}).isForMe().should.equal(true); |
|||
}); |
|||
|
|||
it('should know that this message is not for me', function() { |
|||
StealthMessage().set({ |
|||
encbuf: encbuf, |
|||
toStealthkey: sk, |
|||
fromKeypair: fromKeypair, |
|||
receiveAddress: Address().set({hashbuf: encbuf.slice(0, 20)}) |
|||
}).isForMe().should.equal(true); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,68 @@ |
|||
var should = require('chai').should(); |
|||
var Txout = require('../lib/txout'); |
|||
var Stealthkey = require('../lib/expmt/stealthkey'); |
|||
var StealthTx = require('../lib/expmt/stealthtx'); |
|||
var Transaction = require('../lib/transaction'); |
|||
var Varint = require('../lib/varint'); |
|||
|
|||
describe('StealthTx', function() { |
|||
|
|||
var txhex = '0100000001c828ccce36eca04f96321ad488528af86c7598e67157c4f8e2f462a9e0e3af5f010000006a47304402204525eef6a56cc57fb184e53efdfdc1086d5265da21480d55c2184536440a64f70220349cdc6c66a8507dde0d172fe64aeb57ae56e014b50315f615086a6b85c5424e012102c0633ddb6bf2a8686e2ba4ce8026c94e1e27ef12e73f8fed6d6d2b97199f9b74ffffffff020000000000000000286a2606deadbeef0365b5a5b0ba059666e907b0b5e07b37fdb162d1399ed829315491fe1f30c87b3f905f0100000000001976a9142042d5e7ef9e82346419fbfe7df5ae52fe4bea3c88ac00000000'; |
|||
var txbuf = new Buffer(txhex, 'hex'); |
|||
var txidhex = '66da969fff214c329e27062beaf3baf20ed035801559b31f3e868c2de4cdfc5b'; |
|||
var tx = Transaction(txbuf); |
|||
|
|||
it('should make a new StealthTx', function() { |
|||
var stx = new StealthTx(); |
|||
should.exist(stx); |
|||
stx = StealthTx(); |
|||
should.exist(stx); |
|||
}); |
|||
|
|||
describe('#isForMe', function() { |
|||
|
|||
it('should return false for this known tx and random stealthkey', function() { |
|||
var sk = Stealthkey().fromRandom(); |
|||
var stx = StealthTx().set({sk: sk, tx: tx}); |
|||
stx.isForMe().should.equal(false); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#notMine', function() { |
|||
|
|||
it('should return true for this known tx and random stealthkey', function() { |
|||
var sk = Stealthkey().fromRandom(); |
|||
var stx = StealthTx().set({sk: sk, tx: tx}); |
|||
stx.notMine().should.equal("StealthTx not mine"); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#notStealth', function() { |
|||
|
|||
it('should know this is a stealth tx', function() { |
|||
var stx = StealthTx().set({tx: tx}); |
|||
stx.notStealth().should.equal(false); |
|||
}); |
|||
|
|||
it('should know this is not a stealth tx', function() { |
|||
var tx2 = Transaction(tx); |
|||
tx2.txouts.pop(); |
|||
tx2.txoutsvi = Varint(1); |
|||
var stx = StealthTx().set({tx: tx2}); |
|||
stx.notStealth().should.equal("Not enough txouts"); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('@parseOpReturnData', function() { |
|||
var txout = tx.txouts[0]; |
|||
var buf = txout.script.chunks[1].buf; |
|||
var parsed = StealthTx.parseOpReturnData(buf); |
|||
(typeof parsed.version).should.equal('number'); |
|||
parsed.noncebuf.length.should.be.above(0); |
|||
parsed.pubkey.toBuffer().length.should.equal(33); |
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,195 @@ |
|||
var Varint = require('../lib/varint'); |
|||
var Transaction = require('../lib/transaction'); |
|||
var Txin = require('../lib/txin'); |
|||
var Txout = require('../lib/txout'); |
|||
var should = require('chai').should(); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
|
|||
describe('Transaction', function() { |
|||
|
|||
var txin = Txin().fromBuffer(new Buffer('00000000000000000000000000000000000000000000000000000000000000000000000001ae00000000', 'hex')); |
|||
var txout = Txout().fromBuffer(new Buffer('050000000000000001ae', 'hex')); |
|||
var tx = Transaction().set({ |
|||
version: 0, |
|||
txinsvi: Varint(1), |
|||
txins: [txin], |
|||
txoutsvi: Varint(1), |
|||
txouts: [txout], |
|||
nlocktime: 0 |
|||
}); |
|||
var txhex = '000000000100000000000000000000000000000000000000000000000000000000000000000000000001ae0000000001050000000000000001ae00000000'; |
|||
var txbuf = new Buffer(txhex, 'hex'); |
|||
|
|||
var tx2idhex = '8c9aa966d35bfeaf031409e0001b90ccdafd8d859799eb945a3c515b8260bcf2'; |
|||
var tx2hex = '01000000029e8d016a7b0dc49a325922d05da1f916d1e4d4f0cb840c9727f3d22ce8d1363f000000008c493046022100e9318720bee5425378b4763b0427158b1051eec8b08442ce3fbfbf7b30202a44022100d4172239ebd701dae2fbaaccd9f038e7ca166707333427e3fb2a2865b19a7f27014104510c67f46d2cbb29476d1f0b794be4cb549ea59ab9cc1e731969a7bf5be95f7ad5e7f904e5ccf50a9dc1714df00fbeb794aa27aaff33260c1032d931a75c56f2ffffffffa3195e7a1ab665473ff717814f6881485dc8759bebe97e31c301ffe7933a656f020000008b48304502201c282f35f3e02a1f32d2089265ad4b561f07ea3c288169dedcf2f785e6065efa022100e8db18aadacb382eed13ee04708f00ba0a9c40e3b21cf91da8859d0f7d99e0c50141042b409e1ebbb43875be5edde9c452c82c01e3903d38fa4fd89f3887a52cb8aea9dc8aec7e2c9d5b3609c03eb16259a2537135a1bf0f9c5fbbcbdbaf83ba402442ffffffff02206b1000000000001976a91420bb5c3bfaef0231dc05190e7f1c8e22e098991e88acf0ca0100000000001976a9149e3e2d23973a04ec1b02be97c30ab9f2f27c3b2c88ac00000000'; |
|||
var tx2buf = new Buffer(tx2hex, 'hex'); |
|||
|
|||
it('should make a new transaction', function() { |
|||
var tx = new Transaction(); |
|||
should.exist(tx); |
|||
tx = Transaction(); |
|||
should.exist(tx); |
|||
|
|||
Transaction(txbuf).toBuffer().toString('hex').should.equal(txhex); |
|||
|
|||
//should set known defaults
|
|||
tx.version.should.equal(1); |
|||
tx.txinsvi.toNumber().should.equal(0); |
|||
tx.txins.length.should.equal(0); |
|||
tx.txoutsvi.toNumber().should.equal(0); |
|||
tx.txouts.length.should.equal(0); |
|||
tx.nlocktime.should.equal(0xffffffff); |
|||
}); |
|||
|
|||
describe('#initialize', function() { |
|||
|
|||
it('should set these known defaults', function() { |
|||
var tx = new Transaction(); |
|||
tx.initialize(); |
|||
tx.version.should.equal(1); |
|||
tx.txinsvi.toNumber().should.equal(0); |
|||
tx.txins.length.should.equal(0); |
|||
tx.txoutsvi.toNumber().should.equal(0); |
|||
tx.txouts.length.should.equal(0); |
|||
tx.nlocktime.should.equal(0xffffffff); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set all the basic parameters', function() { |
|||
var tx = Transaction().set({ |
|||
version: 0, |
|||
txinsvi: Varint(1), |
|||
txins: [txin], |
|||
txoutsvi: Varint(1), |
|||
txouts: [txout], |
|||
nlocktime: 0 |
|||
}); |
|||
should.exist(tx.version); |
|||
should.exist(tx.txinsvi); |
|||
should.exist(tx.txins); |
|||
should.exist(tx.txoutsvi); |
|||
should.exist(tx.txouts); |
|||
should.exist(tx.nlocktime); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set all the basic parameters', function() { |
|||
var tx = Transaction().fromJSON({ |
|||
version: 0, |
|||
txinsvi: Varint(1).toJSON(), |
|||
txins: [txin.toJSON()], |
|||
txoutsvi: Varint(1).toJSON(), |
|||
txouts: [txout.toJSON()], |
|||
nlocktime: 0 |
|||
}); |
|||
should.exist(tx.version); |
|||
should.exist(tx.txinsvi); |
|||
should.exist(tx.txins); |
|||
should.exist(tx.txoutsvi); |
|||
should.exist(tx.txouts); |
|||
should.exist(tx.nlocktime); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should recover all the basic parameters', function() { |
|||
var json = tx.toJSON(); |
|||
should.exist(json.version); |
|||
should.exist(json.txinsvi); |
|||
should.exist(json.txins); |
|||
should.exist(json.txoutsvi); |
|||
should.exist(json.txouts); |
|||
should.exist(json.nlocktime); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should recover from this known tx', function() { |
|||
Transaction().fromBuffer(txbuf).toBuffer().toString('hex').should.equal(txhex); |
|||
}); |
|||
|
|||
it('should recover from this known tx from the blockchain', function() { |
|||
Transaction().fromBuffer(tx2buf).toBuffer().toString('hex').should.equal(tx2hex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should recover from this known tx', function() { |
|||
Transaction().fromBufferReader(BufferReader(txbuf)).toBuffer().toString('hex').should.equal(txhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should produce this known tx', function() { |
|||
Transaction().fromBuffer(txbuf).toBuffer().toString('hex').should.equal(txhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBufferWriter', function() { |
|||
|
|||
it('should produce this known tx', function() { |
|||
Transaction().fromBuffer(txbuf).toBufferWriter().concat().toString('hex').should.equal(txhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#hash', function() { |
|||
|
|||
it('should correctly calculate the hash of this known transaction', function() { |
|||
var tx = Transaction().fromBuffer(tx2buf); |
|||
var txhashbuf = new Buffer(Array.apply([], new Buffer(tx2idhex, 'hex')).reverse()); |
|||
tx.hash().toString('hex').should.equal(txhashbuf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#id', function() { |
|||
|
|||
it('should correctly calculate the id of this known transaction', function() { |
|||
var tx = Transaction().fromBuffer(tx2buf); |
|||
tx.id().toString('hex').should.equal(tx2idhex); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#pushin', function() { |
|||
|
|||
it('should add an input', function() { |
|||
var txin = Txin(); |
|||
var tx = Transaction(); |
|||
tx.pushin(txin); |
|||
tx.txinsvi.toNumber().should.equal(1); |
|||
tx.txins.length.should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#pushout', function() { |
|||
|
|||
it('should add an output', function() { |
|||
var txout = Txout(); |
|||
var tx = Transaction(); |
|||
tx.pushout(txout); |
|||
tx.txoutsvi.toNumber().should.equal(1); |
|||
tx.txouts.length.should.equal(1); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,124 @@ |
|||
var should = require('chai').should(); |
|||
var Script = require('../lib/script'); |
|||
var Txin = require('../lib/txin'); |
|||
var Varint = require('../lib/varint'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
|
|||
describe('Txin', function() { |
|||
|
|||
var txidbuf = new Buffer(32); |
|||
txidbuf.fill(0); |
|||
var txoutnum = 0; |
|||
var script = Script().fromString("OP_CHECKMULTISIG"); |
|||
var scriptvi = Varint(script.toBuffer().length); |
|||
var seqnum = 0; |
|||
var txin = Txin().set({ |
|||
txidbuf: txidbuf, |
|||
txoutnum: txoutnum, |
|||
scriptvi: scriptvi, |
|||
script: script, |
|||
seqnum: seqnum |
|||
}); |
|||
|
|||
it('should make a new txin', function() { |
|||
var txin = new Txin(); |
|||
should.exist(txin); |
|||
txin = Txin(); |
|||
should.exist(txin); |
|||
var txidbuf = new Buffer(32); |
|||
txidbuf.fill(0); |
|||
Txin(txidbuf).txidbuf.length.should.equal(32); |
|||
(function() { |
|||
var txidbuf2 = new Buffer(33); |
|||
txidbuf2.fill(0); |
|||
Txin(txidbuf2); |
|||
}).should.throw('txidbuf must be 32 bytes'); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set these vars', function() { |
|||
var txin = Txin().set({ |
|||
txidbuf: txidbuf, |
|||
txoutnum: txoutnum, |
|||
scriptvi: scriptvi, |
|||
script: script, |
|||
seqnum: seqnum |
|||
}); |
|||
should.exist(txin.txidbuf); |
|||
should.exist(txin.txoutnum); |
|||
should.exist(txin.scriptvi); |
|||
should.exist(txin.script); |
|||
should.exist(txin.seqnum); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set these vars', function() { |
|||
var txin2 = Txin().fromJSON(txin.toJSON()); |
|||
should.exist(txin2.txidbuf); |
|||
should.exist(txin2.txoutnum); |
|||
should.exist(txin2.scriptvi); |
|||
should.exist(txin2.script); |
|||
should.exist(txin2.seqnum); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should set these vars', function() { |
|||
var json = txin.toJSON() |
|||
should.exist(json.txidbuf); |
|||
should.exist(json.txoutnum); |
|||
should.exist(json.scriptvi); |
|||
should.exist(json.script); |
|||
should.exist(json.seqnum); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should convert this known buffer', function() { |
|||
var hex = '00000000000000000000000000000000000000000000000000000000000000000000000001ae00000000'; |
|||
var buf = new Buffer(hex, 'hex'); |
|||
var txin = Txin().fromBuffer(buf); |
|||
txin.scriptvi.toNumber().should.equal(1); |
|||
txin.script.toString().should.equal('OP_CHECKMULTISIG'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should convert this known buffer', function() { |
|||
var hex = '00000000000000000000000000000000000000000000000000000000000000000000000001ae00000000'; |
|||
var buf = new Buffer(hex, 'hex'); |
|||
var br = BufferReader(buf); |
|||
var txin = Txin().fromBufferReader(br); |
|||
txin.scriptvi.toNumber().should.equal(1); |
|||
txin.script.toString().should.equal('OP_CHECKMULTISIG'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should convert this known buffer', function() { |
|||
txin.toBuffer().toString('hex').should.equal('00000000000000000000000000000000000000000000000000000000000000000000000001ae00000000'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBufferWriter', function() { |
|||
|
|||
it('should convert this known buffer', function() { |
|||
txin.toBufferWriter().concat().toString('hex').should.equal('00000000000000000000000000000000000000000000000000000000000000000000000001ae00000000'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,110 @@ |
|||
var should = require('chai').should(); |
|||
var BN = require('../lib/bn'); |
|||
var Txout = require('../lib/txout'); |
|||
var Script = require('../lib/script'); |
|||
var Varint = require('../lib/varint'); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
|
|||
describe('Txout', function() { |
|||
|
|||
var valuebn = BN(5); |
|||
var script = Script().fromString("OP_CHECKMULTISIG"); |
|||
var scriptvi = Varint(script.toBuffer().length); |
|||
var txout = new Txout().set({ |
|||
valuebn: valuebn, |
|||
scriptvi: scriptvi, |
|||
script: script |
|||
}); |
|||
|
|||
it('should make a new txout', function() { |
|||
var txout = new Txout(); |
|||
should.exist(txout); |
|||
txout = Txout(); |
|||
should.exist(txout); |
|||
Txout(valuebn, scriptvi, script).valuebn.toString().should.equal('5'); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set this object', function() { |
|||
var txout = new Txout().set({ |
|||
valuebn: valuebn, |
|||
scriptvi: scriptvi, |
|||
script: script |
|||
}); |
|||
should.exist(txout.valuebn); |
|||
should.exist(txout.scriptvi); |
|||
should.exist(txout.script); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set from this json', function() { |
|||
var txout = Txout().fromJSON({ |
|||
valuebn: valuebn.toJSON(), |
|||
scriptvi: scriptvi.toJSON(), |
|||
script: script.toJSON() |
|||
}); |
|||
should.exist(txout.valuebn); |
|||
should.exist(txout.scriptvi); |
|||
should.exist(txout.script); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should return this json', function() { |
|||
var txout = Txout().fromJSON({ |
|||
valuebn: valuebn.toJSON(), |
|||
scriptvi: scriptvi.toJSON(), |
|||
script: script.toJSON() |
|||
}); |
|||
var json = txout.toJSON(); |
|||
should.exist(json.valuebn); |
|||
should.exist(json.scriptvi); |
|||
should.exist(json.script); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should make this txin from this known buffer', function() { |
|||
var txout = Txout().fromBuffer(new Buffer('050000000000000001ae', 'hex')); |
|||
txout.toBuffer().toString('hex').should.equal('050000000000000001ae'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should make this txin from this known buffer', function() { |
|||
var txout = Txout().fromBufferReader(BufferReader(new Buffer('050000000000000001ae', 'hex'))); |
|||
txout.toBuffer().toString('hex').should.equal('050000000000000001ae'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should output this known buffer', function() { |
|||
var txout = Txout().fromBufferReader(BufferReader(new Buffer('050000000000000001ae', 'hex'))); |
|||
txout.toBuffer().toString('hex').should.equal('050000000000000001ae'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBufferWriter', function() { |
|||
|
|||
it('should output this known buffer', function() { |
|||
var txout = Txout().fromBufferReader(BufferReader(new Buffer('050000000000000001ae', 'hex'))); |
|||
txout.toBufferWriter().concat().toString('hex').should.equal('050000000000000001ae'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
@ -0,0 +1,123 @@ |
|||
var BN = require('../lib/bn'); |
|||
var should = require('chai').should(); |
|||
var BufferReader = require('../lib/bufferreader'); |
|||
var BufferWriter = require('../lib/bufferwriter'); |
|||
var Varint = require('../lib/varint'); |
|||
|
|||
describe('Varint', function() { |
|||
|
|||
it('should make a new varint', function() { |
|||
var buf = new Buffer('00', 'hex'); |
|||
var varint = new Varint(buf); |
|||
should.exist(varint); |
|||
varint.buf.toString('hex').should.equal('00'); |
|||
varint = Varint(buf); |
|||
should.exist(varint); |
|||
varint.buf.toString('hex').should.equal('00'); |
|||
|
|||
//various ways to use the constructor
|
|||
Varint(Varint(0).toBuffer()).toNumber().should.equal(0); |
|||
Varint(0).toNumber().should.equal(0); |
|||
Varint(BN(0)).toNumber().should.equal(0); |
|||
}); |
|||
|
|||
describe('#set', function() { |
|||
|
|||
it('should set a buffer', function() { |
|||
var buf = new Buffer('00', 'hex'); |
|||
var varint = Varint().set({buf: buf}); |
|||
varint.buf.toString('hex').should.equal('00'); |
|||
varint.set({}); |
|||
varint.buf.toString('hex').should.equal('00'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromJSON', function() { |
|||
|
|||
it('should set a buffer', function() { |
|||
var buf = BufferWriter().writeVarintNum(5).concat(); |
|||
var varint = Varint().fromJSON(buf.toString('hex')); |
|||
varint.toNumber().should.equal(5); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toJSON', function() { |
|||
|
|||
it('should return a buffer', function() { |
|||
var buf = BufferWriter().writeVarintNum(5).concat(); |
|||
var varint = Varint().fromJSON(buf.toString('hex')); |
|||
varint.toJSON().should.equal('05'); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBuffer', function() { |
|||
|
|||
it('should set a buffer', function() { |
|||
var buf = BufferWriter().writeVarintNum(5).concat(); |
|||
var varint = Varint().fromBuffer(buf); |
|||
varint.toNumber().should.equal(5); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBufferReader', function() { |
|||
|
|||
it('should set a buffer reader', function() { |
|||
var buf = BufferWriter().writeVarintNum(5).concat(); |
|||
var br = BufferReader(buf); |
|||
var varint = Varint().fromBufferReader(br); |
|||
varint.toNumber().should.equal(5); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromBN', function() { |
|||
|
|||
it('should set a number', function() { |
|||
var varint = Varint().fromBN(BN(5)); |
|||
varint.toNumber().should.equal(5); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#fromNumber', function() { |
|||
|
|||
it('should set a number', function() { |
|||
var varint = Varint().fromNumber(5); |
|||
varint.toNumber().should.equal(5); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBuffer', function() { |
|||
|
|||
it('should return a buffer', function() { |
|||
buf = BufferWriter().writeVarintNum(5).concat(); |
|||
var varint = Varint(buf); |
|||
varint.toBuffer().toString('hex').should.equal(buf.toString('hex')); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toBN', function() { |
|||
|
|||
it('should return a buffer', function() { |
|||
var varint = Varint(5); |
|||
varint.toBN().toString().should.equal(BN(5).toString()); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
describe('#toNumber', function() { |
|||
|
|||
it('should return a buffer', function() { |
|||
var varint = Varint(5); |
|||
varint.toNumber().should.equal(5); |
|||
}); |
|||
|
|||
}); |
|||
|
|||
}); |
Loading…
Reference in new issue