replace tabs with 2 spaces using "expand"

This commit is contained in:
Matias Alejo Garcia 2014-01-16 06:21:35 -03:00
parent c24ae73cf5
commit f35c03544b
16 changed files with 625 additions and 625 deletions

View File

@ -39,12 +39,12 @@ function spec(b) {
Block.prototype.getHeader = function getHeader() {
var buf = new Buffer(80);
var ofs = 0;
buf.writeUInt32LE(this.version, ofs); ofs += 4;
this.prev_hash.copy(buf, ofs); ofs += 32;
this.merkle_root.copy(buf, ofs); ofs += 32;
buf.writeUInt32LE(this.timestamp, ofs); ofs += 4;
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
buf.writeUInt32LE(this.version, ofs); ofs += 4;
this.prev_hash.copy(buf, ofs); ofs += 32;
this.merkle_root.copy(buf, ofs); ofs += 32;
buf.writeUInt32LE(this.timestamp, ofs); ofs += 4;
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
return buf;
};

180
Bloom.js
View File

@ -1,116 +1,116 @@
require('classtool');
function ClassSpec(b) {
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
var MAX_HASH_FUNCS = 50;
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
var MAX_HASH_FUNCS = 50;
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
function Bloom() {
this.data = '';
this.hashFuncs = 0;
};
function Bloom() {
this.data = '';
this.hashFuncs = 0;
};
function ROTL32(x, r) {
return (x << r) | (x >> (32 - r));
};
function ROTL32(x, r) {
return (x << r) | (x >> (32 - r));
};
function getBlockU32(blockIdx, data) {
var idx = blockIdx * 4;
var v = (data[idx + 0] << (0 * 8)) |
(data[idx + 1] << (1 * 8)) |
(data[idx + 2] << (2 * 8)) |
(data[idx + 3] << (3 * 8));
return v;
};
function getBlockU32(blockIdx, data) {
var idx = blockIdx * 4;
var v = (data[idx + 0] << (0 * 8)) |
(data[idx + 1] << (1 * 8)) |
(data[idx + 2] << (2 * 8)) |
(data[idx + 3] << (3 * 8));
return v;
};
Bloom.prototype.hash = function(hashNum, data) {
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
var nBlocks = data.length / 4;
Bloom.prototype.hash = function(hashNum, data) {
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
var nBlocks = data.length / 4;
// data body
for (var i = -nBlocks; i; i++) {
var k1 = getBlockU32(i);
// data body
for (var i = -nBlocks; i; i++) {
var k1 = getBlockU32(i);
k1 *= c1;
k1 = ROTLF32(k1, 15);
k1 *= c2;
k1 *= c1;
k1 = ROTLF32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = ROTFL(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
h1 ^= k1;
h1 = ROTFL(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// tail (trailing 1-3 bytes)
var tail = data.slice(nBlocks * 4);
// tail (trailing 1-3 bytes)
var tail = data.slice(nBlocks * 4);
var k1 = 0;
var k1 = 0;
switch (data.length & 3) {
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
switch (data.length & 3) {
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
// finalize
h1 ^= data.length;
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
// finalize
h1 ^= data.length;
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1 % (this.data.length * 8);
};
return h1 % (this.data.length * 8);
};
Bloom.prototype.insert = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
this.data[index >> 3] |= bit_mask[7 & index];
}
};
Bloom.prototype.insert = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
this.data[index >> 3] |= bit_mask[7 & index];
}
};
Bloom.prototype.contains = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
if (!(this.data[index >> 3] & bit_mask[7 & index]))
return false;
}
Bloom.prototype.contains = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
if (!(this.data[index >> 3] & bit_mask[7 & index]))
return false;
}
return true;
};
return true;
};
Bloom.prototype.sizeOk = function() {
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
this.hashFuncs <= MAX_HASH_FUNCS;
};
Bloom.prototype.sizeOk = function() {
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
this.hashFuncs <= MAX_HASH_FUNCS;
};
function toInt(v) {
return ~~v;
}
function toInt(v) {
return ~~v;
}
function min(a, b) {
if (a < b)
return a;
return b;
}
function min(a, b) {
if (a < b)
return a;
return b;
}
Bloom.prototype.init = function(elements, FPRate) {
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
MAX_BLOOM_FILTER_SIZE * 8) / 8;
this.data[filterSize] = 0;
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
MAX_HASH_FUNCS);
};
Bloom.prototype.init = function(elements, FPRate) {
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
MAX_BLOOM_FILTER_SIZE * 8) / 8;
this.data[filterSize] = 0;
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
MAX_HASH_FUNCS);
};
return Bloom;
return Bloom;
};
module.defineClass(ClassSpec);

View File

@ -443,8 +443,8 @@ function spec(b) {
data.headers = [];
for (i = 0; i < data.count; i++) {
var header = new Block();
header.parse(parser);
data.headers.push(header);
header.parse(parser);
data.headers.push(header);
}
break;
@ -474,7 +474,7 @@ function spec(b) {
lock_time: tx.lock_time,
ins: tx.ins,
outs: tx.outs,
tx: tx,
tx: tx,
};
case 'getblocks':

View File

@ -1,8 +1,8 @@
exports.intFromCompact = function(c)
{
var bytes = ((c >>> 24) & 0xff) >>> 0;
var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0;
return v;
var bytes = ((c >>> 24) & 0xff) >>> 0;
var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0;
return v;
}

8
SIN.js
View File

@ -11,16 +11,16 @@ function ClassSpec(b) {
};
this.data = new Buffer(1 + 1 + payload.length);
this.__proto__ = this.encodings['binary'];
this.prefix(0x0F); // SIN magic number, in numberspace
this.prefix(0x0F); // SIN magic number, in numberspace
this.type(type);
this.payload(payload);
};
SIN.superclass = superclass;
superclass.applyEncodingsTo(SIN);
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
// get or set the prefix data (the first byte of the address)
SIN.prototype.prefix = function(num) {

View File

@ -1,43 +1,43 @@
require('classtool');
function ClassSpec(b) {
var coinUtil = require('./util/util');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var SIN = require('./SIN').class();
var coinUtil = require('./util/util');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var SIN = require('./SIN').class();
function SINKey(cfg) {
if (typeof cfg != 'object')
cfg = {};
function SINKey(cfg) {
if (typeof cfg != 'object')
cfg = {};
this.created = cfg.created;
this.privKey = cfg.privKey;
};
this.created = cfg.created;
this.privKey = cfg.privKey;
};
SINKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
SINKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
SINKey.prototype.pubkeyHash = function() {
return coinUtil.sha256ripe160(this.privKey.public);
};
SINKey.prototype.pubkeyHash = function() {
return coinUtil.sha256ripe160(this.privKey.public);
};
SINKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = this.pubkeyHash();
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
var obj = {
created: this.created,
priv: this.privKey.private.toString('hex'),
pub: pubKey,
sin: sin.toString(),
};
SINKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = this.pubkeyHash();
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
var obj = {
created: this.created,
priv: this.privKey.private.toString('hex'),
pub: pubKey,
sin: sin.toString(),
};
return obj;
};
return obj;
};
return SINKey;
return SINKey;
};
module.defineClass(ClassSpec);

106
Script.js
View File

@ -84,42 +84,42 @@ function spec(b) {
Script.prototype.isP2SH = function ()
{
return (this.chunks.length == 3 &&
this.chunks[0] == OP_HASH160 &&
Buffer.isBuffer(this.chunks[1]) &&
this.chunks[1].length == 20 &&
this.chunks[2] == OP_EQUAL);
this.chunks[0] == OP_HASH160 &&
Buffer.isBuffer(this.chunks[1]) &&
this.chunks[1].length == 20 &&
this.chunks[2] == OP_EQUAL);
};
Script.prototype.isPubkey = function ()
{
return (this.chunks.length == 2 &&
Buffer.isBuffer(this.chunks[0]) &&
this.chunks[1] == OP_CHECKSIG);
Buffer.isBuffer(this.chunks[0]) &&
this.chunks[1] == OP_CHECKSIG);
};
Script.prototype.isPubkeyHash = function ()
{
return (this.chunks.length == 5 &&
this.chunks[0] == OP_DUP &&
this.chunks[1] == OP_HASH160 &&
Buffer.isBuffer(this.chunks[2]) &&
this.chunks[2].length == 20 &&
this.chunks[3] == OP_EQUALVERIFY &&
this.chunks[4] == OP_CHECKSIG);
this.chunks[0] == OP_DUP &&
this.chunks[1] == OP_HASH160 &&
Buffer.isBuffer(this.chunks[2]) &&
this.chunks[2].length == 20 &&
this.chunks[3] == OP_EQUALVERIFY &&
this.chunks[4] == OP_CHECKSIG);
};
function isSmallIntOp(opcode)
{
return ((opcode == OP_0) ||
((opcode >= OP_1) && (opcode <= OP_16)));
((opcode >= OP_1) && (opcode <= OP_16)));
};
Script.prototype.isMultiSig = function ()
{
return (this.chunks.length > 3 &&
isSmallIntOp(this.chunks[0]) &&
isSmallIntOp(this.chunks[this.chunks.length-2]) &&
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG);
isSmallIntOp(this.chunks[0]) &&
isSmallIntOp(this.chunks[this.chunks.length-2]) &&
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG);
};
Script.prototype.finishedMultiSig = function()
@ -166,60 +166,60 @@ function spec(b) {
// is this a script form we know?
Script.prototype.classify = function ()
{
if (this.isPubkeyHash())
return TX_PUBKEYHASH;
if (this.isP2SH())
return TX_SCRIPTHASH;
if (this.isMultiSig())
return TX_MULTISIG;
if (this.isPubkey())
return TX_PUBKEY;
return TX_UNKNOWN;
if (this.isPubkeyHash())
return TX_PUBKEYHASH;
if (this.isP2SH())
return TX_SCRIPTHASH;
if (this.isMultiSig())
return TX_MULTISIG;
if (this.isPubkey())
return TX_PUBKEY;
return TX_UNKNOWN;
};
// extract useful data items from known scripts
Script.prototype.capture = function ()
{
var txType = this.classify();
var res = [];
switch (txType) {
case TX_PUBKEY:
res.push(this.chunks[0]);
break;
case TX_PUBKEYHASH:
res.push(this.chunks[2]);
break;
case TX_MULTISIG:
for (var i = 1; i < (this.chunks.length - 2); i++)
res.push(this.chunks[i]);
break;
case TX_SCRIPTHASH:
res.push(this.chunks[1]);
break;
var txType = this.classify();
var res = [];
switch (txType) {
case TX_PUBKEY:
res.push(this.chunks[0]);
break;
case TX_PUBKEYHASH:
res.push(this.chunks[2]);
break;
case TX_MULTISIG:
for (var i = 1; i < (this.chunks.length - 2); i++)
res.push(this.chunks[i]);
break;
case TX_SCRIPTHASH:
res.push(this.chunks[1]);
break;
case TX_UNKNOWN:
default:
// do nothing
break;
}
case TX_UNKNOWN:
default:
// do nothing
break;
}
return res;
return res;
};
// return first extracted data item from script
Script.prototype.captureOne = function ()
{
var arr = this.capture();
return arr[0];
var arr = this.capture();
return arr[0];
};
Script.prototype.getOutType = function ()
{
var txType = this.classify();
switch (txType) {
case TX_PUBKEY: return 'Pubkey';
case TX_PUBKEYHASH: return 'Address';
default: return 'Strange';
case TX_PUBKEY: return 'Pubkey';
case TX_PUBKEYHASH: return 'Address';
default: return 'Strange';
}
};
@ -446,7 +446,7 @@ function spec(b) {
var script = new Script();
script.writeN(n_required);
keys.forEach(function(key) {
script.writeBytes(key);
script.writeBytes(key);
});
script.writeN(keys.length);
script.writeOp(OP_CHECKMULTISIG);

View File

@ -918,85 +918,85 @@ function spec(b) {
};
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy)
hashType, opts, callback, si, siCopy)
{
if (siCopy.stack.length == 0) {
callback(null, false);
return;
}
callback(null, castBool(siCopy.stackBack()));
if (siCopy.stack.length == 0) {
callback(null, false);
return;
}
callback(null, castBool(siCopy.stackBack()));
}
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy)
hashType, opts, callback, si, siCopy)
{
if (si.stack.length == 0) {
callback(null, false);
return;
}
if (castBool(si.stackBack()) == false) {
callback(null, false);
return;
}
if (si.stack.length == 0) {
callback(null, false);
return;
}
if (castBool(si.stackBack()) == false) {
callback(null, false);
return;
}
// if not P2SH, we're done
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
callback(null, true);
return;
}
// if not P2SH, we're done
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
callback(null, true);
return;
}
if (!scriptSig.isPushOnly()) {
callback(null, false);
return;
}
if (!scriptSig.isPushOnly()) {
callback(null, false);
return;
}
assert.notEqual(siCopy.length, 0);
assert.notEqual(siCopy.length, 0);
var subscript = new Script(siCopy.stackPop());
var subscript = new Script(siCopy.stackPop());
ok = true;
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
ok = true;
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
}
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy)
hashType, opts, callback, si, siCopy)
{
if (opts.verifyP2SH) {
si.stack.forEach(function(item) {
siCopy.stack.push(item);
});
}
if (opts.verifyP2SH) {
si.stack.forEach(function(item) {
siCopy.stack.push(item);
});
}
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
}
ScriptInterpreter.verifyFull =
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
opts, callback)
opts, callback)
{
var si = new ScriptInterpreter();
var siCopy = new ScriptInterpreter();
var si = new ScriptInterpreter();
var siCopy = new ScriptInterpreter();
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
};
var checkSig = ScriptInterpreter.checkSig =

202
Sign.js
View File

@ -1,133 +1,133 @@
function signOne(hash, addrStr, keys)
{
var keyObj = keys[addrStr];
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
var key = new KeyModule.Key();
key.private = rawPrivKey;
var signature = key.signSync(hash);
var keyObj = keys[addrStr];
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
var key = new KeyModule.Key();
key.private = rawPrivKey;
var signature = key.signSync(hash);
return signature;
return signature;
}
function signTxIn(nIn, tx, txInputs, network, keys, scripts)
{
// locate TX input needing a signature
var txin = tx.ins[nIn];
var scriptSig = txin.getScript();
// locate TX input needing a signature
var txin = tx.ins[nIn];
var scriptSig = txin.getScript();
// locate TX output, within txInputs
var txoutHash = txin.getOutpointHash();
if (!(txoutHash in txInputs))
throw new Error("signTxIn missing input hash");
var txFrom = txInputs[txoutHash];
var txoutIndex = txin.getOutpointIndex();
if (txFrom.outs.length >= txoutIndex)
throw new Error("signTxIn missing input index");
var txout = txFrom.outs[txoutIndex];
var scriptPubKey = txout.getScript();
// locate TX output, within txInputs
var txoutHash = txin.getOutpointHash();
if (!(txoutHash in txInputs))
throw new Error("signTxIn missing input hash");
var txFrom = txInputs[txoutHash];
var txoutIndex = txin.getOutpointIndex();
if (txFrom.outs.length >= txoutIndex)
throw new Error("signTxIn missing input index");
var txout = txFrom.outs[txoutIndex];
var scriptPubKey = txout.getScript();
// detect type of transaction, and extract useful elements
var txType = scriptPubKey.classify();
if (txType == TX_UNKNOWN)
throw new Error("unknown TX type");
var scriptData = scriptPubKey.capture();
// detect type of transaction, and extract useful elements
var txType = scriptPubKey.classify();
if (txType == TX_UNKNOWN)
throw new Error("unknown TX type");
var scriptData = scriptPubKey.capture();
// if P2SH, lookup the script
var subscriptRaw = undefined;
var subscript = undefined;
var subType = undefined;
var subData = undefined;
if (txType == TX_SCRIPTHASH) {
var addr = new Address(network.addressScript, scriptData[0]);
var addrStr = addr.toString();
if (!(addrStr in scripts))
throw new Error("unknown script hash address");
// if P2SH, lookup the script
var subscriptRaw = undefined;
var subscript = undefined;
var subType = undefined;
var subData = undefined;
if (txType == TX_SCRIPTHASH) {
var addr = new Address(network.addressScript, scriptData[0]);
var addrStr = addr.toString();
if (!(addrStr in scripts))
throw new Error("unknown script hash address");
subscriptRaw = new Buffer(scripts[addrStr], 'hex');
subscript = new Script(subscriptRaw);
subType = subscript.classify();
if (subType == TX_UNKNOWN)
throw new Error("unknown subscript TX type");
subData = subscript.capture();
}
subscriptRaw = new Buffer(scripts[addrStr], 'hex');
subscript = new Script(subscriptRaw);
subType = subscript.classify();
if (subType == TX_UNKNOWN)
throw new Error("unknown subscript TX type");
subData = subscript.capture();
}
var hash = tx.hashForSignature(scriptPubKey, i, 0);
var hash = tx.hashForSignature(scriptPubKey, i, 0);
switch (txType) {
case TX_PUBKEY:
// already signed
if (scriptSig.chunks.length > 0)
return;
switch (txType) {
case TX_PUBKEY:
// already signed
if (scriptSig.chunks.length > 0)
return;
var pubkeyhash = util.sha256ripe160(scriptData[0]);
var addr = new Address(network.addressPubkey, pubkeyhash);
var addrStr = addr.toString();
if (!(addrStr in keys))
throw new Error("unknown pubkey");
var pubkeyhash = util.sha256ripe160(scriptData[0]);
var addr = new Address(network.addressPubkey, pubkeyhash);
var addrStr = addr.toString();
if (!(addrStr in keys))
throw new Error("unknown pubkey");
var signature = signOne(hash, addrStr, keys);
scriptSig.writeBytes(signature);
break;
var signature = signOne(hash, addrStr, keys);
scriptSig.writeBytes(signature);
break;
case TX_PUBKEYHASH:
// already signed
if (scriptSig.chunks.length > 0)
return;
case TX_PUBKEYHASH:
// already signed
if (scriptSig.chunks.length > 0)
return;
var addr = new Address(network.addressPubkey, scriptData[0]);
var addrStr = addr.toString();
if (!(addrStr in keys))
throw new Error("unknown pubkey hash address");
var addr = new Address(network.addressPubkey, scriptData[0]);
var addrStr = addr.toString();
if (!(addrStr in keys))
throw new Error("unknown pubkey hash address");
var signature = signOne(hash, addrStr, keys);
scriptSig.writeBytes(signature);
scriptSig.writeBytes(key.public);
break;
var signature = signOne(hash, addrStr, keys);
scriptSig.writeBytes(signature);
scriptSig.writeBytes(key.public);
break;
case TX_SCRIPTHASH:
// already signed
if (scriptSig.chunks.length > 0)
return;
case TX_SCRIPTHASH:
// already signed
if (scriptSig.chunks.length > 0)
return;
var addr = new Address(network.addressPubkey, subData[0]);
var addrStr = addr.toString();
if (!(addrStr in keys))
throw new Error("unknown script(pubkey hash) address");
var addr = new Address(network.addressPubkey, subData[0]);
var addrStr = addr.toString();
if (!(addrStr in keys))
throw new Error("unknown script(pubkey hash) address");
var signature = signOne(hash, addrStr, keys);
scriptSig.writeBytes(signature);
scriptSig.writeBytes(key.public);
break;
var signature = signOne(hash, addrStr, keys);
scriptSig.writeBytes(signature);
scriptSig.writeBytes(key.public);
break;
case TX_MULTISIG:
while (scriptSig.chunks.length < scriptData.length) {
scriptSig.writeBytes(util.EMPTY_BUFFER);
}
for (var i = 0; i < scriptData.length; i++) {
// skip already signed
if (scriptSig.chunks[i].length > 0)
continue;
case TX_MULTISIG:
while (scriptSig.chunks.length < scriptData.length) {
scriptSig.writeBytes(util.EMPTY_BUFFER);
}
for (var i = 0; i < scriptData.length; i++) {
// skip already signed
if (scriptSig.chunks[i].length > 0)
continue;
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
var addr = new Address(network.addressPubkey, pubkeyhash);
var addrStr = addr.toString();
if (!(addrStr in keys))
continue;
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
var addr = new Address(network.addressPubkey, pubkeyhash);
var addrStr = addr.toString();
if (!(addrStr in keys))
continue;
var signature = signOne(hash, addrStr, keys);
scriptSig.chunks[i] = signature;
}
break;
}
var signature = signOne(hash, addrStr, keys);
scriptSig.chunks[i] = signature;
}
break;
}
if (txtype == TX_SCRIPTHASH)
scriptSig.writeBytes(subscriptRaw);
if (txtype == TX_SCRIPTHASH)
scriptSig.writeBytes(subscriptRaw);
}
exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts)
{
for (var i = 0; i < tx.ins.length; i++)
signTxIn(i, tx, txInputs, network, keys, scripts);
for (var i = 0; i < tx.ins.length; i++)
signTxIn(i, tx, txInputs, network, keys, scripts);
};

224
Wallet.js
View File

@ -2,141 +2,141 @@ require('classtool');
var hex = function(hex) {return new Buffer(hex, 'hex');};
function ClassSpec(b) {
var fs = require('fs');
var EncFile = require('./util/EncFile');
var Address = require('./Address').class();
var networks = require('./networks');
var util = b.util || require('./util/util');
var ENC_METHOD = 'aes-256-cbc';
var fs = require('fs');
var EncFile = require('./util/EncFile');
var Address = require('./Address').class();
var networks = require('./networks');
var util = b.util || require('./util/util');
var ENC_METHOD = 'aes-256-cbc';
var skeleton = {
client: 'libcoin',
client_version: '0.0.1',
network: 'testnet',
version: 1,
best_hash: null,
best_height: -1,
keys: [],
sin: {},
scripts: {},
};
var skeleton = {
client: 'libcoin',
client_version: '0.0.1',
network: 'testnet',
version: 1,
best_hash: null,
best_height: -1,
keys: [],
sin: {},
scripts: {},
};
function Wallet(cfg) {
if (typeof cfg !== 'object')
cfg = {};
function Wallet(cfg) {
if (typeof cfg !== 'object')
cfg = {};
// deep copy (no references)
if (cfg.datastore)
this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
else
this.datastore = JSON.parse(JSON.stringify(skeleton));
// deep copy (no references)
if (cfg.datastore)
this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
else
this.datastore = JSON.parse(JSON.stringify(skeleton));
this.network = undefined;
this.dirty = cfg.dirty || true;
};
this.network = undefined;
this.dirty = cfg.dirty || true;
};
Wallet.prototype.readSync = function(filename, passphrase) {
this.datastore = EncFile.readJFileSync(ENC_METHOD,
passphrase, filename);
this.dirty = false;
};
Wallet.prototype.readSync = function(filename, passphrase) {
this.datastore = EncFile.readJFileSync(ENC_METHOD,
passphrase, filename);
this.dirty = false;
};
Wallet.prototype.writeSync = function(filename, passphrase) {
var tmp_fn = filename + ".tmp";
Wallet.prototype.writeSync = function(filename, passphrase) {
var tmp_fn = filename + ".tmp";
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
this.datastore);
fs.renameSync(tmp_fn, filename);
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
this.datastore);
fs.renameSync(tmp_fn, filename);
this.dirty = false;
};
this.dirty = false;
};
Wallet.prototype.setNetwork = function(netname) {
if (!netname)
netname = this.datastore.network;
Wallet.prototype.setNetwork = function(netname) {
if (!netname)
netname = this.datastore.network;
switch (netname) {
case "mainnet":
case "livenet":
this.network = networks.livenet;
break;
case "testnet":
this.network = networks.testnet;
break;
default:
throw new Error("Unsupported network");
}
switch (netname) {
case "mainnet":
case "livenet":
this.network = networks.livenet;
break;
case "testnet":
this.network = networks.testnet;
break;
default:
throw new Error("Unsupported network");
}
// store+canonicalize name
this.datastore['network'] = this.network.name;
this.dirty = true;
};
// store+canonicalize name
this.datastore['network'] = this.network.name;
this.dirty = true;
};
Wallet.prototype.addKey = function(wkey) {
this.datastore.keys.push(wkey);
this.dirty = true;
};
Wallet.prototype.addKey = function(wkey) {
this.datastore.keys.push(wkey);
this.dirty = true;
};
Wallet.prototype.addSIN = function(sinObj) {
this.datastore.sin[sinObj.sin] = sinObj;
this.dirty = true;
};
Wallet.prototype.addSIN = function(sinObj) {
this.datastore.sin[sinObj.sin] = sinObj;
this.dirty = true;
};
Wallet.prototype.findKeyHash = function(pubKeyHash) {
var pkhStr = pubKeyHash.toString();
Wallet.prototype.findKeyHash = function(pubKeyHash) {
var pkhStr = pubKeyHash.toString();
for (var i = 0; i < this.datastore.keys.length; i++) {
var obj = this.datastore.keys[i];
var addrStr = obj.addr;
var addr = new Address(addrStr);
if (addr.payload().toString() == pkhStr)
return obj;
}
for (var i = 0; i < this.datastore.keys.length; i++) {
var obj = this.datastore.keys[i];
var addrStr = obj.addr;
var addr = new Address(addrStr);
if (addr.payload().toString() == pkhStr)
return obj;
}
return undefined;
};
return undefined;
};
Wallet.prototype.expandKey = function(key) {
var addr = new Address(key);
var isAddr = true;
Wallet.prototype.expandKey = function(key) {
var addr = new Address(key);
var isAddr = true;
try {
addr.validate();
var b = addr.payload();
var obj = this.findKeyHash(b);
key = obj.pub;
} catch(e) {
// do nothing
}
try {
addr.validate();
var b = addr.payload();
var obj = this.findKeyHash(b);
key = obj.pub;
} catch(e) {
// do nothing
}
var re = /^[a-fA-F0-9]+$/;
if (!key.match(re))
throw new Error("Unknown key type");
return hex(key);
};
var re = /^[a-fA-F0-9]+$/;
if (!key.match(re))
throw new Error("Unknown key type");
return hex(key);
};
Wallet.prototype.expandKeys = function(keys) {
var res = [];
var us = this;
keys.forEach(function(key) {
var expKey = us.expandKey(key);
res.push(expKey);
});
return res;
};
Wallet.prototype.expandKeys = function(keys) {
var res = [];
var us = this;
keys.forEach(function(key) {
var expKey = us.expandKey(key);
res.push(expKey);
});
return res;
};
Wallet.prototype.addScript = function(script) {
var buf = script.getBuffer();
var hash = util.sha256ripe160(buf);
var addr = new Address(this.network.addressScript, hash);
var addrStr = addr.as('base58');
this.datastore.scripts[addrStr] = buf.toString('hex');
this.dirty = true;
Wallet.prototype.addScript = function(script) {
var buf = script.getBuffer();
var hash = util.sha256ripe160(buf);
var addr = new Address(this.network.addressScript, hash);
var addrStr = addr.as('base58');
this.datastore.scripts[addrStr] = buf.toString('hex');
this.dirty = true;
return addrStr;
};
return addrStr;
};
return Wallet;
return Wallet;
};
module.defineClass(ClassSpec);

View File

@ -1,53 +1,53 @@
require('classtool');
function ClassSpec(b) {
var coinUtil = require('./util/util');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var PrivateKey = require('./PrivateKey').class();
var Address = require('./Address').class();
var coinUtil = require('./util/util');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var PrivateKey = require('./PrivateKey').class();
var Address = require('./Address').class();
function WalletKey(cfg) {
this.network = cfg.network; // required
this.created = cfg.created;
this.privKey = cfg.privKey;
};
function WalletKey(cfg) {
this.network = cfg.network; // required
this.created = cfg.created;
this.privKey = cfg.privKey;
};
WalletKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
WalletKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
WalletKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
var addr = new Address(this.network.addressPubkey, pubKeyHash);
var priv = new PrivateKey(this.network.keySecret, this.privKey.private, this.privKey.compressed);
var obj = {
created: this.created,
priv: priv.toString(),
pub: pubKey,
addr: addr.toString(),
};
WalletKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
var addr = new Address(this.network.addressPubkey, pubKeyHash);
var priv = new PrivateKey(this.network.keySecret, this.privKey.private, this.privKey.compressed);
var obj = {
created: this.created,
priv: priv.toString(),
pub: pubKey,
addr: addr.toString(),
};
return obj;
};
return obj;
};
WalletKey.prototype.fromObj = function(obj) {
this.created = obj.created;
this.privKey = new KeyModule.Key();
if (obj.priv.length==64) {
this.privKey.private = new Buffer(obj.priv,'hex');
this.privKey.compressed = true;
}
else {
var priv = new PrivateKey(obj.priv);
this.privKey.private = new Buffer(priv.payload());
this.privKey.compressed = priv.compressed();
}
this.privKey.regenerateSync();
};
WalletKey.prototype.fromObj = function(obj) {
this.created = obj.created;
this.privKey = new KeyModule.Key();
if (obj.priv.length==64) {
this.privKey.private = new Buffer(obj.priv,'hex');
this.privKey.compressed = true;
}
else {
var priv = new PrivateKey(obj.priv);
this.privKey.private = new Buffer(priv.payload());
this.privKey.compressed = priv.compressed();
}
this.privKey.regenerateSync();
};
return WalletKey;
return WalletKey;
};
module.defineClass(ClassSpec);

View File

@ -1,8 +1,8 @@
MSG = {
TX: 1,
BLOCK: 2,
FILTERED_BLOCK: 3,
TX: 1,
BLOCK: 2,
FILTERED_BLOCK: 3,
};
MSG.to_str = function(t) {

View File

@ -10,104 +10,104 @@ suite('basic');
function test_encode_priv(b58, payload, isTestnet, isCompressed)
{
var network = isTestnet ? networks.testnet : networks.livenet;
var version = network.keySecret;
var network = isTestnet ? networks.testnet : networks.livenet;
var version = network.keySecret;
var buf_pl = new Buffer(payload, 'hex');
var buf;
if (isCompressed) {
buf = new Buffer(buf_pl.length + 1);
buf_pl.copy(buf);
buf[buf_pl.length] = 1;
} else
buf = buf_pl;
var buf_pl = new Buffer(payload, 'hex');
var buf;
if (isCompressed) {
buf = new Buffer(buf_pl.length + 1);
buf_pl.copy(buf);
buf[buf_pl.length] = 1;
} else
buf = buf_pl;
var key = new KeyModule.Key();
key.private = buf;
key.compressed = isCompressed;
var key = new KeyModule.Key();
key.private = buf;
key.compressed = isCompressed;
var privkey = new PrivateKey(version, buf);
assert.equal(privkey.toString(), b58);
var privkey = new PrivateKey(version, buf);
assert.equal(privkey.toString(), b58);
}
function test_encode_pub(b58, payload, isTestnet, addrType)
{
var isScript = (addrType == 'script');
var network = isTestnet ? networks.testnet : networks.livenet;
var version = isScript ? network.addressScript : network.addressPubkey;
var buf = new Buffer(payload, 'hex');
var addr = new Address(version, buf);
assert.equal(addr.toString(), b58);
var isScript = (addrType == 'script');
var network = isTestnet ? networks.testnet : networks.livenet;
var version = isScript ? network.addressScript : network.addressPubkey;
var buf = new Buffer(payload, 'hex');
var addr = new Address(version, buf);
assert.equal(addr.toString(), b58);
}
function test_decode_priv(b58, payload, isTestnet, isCompressed)
{
var network = isTestnet ? networks.testnet : networks.livenet;
var version = network.keySecret;
var network = isTestnet ? networks.testnet : networks.livenet;
var version = network.keySecret;
var buf_pl = new Buffer(payload, 'hex');
var buf;
if (isCompressed) {
buf = new Buffer(buf_pl.length + 1);
buf_pl.copy(buf);
buf[buf_pl.length] = 1;
} else
buf = buf_pl;
var buf_pl = new Buffer(payload, 'hex');
var buf;
if (isCompressed) {
buf = new Buffer(buf_pl.length + 1);
buf_pl.copy(buf);
buf[buf_pl.length] = 1;
} else
buf = buf_pl;
var privkey = new PrivateKey(b58);
assert.equal(version, privkey.version());
assert.equal(buf_pl.toString(), privkey.payload().toString());
var privkey = new PrivateKey(b58);
assert.equal(version, privkey.version());
assert.equal(buf_pl.toString(), privkey.payload().toString());
}
function test_decode_pub(b58, payload, isTestnet, addrType)
{
var isScript = (addrType == 'script');
var network = isTestnet ? networks.testnet : networks.livenet;
var version = isScript ? network.addressScript : network.addressPubkey;
var buf = new Buffer(payload, 'hex');
var addr = new Address(b58);
var isScript = (addrType == 'script');
var network = isTestnet ? networks.testnet : networks.livenet;
var version = isScript ? network.addressScript : network.addressPubkey;
var buf = new Buffer(payload, 'hex');
var addr = new Address(b58);
assert.equal(version, addr.version());
assert.equal(buf.toString(), addr.payload().toString());
assert.equal(version, addr.version());
assert.equal(buf.toString(), addr.payload().toString());
}
function is_valid(datum)
{
var b58 = datum[0];
var payload = datum[1];
var obj = datum[2];
var isPrivkey = obj['isPrivkey'];
var isTestnet = obj['isTestnet'];
var b58 = datum[0];
var payload = datum[1];
var obj = datum[2];
var isPrivkey = obj['isPrivkey'];
var isTestnet = obj['isTestnet'];
if (isPrivkey) {
var isCompressed = obj['isCompressed'];
test_encode_priv(b58, payload, isTestnet, isCompressed);
test_decode_priv(b58, payload, isTestnet, isCompressed);
} else {
var addrType = obj['addrType'];
test_encode_pub(b58, payload, isTestnet, addrType);
test_decode_pub(b58, payload, isTestnet, addrType);
}
if (isPrivkey) {
var isCompressed = obj['isCompressed'];
test_encode_priv(b58, payload, isTestnet, isCompressed);
test_decode_priv(b58, payload, isTestnet, isCompressed);
} else {
var addrType = obj['addrType'];
test_encode_pub(b58, payload, isTestnet, addrType);
test_decode_pub(b58, payload, isTestnet, addrType);
}
}
function is_invalid(datum)
{
if (datum.length < 1)
throw new Error("Bad test");
// ignore succeeding elements, as comments
var b58 = datum[0];
var privkey = new PrivateKey(b58);
var addr = new Address(b58);
if (datum.length < 1)
throw new Error("Bad test");
// ignore succeeding elements, as comments
var b58 = datum[0];
var privkey = new PrivateKey(b58);
var addr = new Address(b58);
var valid = true;
try {
privkey.validate();
addr.validate();
} catch(e) {
valid = false;
}
assert.equal(valid, false);
var valid = true;
try {
privkey.validate();
addr.validate();
} catch(e) {
valid = false;
}
assert.equal(valid, false);
}
var dataValid = JSON.parse(fs.readFileSync('test/base58_keys_valid.json'));

View File

@ -4,56 +4,56 @@ var crypto = require('crypto');
exports.readFileSync = function(enc_method, enc_passphrase, filename)
{
// read entire file into memory
var fileData = fs.readFileSync(filename, 'binary');
if (fileData.length < 32)
throw new Error("Crypted file " + filename + " truncated");
// read entire file into memory
var fileData = fs.readFileSync(filename, 'binary');
if (fileData.length < 32)
throw new Error("Crypted file " + filename + " truncated");
// separate into data, hmac parts
var fileCrypted = fileData.slice(0, -32);
var fileHmac = fileData.slice(-32);
// separate into data, hmac parts
var fileCrypted = fileData.slice(0, -32);
var fileHmac = fileData.slice(-32);
// generate and verify HMAC
var hmac = crypto.createHmac('sha256', enc_passphrase);
hmac.update(fileCrypted);
var digest = hmac.digest('binary');
// generate and verify HMAC
var hmac = crypto.createHmac('sha256', enc_passphrase);
hmac.update(fileCrypted);
var digest = hmac.digest('binary');
if (digest.toString() != fileHmac.toString())
throw new Error("Crypted file " + filename + " failed HMAC checksum verification");
if (digest.toString() != fileHmac.toString())
throw new Error("Crypted file " + filename + " failed HMAC checksum verification");
// decrypt to plaintext
var decipher = crypto.createDecipher(enc_method, enc_passphrase);
var dec = decipher.update(fileCrypted, 'binary', 'binary');
dec += decipher.final('binary');
return dec;
// decrypt to plaintext
var decipher = crypto.createDecipher(enc_method, enc_passphrase);
var dec = decipher.update(fileCrypted, 'binary', 'binary');
dec += decipher.final('binary');
return dec;
};
exports.readJFileSync = function(enc_method, enc_passphrase, filename)
{
var raw = this.readFileSync(enc_method, enc_passphrase, filename);
return JSON.parse(raw);
var raw = this.readFileSync(enc_method, enc_passphrase, filename);
return JSON.parse(raw);
};
exports.writeFileSync = function(enc_method, enc_passphrase, filename, data)
{
// encrypt to ciphertext
var cipher = crypto.createCipher(enc_method, enc_passphrase);
var crypted = cipher.update(data, 'binary', 'binary');
crypted += cipher.final('binary');
// encrypt to ciphertext
var cipher = crypto.createCipher(enc_method, enc_passphrase);
var crypted = cipher.update(data, 'binary', 'binary');
crypted += cipher.final('binary');
// compute HMAC
var hmac = crypto.createHmac('sha256', enc_passphrase);
hmac.update(crypted);
var digest = hmac.digest('binary');
// compute HMAC
var hmac = crypto.createHmac('sha256', enc_passphrase);
hmac.update(crypted);
var digest = hmac.digest('binary');
fs.writeFileSync(filename, crypted + digest, 'binary');
fs.writeFileSync(filename, crypted + digest, 'binary');
return true;
return true;
};
exports.writeJFileSync = function(enc_method, enc_passphrase, filename, obj)
{
var raw = JSON.stringify(obj);
return this.writeFileSync(enc_method, enc_passphrase, filename, raw);
var raw = JSON.stringify(obj);
return this.writeFileSync(enc_method, enc_passphrase, filename, raw);
};

View File

@ -2,6 +2,6 @@
// current time, in seconds
exports.curtime = function curtime()
{
return Math.round(Date.now() / 1000);
return Math.round(Date.now() / 1000);
}

View File

@ -113,42 +113,42 @@ var reWholeVal = /^\s*(\d+)/;
function padFrac(frac)
{
frac=frac.substr(0,8); //truncate to 8 decimal places
while (frac.length < 8)
frac = frac + '0';
return frac;
frac=frac.substr(0,8); //truncate to 8 decimal places
while (frac.length < 8)
frac = frac + '0';
return frac;
}
function parseFullValue(res)
{
return bignum(res[1]).mul('100000000').add(padFrac(res[2]));
return bignum(res[1]).mul('100000000').add(padFrac(res[2]));
}
function parseFracValue(res)
{
return bignum(padFrac(res[1]));
return bignum(padFrac(res[1]));
}
function parseWholeValue(res)
{
return bignum(res[1]).mul('100000000');
return bignum(res[1]).mul('100000000');
}
exports.parseValue = function parseValue(valueStr)
{
var res = valueStr.match(reFullVal);
if (res)
return parseFullValue(res);
var res = valueStr.match(reFullVal);
if (res)
return parseFullValue(res);
res = valueStr.match(reFracVal);
if (res)
return parseFracValue(res);
res = valueStr.match(reFracVal);
if (res)
return parseFracValue(res);
res = valueStr.match(reWholeVal);
if (res)
return parseWholeValue(res);
res = valueStr.match(reWholeVal);
if (res)
return parseWholeValue(res);
return undefined;
return undefined;
};
// Utility that synchronizes function calls based on a key