mirror of
https://github.com/bitcoin/bips.git
synced 2025-05-12 12:03:29 +00:00
Merge pull request #370 from jl2012/bip114ref
BIP114: Clarifying reference implementation
This commit is contained in:
commit
6026a0b599
@ -133,24 +133,33 @@ This BIP depends on [[bip-0141.mediawiki|BIP141]] and will be deployed by versio
|
|||||||
The idea of MAST originates from Russell O’Connor, Pieter Wuille, and [https://bitcointalk.org/index.php?topic=255145.msg2757327#msg2757327 Peter Todd].
|
The idea of MAST originates from Russell O’Connor, Pieter Wuille, and [https://bitcointalk.org/index.php?topic=255145.msg2757327#msg2757327 Peter Todd].
|
||||||
|
|
||||||
== Reference Implementation ==
|
== Reference Implementation ==
|
||||||
https://github.com/jl2012/bitcoin/commit/f335cab76eb95d4f7754a718df201216a4975d8c
|
https://github.com/jl2012/bitcoin/tree/segwit_mast
|
||||||
|
|
||||||
<source lang="cpp">
|
<source lang="cpp">
|
||||||
|
//New rules apply if version byte is 1 and witness program size is 32 bytes
|
||||||
if (witversion == 1) {
|
if (witversion == 1) {
|
||||||
if (program.size() == 32) {
|
if (program.size() == 32) {
|
||||||
|
|
||||||
|
//Witness stack must have at least 3 items
|
||||||
if (witness.stack.size() < 3)
|
if (witness.stack.size() < 3)
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
|
|
||||||
//Script: the last witness stack item
|
//Script is the last witness stack item
|
||||||
scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
|
scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end());
|
||||||
uint256 hashScriptPubKey;
|
uint256 hashScriptPubKey;
|
||||||
CHash256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
|
CHash256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin());
|
||||||
|
|
||||||
//Path: the second last witness stack item; size = 32N, 0 <= N < 33
|
//Path is the second last witness stack item
|
||||||
std::vector<unsigned char> pathdata = witness.stack.at(witness.stack.size() - 2);
|
std::vector<unsigned char> pathdata = witness.stack.at(witness.stack.size() - 2);
|
||||||
|
|
||||||
|
// Size of Path must be a multiple of 32 bytes (0 byte is allowed)
|
||||||
if (pathdata.size() & 0x1F)
|
if (pathdata.size() & 0x1F)
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
|
|
||||||
|
// Depth of the tree is size of Path divided by 32
|
||||||
unsigned int depth = pathdata.size() >> 5;
|
unsigned int depth = pathdata.size() >> 5;
|
||||||
|
|
||||||
|
// Maximum allowed depth is 32
|
||||||
if (depth > 32)
|
if (depth > 32)
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
std::vector<uint256> path;
|
std::vector<uint256> path;
|
||||||
@ -158,33 +167,62 @@ if (witversion == 1) {
|
|||||||
for (unsigned int i = 0; i < depth; i++)
|
for (unsigned int i = 0; i < depth; i++)
|
||||||
memcpy(path[i].begin(), &pathdata[32 * i], 32);
|
memcpy(path[i].begin(), &pathdata[32 * i], 32);
|
||||||
|
|
||||||
//Position: the third last witness stack item; unsigned int with smallest possible value and no leading zero
|
//Position is the third last witness stack item
|
||||||
std::vector<unsigned char> positiondata = witness.stack.at(witness.stack.size() - 3);
|
std::vector<unsigned char> positiondata = witness.stack.at(witness.stack.size() - 3);
|
||||||
|
|
||||||
|
//Position may have 4 bytes at most
|
||||||
if (positiondata.size() > 4)
|
if (positiondata.size() > 4)
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
|
|
||||||
uint32_t position = 0;
|
uint32_t position = 0;
|
||||||
|
|
||||||
|
//Position is an unsigned little-endian integer with no leading zero byte
|
||||||
if (positiondata.size() > 0) {
|
if (positiondata.size() > 0) {
|
||||||
if (positiondata.back() == 0x00)
|
if (positiondata.back() == 0x00)
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
for (size_t i = 0; i != positiondata.size(); ++i)
|
for (size_t i = 0; i != positiondata.size(); ++i)
|
||||||
position |= static_cast<uint32_t>(positiondata[i]) << 8 * i;
|
position |= static_cast<uint32_t>(positiondata[i]) << 8 * i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Position must not be larger than the maximum number of items allowed by the depth of tree
|
||||||
if (depth < 32) {
|
if (depth < 32) {
|
||||||
if (position >= (1U << depth))
|
if (position >= (1U << depth))
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Calculate the Merkle Root and compare with the witness program
|
||||||
uint256 root = ComputeMerkleRootFromBranch(hashScriptPubKey, path, position);
|
uint256 root = ComputeMerkleRootFromBranch(hashScriptPubKey, path, position);
|
||||||
if (memcmp(root.begin(), &program[0], 32))
|
if (memcmp(root.begin(), &program[0], 32))
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH);
|
||||||
|
|
||||||
|
//Remaining stack items used for evaluation
|
||||||
stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 3);
|
stack = std::vector<std::vector<unsigned char> >(witness.stack.begin(), witness.stack.end() - 3);
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
//Invalid if version byte is 1 but witness program size is not 32 bytes
|
||||||
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
|
return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_WRONG_LENGTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</source>
|
</source>
|
||||||
|
|
||||||
|
Copying from <code>src/consensus/merkle.cpp</code>:
|
||||||
|
<source lang="cpp">
|
||||||
|
uint256 ComputeMerkleRootFromBranch(const uint256& leaf, const std::vector<uint256>& vMerkleBranch, uint32_t nIndex) {
|
||||||
|
uint256 hash = leaf;
|
||||||
|
for (std::vector<uint256>::const_iterator it = vMerkleBranch.begin(); it != vMerkleBranch.end(); ++it) {
|
||||||
|
if (nIndex & 1) {
|
||||||
|
hash = Hash(BEGIN(*it), END(*it), BEGIN(hash), END(hash));
|
||||||
|
} else {
|
||||||
|
hash = Hash(BEGIN(hash), END(hash), BEGIN(*it), END(*it));
|
||||||
|
}
|
||||||
|
nIndex >>= 1;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
</source>
|
||||||
|
|
||||||
|
|
||||||
== References ==
|
== References ==
|
||||||
*[[bip-0141.mediawiki|BIP141 Segregated Witness (Consensus layer)]]
|
*[[bip-0141.mediawiki|BIP141 Segregated Witness (Consensus layer)]]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user