tx: wip sign/verify
This commit is contained in:
parent
471a78b0fa
commit
9fd54758a2
@ -70,3 +70,69 @@ script.encode = function encode(s) {
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
script.subscript = function subscript(s) {
|
||||
if (!s)
|
||||
return [];
|
||||
|
||||
var lastSep = -1;
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
if (s[i] === 'codesep')
|
||||
lastSep = i;
|
||||
else if (s[i] === 'checksig' ||
|
||||
s[i] === 'checksigverify' ||
|
||||
s[i] === 'checkmultisig' ||
|
||||
s[i] === 'checkmultisigverify') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var res = [];
|
||||
for (var i = lastSep + 1; i < s.length; i++)
|
||||
if (s[i] !== 'codesep')
|
||||
res.push(s[i]);
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
script.execute = function execute(s, stack, tx) {
|
||||
for (var i = 0; i < s.length; i++) {
|
||||
var o = s[i];
|
||||
if (Array.isArray(o)) {
|
||||
stack.push(o);
|
||||
} else if (o === 'dup') {
|
||||
if (stack.length === 0)
|
||||
return false;
|
||||
|
||||
stack.push(stack[stack.length - 1]);
|
||||
} else if (o === 'hash160') {
|
||||
if (stack.length === 0)
|
||||
return false;
|
||||
|
||||
stack.push(bcoin.utils.ripesha(stack.pop()));
|
||||
} else if (o === 'eqverify' || o === 'eq') {
|
||||
if (stack.length < 2)
|
||||
return false;
|
||||
|
||||
var res = bcoin.utils.isEqual(stack.pop(), stack.pop());
|
||||
stack.push([ res ? 1 : 0 ]);
|
||||
if (!res && o === 'eqverify')
|
||||
return false;
|
||||
} else if (o === 'checksigverify' || o === 'checksig') {
|
||||
if (!tx || stack.length < 2)
|
||||
return false;
|
||||
|
||||
var pub = stack.pop();
|
||||
var sig = stack.pop();
|
||||
var res = bcoin.ecdsa.verify(tx, sig, pub);
|
||||
stack.push([ res ? 1 : 0 ]);
|
||||
if (!res && o ==='checksigverify')
|
||||
return false;
|
||||
} else {
|
||||
// Unknown operation
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
var assert = require('assert');
|
||||
var bn = require('bn.js');
|
||||
|
||||
var bcoin = require('../bcoin');
|
||||
@ -53,7 +54,7 @@ TX.prototype.render = function render() {
|
||||
|
||||
TX.prototype.input = function input(i, index) {
|
||||
if (i instanceof TX)
|
||||
i = { tx: i, index: i };
|
||||
i = { tx: i, index: index };
|
||||
|
||||
var hash;
|
||||
if (i.tx)
|
||||
@ -106,10 +107,37 @@ TX.prototype.out = function out(output, value) {
|
||||
};
|
||||
|
||||
TX.prototype.getSubscript = function getSubscript(index) {
|
||||
var input = this.inputs[index];
|
||||
assert(input);
|
||||
var output = this.outputs[index];
|
||||
assert(output);
|
||||
|
||||
var script = input.script;
|
||||
|
||||
for (var i = 0; input.script.
|
||||
var script = output.script;
|
||||
return bcoin.script.subscript(script);
|
||||
};
|
||||
|
||||
TX.prototype.subscriptHash = function subscriptHash(index, s, type) {
|
||||
var copy = this.clone();
|
||||
|
||||
copy.inputs.forEach(function(input, i) {
|
||||
input.script = index === i ? s : [];
|
||||
});
|
||||
var verifyStr = copy.render();
|
||||
verifyStr = verifyStr.concat(bcoin.protocol.constants.hashType[type]);
|
||||
var hash = utils.dsha256(verifyStr);
|
||||
|
||||
return hash;
|
||||
};
|
||||
|
||||
TX.prototype.validate = function validate() {
|
||||
return this.inputs.every(function(input, i) {
|
||||
assert(input.out.tx);
|
||||
assert(input.out.tx.outputs.length > input.out.index);
|
||||
|
||||
var subscript = input.out.tx.getSubscript(input.out.index);
|
||||
var hash = this.subscriptHash(i, subscript, 'all');
|
||||
|
||||
var stack = [];
|
||||
bcoin.script.execute(input.script, stack);
|
||||
var prev = input.out.tx.outputs[input.out.index].script;
|
||||
return bcoin.script.execute(prev, stack, hash);
|
||||
}, this);
|
||||
};
|
||||
|
||||
@ -272,6 +272,17 @@ function testTarget(target, hash) {
|
||||
}
|
||||
utils.testTarget = testTarget;
|
||||
|
||||
utils.isEqual = function isEqual(a, b) {
|
||||
if (a.length !== b.length)
|
||||
return false;
|
||||
|
||||
for (var i = 0; i < a.length; i++)
|
||||
if (a[i] !== b[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
// TODO(indutny): use process.nextTick in node.js
|
||||
utils.nextTick = function nextTick(fn) {
|
||||
setTimeout(fn, 0);
|
||||
|
||||
@ -56,7 +56,7 @@ Wallet.prototype.own = function own(tx) {
|
||||
return output.script.length === 5 &&
|
||||
output.script[0] === 'dup' &&
|
||||
output.script[1] === 'hash160' &&
|
||||
utils.toHex(output.script[2]) === utils.toHex(this.getHash()) &&
|
||||
utils.isEqual(output.script[2], this.getHash()) &&
|
||||
output.script[3] === 'eqverify' &&
|
||||
output.script[4] === 'checksig';
|
||||
}, this);
|
||||
@ -75,17 +75,15 @@ Wallet.prototype.sign = function sign(tx, type) {
|
||||
|
||||
// Add signature script to each input
|
||||
inputs.forEach(function(input, i) {
|
||||
var copy = tx.clone();
|
||||
var s = input.out.tx.getSubscript(input.out.index);
|
||||
|
||||
copy.inputs.forEach(function(input, j) {
|
||||
input.script = i === j ? s : [];
|
||||
});
|
||||
var hash = tx.subscriptHash(i, s, type);
|
||||
var signature = bcoin.ecdsa.sign(hash, this.key).toDER();
|
||||
|
||||
var verifyStr = copy.render();
|
||||
verifyStr = verifyStr.concat(bcoin.protocol.constants.hashType[type]);
|
||||
var hash = utils.dsha256(verifyStr);
|
||||
var signature = this.key.sign(hash).toDER();
|
||||
input.script = [
|
||||
signature,
|
||||
pub
|
||||
];
|
||||
}, this);
|
||||
|
||||
return inputs.length;
|
||||
|
||||
@ -22,8 +22,8 @@
|
||||
"homepage": "https://github.com/indutny/bcoin",
|
||||
"dependencies": {
|
||||
"async": "^0.8.0",
|
||||
"bn.js": "^0.2.0",
|
||||
"elliptic": "^0.7.0",
|
||||
"bn.js": "^0.3.0",
|
||||
"elliptic": "^0.8.0",
|
||||
"hash.js": "^0.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -29,9 +29,10 @@ describe('Wallet', function() {
|
||||
assert(w.own(src));
|
||||
|
||||
var tx = bcoin.tx()
|
||||
.input(src, 1)
|
||||
.input(src, 0)
|
||||
.out(w.getAddress(), 5460);
|
||||
|
||||
w.sign(tx);
|
||||
assert(tx.validate());
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user