Merge branch 'master' of ../fullnode into v0.8
Conflicts: .gitignore .travis.yml README.md
This commit is contained in:
commit
fb1a193893
|
@ -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
|
||||
|
|
|
@ -9,4 +9,3 @@ notifications:
|
|||
- '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} (<a href="%{build_url}">Details</a>/<a href="%{compare_url}">Change view</a>)'
|
||||
format: html
|
||||
on_success: never
|
||||
|
||||
|
|
|
@ -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