From 5cce4539d19d26662919296eb8f218ad51e64777 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Fri, 24 Jun 2016 10:15:34 -0700 Subject: [PATCH] bip114: mast. --- lib/bcoin/protocol/constants.js | 1 + lib/bcoin/script.js | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/lib/bcoin/protocol/constants.js b/lib/bcoin/protocol/constants.js index e6170dd2..1a5b5807 100644 --- a/lib/bcoin/protocol/constants.js +++ b/lib/bcoin/protocol/constants.js @@ -662,6 +662,7 @@ exports.flags = { VERIFY_CHECKSEQUENCEVERIFY: (1 << 10), VERIFY_WITNESS: (1 << 11), VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: (1 << 12), + VERIFY_MAST: (1 << 13), VERIFY_SEQUENCE: (1 << 0), MEDIAN_TIME_PAST: (1 << 1) }; diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 61b87a42..01d4d8c5 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -4077,6 +4077,7 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i) { var program = output.toProgram(); var stack = witness.toStack(); var witnessScript, redeem, j; + var hash, pathdata, depth, path, posdata, pos, depth, root; assert(program, 'verifyProgram called on non-witness-program.'); assert((flags & constants.flags.VERIFY_WITNESS) !== 0); @@ -4101,6 +4102,58 @@ Script.verifyProgram = function verifyProgram(witness, output, flags, tx, i) { // Failure on version=0 (bad program data length) throw new ScriptError('WITNESS_PROGRAM_WRONG_LENGTH'); } + } else if ((flags & constants.flags.VERIFY_MAST) && program.version === 1) { + if (program.data.length !== 32) + throw new ScriptError('WITNESS_PROGRAM_WRONG_LENGTH'); + + if (stack.length < 3) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); + + witnessScript = stack.pop(); + redeem = new Script(witnessScript); + + hash = utils.hash256(witnessScript); + pathdata = stack.pop(); + + if (pathdata.length & 0x1f) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); + + depth = pathdata.length >>> 5; + + if (depth > 32) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); + + path = []; + + for (j = 0; j < depth; j++) + path.push(pathdata.slice(j * 32, j * 32 + 32)); + + posdata = stack.pop(); + + if (posdata.length > 4) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); + + pos = 0; + if (posdata.length > 0) { + if (posdata[posdata.length - 1] === 0x00) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); + + for (j = 0; j < posdata.length; j++) + pos |= posdata[i] << 8 * j; + + if (pos < 0) + pos += 0x100000000; + } + + if (depth < 32) { + if (pos >= ((1 << depth) >>> 0)) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); + } + + root = utils.checkMerkleBranch(hash, path, pos); + + if (!utils.equal(root, program.data)) + throw new ScriptError('WITNESS_PROGRAM_MISMATCH'); } else { // Anyone can spend (we can return true here // if we want to always relay these transactions).