From e00a157306878c732a93bb2f2ea456701886858d Mon Sep 17 00:00:00 2001 From: Sandro Machado Date: Mon, 18 Jul 2016 00:37:10 +0100 Subject: [PATCH 01/14] Add Swift Library --- bip-0021.mediawiki | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bip-0021.mediawiki b/bip-0021.mediawiki index a3c2d4e..513b8bb 100644 --- a/bip-0021.mediawiki +++ b/bip-0021.mediawiki @@ -124,4 +124,5 @@ Characters must be URI encoded properly. === Libraries === * Javascript - https://github.com/bitcoinjs/bip21 -* [[BitcoinPaymentURI|https://github.com/SandroMachado/BitcoinPaymentURI]] Java library to process and generate Bitcoin payment URI's. +* Java - https://github.com/SandroMachado/BitcoinPaymentURI +* Swift - https://github.com/SandroMachado/BitcoinPaymentURISwift From 9da1f65e390ca18c1d63abea8c4a112a6c95049d Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Fri, 29 Jul 2016 00:59:06 +0800 Subject: [PATCH 02/14] BIP114: MAST proposal v2 --- bip-0114.mediawiki | 344 ++++++++++++++++++++++++++++----------- bip-0114/mastexample.png | Bin 0 -> 26798 bytes 2 files changed, 245 insertions(+), 99 deletions(-) create mode 100644 bip-0114/mastexample.png diff --git a/bip-0114.mediawiki b/bip-0114.mediawiki index aee8646..cb9aea7 100644 --- a/bip-0114.mediawiki +++ b/bip-0114.mediawiki @@ -24,71 +24,172 @@ The [[bip-0016.mediawiki|BIP16]] (Pay-to-script-hash, "P2SH") fixes the first 3 The [[bip-0141.mediawiki|BIP141]] defines 2 new types of scripts that support segregated witness. The pay-to-witness-script-hash (P2WSH) is similar to P2SH is many ways. By supplying the script in witness, P2WSH restores the original 10,000 byte script limit. However, it still requires publishing of unexecuted branches. ===Merkelized Abstract Syntax Tree=== -The idea of Merkelized Abstract Syntax Tree (MAST) is to use a Merkle tree to encode mutually exclusive branches in a script. When spending, the redeemer may provide only the branch they are executing, and hashes that connect the branch to the fixed size Merkel root. This reduces the size of redemption stack from O(n) to O(log n) (n as the number of mutually exclusive branches). This enables complicated redemption conditions that is currently not possible due to the script size and op code limit, improves privacy by hiding unexecuted branches, and allows inclusion of non-consensus enforced data with very low or no additional cost. +The idea of Merkelized Abstract Syntax Tree (MAST) is to use a Merkle tree to encode branches in a script. When spending, users may provide only the branches they are executing, and hashes that connect the branches to the fixed size Merkel root. This reduces the size of redemption stack from O(n) to O(log n) (n as the number of branches). This enables complicated redemption conditions that is currently not possible due to the script size and opcode limit, improves privacy by hiding unexecuted branches, and allows inclusion of non-consensus enforced data with very low or no additional cost. ==Specification== -In [[bip-0141.mediawiki|BIP141]], witness programs with a version byte of 1 or larger are considered to be anyone-can-spend scripts. The following new validation rules are applied if the witness program version byte is 1 and the program size is 32 bytes. The witness program is the MAST Root. +In [[bip-0141.mediawiki|BIP141]], witness programs with a version byte of 1 or larger are considered to be anyone-can-spend scripts. The following new validation rules are applied if the witness program version byte is 1 and the program size is 32 bytes.If the version byte is 1, but the witness program is not 32 bytes, no further interpretation of the witness program or witness stack happens. This is reserved for future extensions. The witness program is the MAST Root. -To redeem an output of this kind, the witness must consist of an input stack to feed to the script, followed by a Postion value, a serialized Merkle path (Path), and a serialized script (MAST Script). +To redeem an output of this kind, the witness must consist of the following items: -The Position, Path, and MAST Script are popped off the initial witness stack. -The double-SHA256 of the MAST Script (≤ TBD bytes) must be correctly connected to the MAST Root with the ComputeMerkleRootFromBranch function, with the specified Path and Position. + Script_stack_1 + Script_stack_2 + . + . + Script_stack_X (X ≥ 0) + Subscript_1 + Subscript_2 + . + . + Subscript_Y (1 ≤ Y ≤ 255) + Position + Path + Metadata (Y|MAST Version) -Path is the serialized Merkle path for the MAST Script. Size of Path must be a multiple of 32 bytes, and not more than 1024 bytes (which allows 32 levels). Each 32 byte word is a double-SHA256 merkle node in the merkle branch connecting to the MAST Root. If the size of Path is zero, the double-SHA256 of the MAST Script must match the MAST Root. -Position indicates the location of the MAST Script in the Merkle tree, with zero indicating the leftmost position. It is an unsigned little-endian integer with not more than 4 bytes. It must be encoded in the most parsimonious way possible, with no leading zero and not larger than the maximum number of items allowed by the depth of the tree (as implied by the size of Path). +Metadata is the last witness item. It is a vector of 1 to 5 bytes. The first byte is an unsigned integer between 1 to 255 denoting the number of Subscript (defined hereinafter). The following 0 to 4 byte(s) is an unsigned little-endian integer denoting the MAST version. MAST Version must be minimally encoded (the most significant byte must not be 0). -The MAST Script is then deserialized, and executed after normal script evaluation with the remaining witness stack (≤ TBD bytes for each stack item). The script must not fail, and result in exactly a single TRUE on the stack. +Path is the second last witness item. It is a serialized Merkle path of the Script Hash (defined hereinafter). Size of Path must be a multiple of 32 bytes, and not more than 1024 bytes. Each 32 byte word is a double-SHA256 merkle node in the merkle branch connecting to the Script Root (defined hereinafter). Depth of the tree (0 to 32) is the size of Path divided by 32. -Sigops in MAST program are counted to the block sigop limit in the same way as the version 0 witness program (see BIP141). +Position is the third last witness item. It indicates the location of the Script Hash in the Merkle tree, with zero indicating the leftmost position. It is an unsigned little-endian integer with not more than 4 bytes. It must be minimally encoded: the value must not be larger than the maximum number of items allowed by the Depth of the tree, and the most significant byte must not be 0. For example, if Depth is 4, the valid range of Position is 0 to 15 (24-1). -If the version byte is 1, but the witness program is not 32 bytes, the script must fail. +Depends on the first byte of Metadata, there should be 1 to 255 Subscript witness item(s) before Position. + +Script Hash is defined as: + + Script Hash = H(Y|H(Subscript_1)|H(Subscript_2)|...|H(Subscript_Y)) + H() = SHA256(SHA256()) + +where Y is a 1-byte value denoting number of Subscript, followed by the hash of each Subscript + +Script Root is the Merkle root calculated by the ComputeMerkleRootFromBranch function, using Script Hash, Path and Position. + +MAST Root is H(MAST Version|Script Root). The pre-image has a fixed size of 36 bytes: 4 bytes for MAST Version (unsigned little-endian integer) and 32 bytes for Script Root. + +The script evaluation fails if MAST Root does not match the witness program. + +If the MAST Root matches the witness program and MAST Version is greater than 0, the script returns a success without further evaluation. SigOpsCost is counted as 0. This is reserved for future script upgrades. + +If the MAST Version is 0, the Subscript(s) are serialized to form the final MAST Script, beginning with Subscript_1. The unused witness item(s) before the Subscript_1 are used as Input Stack to feed to the MASTScript. (Similar to P2WSH in BIP141) + +The script fails with one of the following conditions: +* MAST Script is malformed (i.e. not enough data provided for the last push operation). Individual Subscript might be malformed, as long as they are serialized into a valid MAST Script +* Size of MAST Script is larger than 10,000 bytes +* Size of any one of the Input Stack item is larger than 520 bytes +* Number of non-push operations (nOpCount) is more than 201. nOpCount is the sum of the number of non-push operations in MAST Script (counted in the same way as P2WSH witnessScript), number of Subscript (Y), and Depth of the Merkle tree. + +The MAST Script is then evaluated with the Input Stack (with some new or redefined opcodes described in BIPXXX). The evaluation must not fail, and result in an exactly empty stack. + +Counting of SigOpsCost is based on the MAST Script, described in BIPYYY. + +== Rationale == +=== MAST Structure === +This proposal is a restricted case of more general MAST. In a general MAST design, users may freely assign one or more script branches for execution. In this proposal, only one branch is allowed for execution, and users are required to transform a complicated condition into several mutually exclusive branches. For example, if the desired redeem condition is: + + (A or B) and (C or D or E) and (F or G) + +In a general MAST design, the 7 branches (A to G) will form a 3-level Merkle tree, plus an "overall condition" describing the relationship of different branches. In redemption, the "overall condition", executed branches (e.g. B, D, F), and Merkle path data will be provided for validation. + +In the current proposal, the user has to transform the redeem condition into 12 mutually exclusive branches and form a 4-level Merkle tree, and present only one branch in redemption: + + + A and C and F + B and C and F + A and D and F + . + . + B and E and G + +One way to implement the general MAST design is using a combination of OP_EVAL, OP_CAT, and OP_HASH256. However, that will suffer from the problems of OP_EVAL, including risks of indefinite program loop and inability to do static program analysis. A complicated implementation is required to fix these problems and is difficult to review. + +The advantages of the current proposal are: +* Subscript are located at a fixed position in the witness stack. This allows static program analysis, such as static SigOpsCost counting and early termination of scripts with disabled opcodes. +* If different parties in a contract do not want to expose their scripts to each other, they may provide only H(Subscript) and keep the Subscript private until redemption. +* If they are willing to share the actual scripts, they may combine them into one Subscript for each branch, saving some nOpCount and a few bytes of witness space. + +The are some disadvantages, but only when the redemption condition is very complicated: +* It may require more branches than a general MAST design (as shown in the previous example) and take more witness space in redemption +* Creation and storage of the MAST structure may take more time and space. However, such additional costs affect only the related parties in the contract but not any other Bitcoin users. + +=== MAST Version === +This proposal allows users to indicate the version of scripting language in the witness, which is cheaper than doing that in scriptPubKey or scriptSig. Undefined versions remain anyone-can-spend and are reserved for future expansions. A new version could be used for relaxing constraints (e.g. the 10,000 bytes size limit of MAST Script), adding or redefining opcodes, or even introducing a completely novel scripting system. + +=== nOpCount limit === +In version 0 MAST, the extra hashing operations in calculating the MAST Root are counted towards the 201 nOpCount limit to prevent abusive use. This limitation is not applied to undefined MAST Version for flexibility, but it is constrained by the 255 Subscript and 32 Depth limits. + +=== Script evaluation === +This proposal requires script evaluation resulting in an empty stack, instead of a single TRUE value as in P2WSH. This allows each party in a contract to provide its own Subscript, and demonstrate the required Input Stack to clean up its own Subscript. In this case, order of the Subscript is not important since the overall objective is to clean up the stack after evaluation. == Examples == === Calculation of MAST Root === -To calculate the MAST Root for 4 branches, the double-SHA256 of each branch is first calculated: - <1> EQUAL (0x5187), HASH256=3b647cb856a965fa6feffb4621eb2a4f4c2453693b2f64e021383ccbd80a1abb - <2> EQUAL (0x5287), HASH256=37772654bdce9b3d59e1169ea16ddbaa8a2ae8ee265db64863d0b76f02c882fa - <3> EQUAL (0x5387), HASH256=2e972642436151cd96e4b0868077b6362ffb5eb30b420a6f1c5e1c6fff02bc33 - <4> EQUAL (0x5487), HASH256=4c954fc1e635ce8417341465f85b59d700806f6e57bb96b2a25bec5ca3f9f154 -Serialize the hashes of the first pair and calculate the hash. Same for the other pair: - HASH256(HASH256(5187)|HASH256(5287)) = 64fbdfc0a82ecc3b33434bfea63440e9a5275fa5e533200d2eaf18281e8b28b6 - HASH256(HASH256(5387)|HASH256(5487)) = aeadea837d5e640a1444208f7aca3be63bc8ab3c6b28a19878a00cc9c631ac31 + + + + Subscript: + SA = 1 EQUALVERIFY (0x5188) + SB = 2 EQUALVERIFY (0x5288) + SC = 3 EQUALVERIFY (0x5388) + SD = 4 EQUALVERIFY (0x5488) + SE = 5 EQUALVERIFY (0x5588) + SF = 6 EQUALVERIFY (0x5688) + SG = 7 EQUALVERIFY (0x5788) + SH = 8 EQUALVERIFY (0x5888) + M = RETURN "Hello" (0x6a0548656c6c6f) + Hash: + HA = H(0x01|H(SA)) = H(0x015acb54166e0db370cd1b05a29120373568dacea2abc3748459ec3da2106e4b4e) = 0xd385d7268ad7e1ec51660f833d54787d2d8d79b6b1809d9c1d06c9e71f7be204 + HB = H(0x02|H(SB)|H(SC)) = 0x7cbfa08e44ea9f4f996873be95d9bffd97d4b91a5af32cc5f64efb8461727cdd + HF = H(0x03|H(SD)|H(SE)|H(SF)) = 0x4611414355945a7c2fcc62a53a0004821b87e68f93048ffba7a55a3cb1e9783b + HG = H(0x01|H(SG)) = 0xaa5fbdf58264650eadec33691ba1e7606d0a62f570eea348a465c55bc86ffc10 + HC = H(0x01|H(M)) = 0x70426d480d5b28d93c5be54803681f99abf4e8df4eab4dc87aaa543f0d138159 + HD = H(0x0x|H(SH)) = 0x8482f6c9c3fe90dd4d533b4efedb6a241b95ec9267d1bd5aaaee36d2ce2dd6da + HE = H(HA|HB) = 0x049b9f2f94f0a9bdea624e39cd7d6b27a365c6a0545bf0e9d88d86eff4894210 + HH = H(HC|HD) = 0xc709fdc632f370f3367da45378d1cf430c5fda6805e731ad5761c213cf2d276e + HI = H(HE|HF) = 0xead5e1a1e7e41b77b794f091df9be3f0e9f41d47304eb43dece90688f69843b7 + HJ = H(HG|HH) = 0xd00fc690c4700d0f983f9700740066531ea826b21a4cbc62f80317261723d477 + Script Root = H(HI|HJ) = 0x26d5235d20daf1440a15a248f5b5b4f201392128072c55afa64a26ccc6f56bd9 + MAST Root = H(MAST Version|Script Root) = H(0x0000000026d5235d20daf1440a15a248f5b5b4f201392128072c55afa64a26ccc6f56bd9) = 0xb4b706e0c02eab9aba58419eb7ea2a286fb1c01d7406105fc12742bf8a3f97c9 -Serialize the 2 hashes from the previous step and calculate the hash, which is the MAST Root: - MAST Root = 6746003b5c9d342b2c210d406802c351e7eb5943412dcfc4718be625a8a59c0e The scriptPubKey with native witness program is: - <1> <0x6746003b5c9d342b2c210d406802c351e7eb5943412dcfc4718be625a8a59c0e> - (0x51206746003b5c9d342b2c210d406802c351e7eb5943412dcfc4718be625a8a59c0e) -To redeem with the <4> EQUAL branch, the witness is - 04 (Stack for evaluation) - 03 (Position) - 2e972642436151cd96e4b0868077b6362ffb5eb30b420a6f1c5e1c6fff02bc3364fbdfc0a82ecc3b33434bfea63440e9a5275fa5e533200d2eaf18281e8b28b6 (Path) - 5487 (MAST Script) + 1 <0xb4b706e0c02eab9aba58419eb7ea2a286fb1c01d7406105fc12742bf8a3f97c9> + (0x5120b4b706e0c02eab9aba58419eb7ea2a286fb1c01d7406105fc12742bf8a3f97c9) + + +To redeem with the SD|SE|SF branch, the witness is + + Script_stack_1: 0x06 + Script_stack_2: 0x05 + Script_stack_3: 0x04 + Subscript_1: 0x5488 + Subscript_2: 0x5588 + Subscript_3: 0x5688 + Position: 0x01 (HF is the second hash in its level) + Path (HE|HJ): 0x049b9f2f94f0a9bdea624e39cd7d6b27a365c6a0545bf0e9d88d86eff4894210d00fc690c4700d0f983f9700740066531ea826b21a4cbc62f80317261723d477 + Metadata: 0x03 (3 Subscript) + + === Imbalance MAST === -When constructing a MAST, if the user believes that some of the branches are more likely to be executed, they may put them closer to the MAST Root. It will save some witness space when the preferred branches are actually executed. +When constructing a MAST, if the user believes that some of the branches are more likely to be executed, they may put them closer to the Script Root. It will save some witness space when the preferred branches are actually executed. === Escrow with Timeout === The following is the "Escrow with Timeout" example in [[bip-0112.mediawiki|BIP112]]: IF - 2 3 CHECKMULTISIGVERIFY + 2 3 CHECKMULTISIG ELSE "30d" CHECKSEQUENCEVERIFY DROP - CHECKSIGVERIFY + CHECKSIG ENDIF Using compressed public key, the size of this script is 150 bytes. -With MAST, this script could be broken down into 2 mutually exclusive branches: +With MAST, this script could be broken down into 2 mutually exclusive branches:In BIPXXX, it is proposed that CHECKLOCKTIMEVERIFY and CHECKSEQUENCEVERIFY will pop the top stack item 2 3 CHECKMULTISIGVERIFY (105 bytes) - "30d" CHECKSEQUENCEVERIFY DROP CHECKSIGVERIFY (42 bytes) + "30d" CHECKSEQUENCEVERIFY CHECKSIGVERIFY (42 bytes) -With 2 branches, the Path will be 32 bytes (as the hash of the unexecuted branch), and the Position will be 1 byte as either 0 or 1. Since only one branch will be published, it is more difficult for a blockchain analyst to determine the details of the escrow. +Since only one branch will be published, it is more difficult for a blockchain analyst to determine the details of the escrow. === Hashed Time-Lock Contract === The following is the "Hashed TIme-Lock Contract" example in [[bip-0112.mediawiki|BIP112]]: @@ -107,16 +208,16 @@ The following is the "Hashed TIme-Lock Contract" example in [[bip-0112.mediawiki CHECKSIG To create a MAST Root, it is flattened to 3 mutually exclusive branches: - HASH160 EQUALVERIFY "24h" CHECKSEQUENCEVERIFY DROP CHECKSIG - HASH160 EQUALVERIFY CHECKSIG - "Timestamp" CHECKLOCKTIMEVERIFY DROP CHECKSIG + HASH160 EQUALVERIFY "24h" CHECKSEQUENCEVERIFY CHECKSIGVERIFY + HASH160 EQUALVERIFY CHECKSIGVERIFY + "Timestamp" CHECKLOCKTIMEVERIFY CHECKSIGVERIFY which significantly improves readability and reduces the witness size when it is redeemed. === Large multi-signature constructs === -The current CHECKMULTISIG supports up to 20 public keys. Although it is possible to extend it beyond 20 keys by using multiple CHECKSIGs and IF/ELSE conditions, the construction could be very complicated and soon use up the 10,000 bytes and 201 op codes limit. +The current CHECKMULTISIG supports up to 20 public keys. Although it is possible to extend it beyond 20 keys by using multiple CHECKSIGs and IF/ELSE conditions, the construction could be very complicated and soon use up the 10,000 bytes and 201 nOpCount limit. -With MAST, large and complex multi-signature constructs could be flattened to many simple CHECKMULTISIG conditions. For example, a 3-of-2000 multi-signature scheme could be expressed as 1,331,334,000 3-of-3 CHECKMULTISIGs, which forms a 31-level MAST. The scriptPubKey still maintains a fixed size of 34 bytes, and the redemption witness will be very compact, with less than 1,500 bytes. +With MAST, large and complex multi-signature constructs could be flattened to many simple CHECKMULTISIGVERIFY conditions. For example, a 3-of-2000 multi-signature scheme could be expressed as 1,331,334,000 3-of-3 CHECKMULTISIGVERIFY, which forms a 31-level MAST. The scriptPubKey still maintains a fixed size of 34 bytes, and the redemption witness will be very compact, with less than 1,500 bytes. === Commitment of non-consensus enforced data === Currently, committing non-consensus enforced data in the scriptPubKey requires the use of OP_RETURN which occupies additional block space. With MAST, users may commit such data as a branch. Depends on the number of executable branches, inclusion of such a commitment may incur no extra witness space, or 32 bytes at most. @@ -133,76 +234,121 @@ 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]. == Reference Implementation == -https://github.com/jl2012/bitcoin/tree/segwit_mast +https://github.com/jl2012/bitcoin/tree/bip114v2 (WIP) //New rules apply if version byte is 1 and witness program size is 32 bytes -if (witversion == 1) { - if (program.size() == 32) { - - //Witness stack must have at least 3 items - if (witness.stack.size() < 3) - return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); - - //Script is the last witness stack item - scriptPubKey = CScript(witness.stack.back().begin(), witness.stack.back().end()); - uint256 hashScriptPubKey; - CHash256().Write(&scriptPubKey[0], scriptPubKey.size()).Finalize(hashScriptPubKey.begin()); - - //Path is the second last witness stack item - std::vector 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) - 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; - - // Maximum allowed depth is 32 - if (depth > 32) - return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); - std::vector path; - path.resize(depth); - for (unsigned int i = 0; i < depth; i++) - memcpy(path[i].begin(), &pathdata[32 * i], 32); - - //Position is the third last witness stack item - std::vector positiondata = witness.stack.at(witness.stack.size() - 3); - - //Position may have 4 bytes at most - if (positiondata.size() > 4) - return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); - - uint32_t position = 0; - - //Position is an unsigned little-endian integer with no leading zero byte - if (positiondata.size() > 0) { - if (positiondata.back() == 0x00) - return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); - for (size_t i = 0; i != positiondata.size(); ++i) - position |= static_cast(positiondata[i]) << 8 * i; - } +if (witversion == 1 && program.size() == 32 && (flags & SCRIPT_VERIFY_MAST)) { + CHashWriter sRoot(SER_GETHASH, 0); + CHashWriter sScriptHash(SER_GETHASH, 0); + uint32_t nMASTVersion = 0; + size_t stacksize = witness.stack.size(); + if (stacksize < 4) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + std::vector metadata = witness.stack.back(); // The last witness stack item is metadata + if (metadata.size() < 1 || metadata.size() > 5) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + + // The first byte of metadata is the number of subscripts (1 to 255) + uint32_t nSubscript = static_cast(metadata[0]); + if (nSubscript == 0 || stacksize < nSubscript + 3) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + int nOpCount = nSubscript; // Each condition consumes a nOpCount + sScriptHash << metadata[0]; + + // The rest of metadata is MAST version in minimally-coded unsigned little endian int + if (metadata.back() == 0) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + if (metadata.size() > 1) { + for (size_t i = 1; i != metadata.size(); ++i) + nMASTVersion |= static_cast(metadata[i]) << 8 * (i - 1); + } - //Position must not be larger than the maximum number of items allowed by the depth of tree - if (depth < 32) { - if (position >= (1U << depth)) - return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); - } + // Unknown MAST version is non-standard + if (nMASTVersion > 0 && flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) + return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM); + + sRoot << nMASTVersion; + + // The second last witness stack item is the pathdata + // Size of pathdata must be divisible by 32 (0 is allowed) + // Depth of the Merkle tree is implied by the size of pathdata, and must not be greater than 32 + std::vector pathdata = witness.stack.at(stacksize - 2); + if (pathdata.size() & 0x1F) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + unsigned int depth = pathdata.size() >> 5; + if (depth > 32) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + + // Each level of Merkle tree consumes a nOpCount + // Evaluation of version 0 MAST terminates early if there are too many nOpCount + // Not enforced in unknown MAST version for upgrade flexibility + nOpCount = nOpCount + depth; + if (nMASTVersion == 0 && nOpCount > MAX_OPS_PER_SCRIPT) + return set_error(serror, SCRIPT_ERR_OP_COUNT); + + // path is a vector of 32-byte hashes + std::vector path; + path.resize(depth); + for (unsigned int j = 0; j < depth; j++) + memcpy(path[j].begin(), &pathdata[32 * j], 32); + + // The third last witness stack item is the positiondata + // Position is in minimally-coded unsigned little endian int + std::vector positiondata = witness.stack.at(stacksize - 3); + if (positiondata.size() > 4) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + uint32_t position = 0; + if (positiondata.size() > 0) { + if (positiondata.back() == 0) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + for (size_t k = 0; k != positiondata.size(); ++k) + position |= static_cast(positiondata[k]) << 8 * k; + } - //Calculate the Merkle Root and compare with the witness program - uint256 root = ComputeMerkleRootFromBranch(hashScriptPubKey, path, position); - if (memcmp(root.begin(), &program[0], 32)) - return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); + // Position value must not exceed the number of leaves at the depth + if (depth < 32) { + if (position >= (1U << depth)) + return set_error(serror, SCRIPT_ERR_INVALID_MAST_STACK); + } - //Remaining stack items used for evaluation - stack = std::vector >(witness.stack.begin(), witness.stack.end() - 3); + // Sub-scripts are located before positiondata + for (size_t i = stacksize - nSubscript - 3; i <= stacksize - 4; i++) { + CScript subscript(witness.stack.at(i).begin(), witness.stack.at(i).end()); + + // Evaluation of version 0 MAST terminates early if script is oversize + // Not enforced in unknown MAST version for upgrade flexibility + if (nMASTVersion == 0 && (scriptPubKey.size() + subscript.size()) > MAX_SCRIPT_SIZE) + return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE); + uint256 hashSubScript; + CHash256().Write(&subscript[0], subscript.size()).Finalize(hashSubScript.begin()); + sScriptHash << hashSubScript; + scriptPubKey = scriptPubKey + subscript; // Final scriptPubKey is a serialization of subscripts } + uint256 hashScript = sScriptHash.GetHash(); + + // Calculate MAST Root and compare against witness program + uint256 rootScript = ComputeMerkleRootFromBranch(hashScript, path, position); + sRoot << rootScript; + uint256 rootMAST = sRoot.GetHash(); + if (memcmp(rootMAST.begin(), &program[0], 32)) + return set_error(serror, SCRIPT_ERR_WITNESS_PROGRAM_MISMATCH); + + if (nMASTVersion == 0) { + stack = std::vector >(witness.stack.begin(), witness.stack.end() - 3 - nSubscript); + for (unsigned int i = 0; i < stack.size(); i++) { + if (stack.at(i).size() > MAX_SCRIPT_ELEMENT_SIZE) + return set_error(serror, SCRIPT_ERR_PUSH_SIZE); + } - 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); + // Script evaluation must not fail, and return an empty stack + if (!EvalScript(stack, scriptPubKey, flags, checker, SIGVERSION_WITNESS_V1, nOpCount, serror)) + return false; + if (stack.size() != 0) + return set_error(serror, SCRIPT_ERR_EVAL_FALSE); } + + return set_success(serror); } diff --git a/bip-0114/mastexample.png b/bip-0114/mastexample.png new file mode 100644 index 0000000000000000000000000000000000000000..9bff7b9939d7b8b98f0b01a987e8e397c2f5a7ed GIT binary patch literal 26798 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 S=$MCteW)pGD^)32z5hSC17(*0 literal 0 HcmV?d00001 From 0c8256f764b895ffe2029e95a7e0166e6b544b32 Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sun, 7 Aug 2016 22:21:06 +0200 Subject: [PATCH 03/14] [bip151] fix typo in HKDF key --- bip-0151.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0151.mediawiki b/bip-0151.mediawiki index a4c8b8e..11f9614 100644 --- a/bip-0151.mediawiki +++ b/bip-0151.mediawiki @@ -39,7 +39,7 @@ Encryption initialization must happen before sending any other messages to the r The symmetric encryption cipher keys will be calculated with ECDH/HKDF by sharing the pubkeys of a ephemeral key. Once the ECDH secret is calculated on each side, the symmetric encryption cipher keys must be derived with HKDF [2] after the following specification: 1. HKDF extraction -PRK = HKDF_EXTRACT(hash=SHA256, salt="bitcoinechd", ikm=ecdh_secret|cipher-type). +PRK = HKDF_EXTRACT(hash=SHA256, salt="bitcoinecdh", ikm=ecdh_secret|cipher-type). 2. Derive Key1 K_1 = HKDF_EXPAND(prk=PRK, hash=SHA256, info="BitcoinK1", L=32) From 55163e45460d8aab14950724fe7e1b4260dbbada Mon Sep 17 00:00:00 2001 From: Jonas Schnelli Date: Sun, 7 Aug 2016 22:24:37 +0200 Subject: [PATCH 04/14] [bip151] slightly increase robustness of the re-keying --- bip-0151.mediawiki | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bip-0151.mediawiki b/bip-0151.mediawiki index 11f9614..cf221f2 100644 --- a/bip-0151.mediawiki +++ b/bip-0151.mediawiki @@ -148,7 +148,7 @@ If more data is present, another message must be deserialized. There is no expli A responding peer can inform the requesting peer over a re-keying with a encack message containing 33byte of zeros to indicate that all encrypted message following after this encack message will be encrypted with ''the next symmetric cipher key''. -The new symmetric cipher key will be calculated by SHA256(SHA256(old_symetric_cipher_key)). +The new symmetric cipher key will be calculated by SHA256(SHA256(session_id || old_symmetric_cipher_key)). Re-Keying interval is a peer policy with a minimum timespan of 10 seconds. From 93ef85891196b31c12d5772d8741d1f672aade46 Mon Sep 17 00:00:00 2001 From: Sreekanth G S Date: Wed, 10 Aug 2016 22:08:22 +0530 Subject: [PATCH 05/14] Adding ruby implementation to Other implementation --- bip-0039.mediawiki | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bip-0039.mediawiki b/bip-0039.mediawiki index 0d05d81..6fd8bd0 100644 --- a/bip-0039.mediawiki +++ b/bip-0039.mediawiki @@ -146,3 +146,6 @@ Haskell: JavaScript: * https://github.com/bitpay/bitcore-mnemonic * https://github.com/bitcoinjs/bip39 (used by [[https://github.com/blockchain/My-Wallet-V3/blob/v3.8.0/src/hd-wallet.js#L121-L146|blockchain.info]]) + +Ruby: +* https://github.com/sreekanthgs/bip_mnemonic From b004187f14ef3fadd0851e1f3296e8ebac6109bd Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Tue, 16 Aug 2016 17:26:08 +0800 Subject: [PATCH 06/14] Add new BIP: Low S values signatures --- bip-lows.mediawiki | 60 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 bip-lows.mediawiki diff --git a/bip-lows.mediawiki b/bip-lows.mediawiki new file mode 100644 index 0000000..1b5a950 --- /dev/null +++ b/bip-lows.mediawiki @@ -0,0 +1,60 @@ +
+  BIP: ?
+  Title: Low S values signatures
+  Author: Pieter Wuille 
+          Johnson Lau 
+  Status: Draft
+  Type: Standards Track
+  Created: 2016-08-16
+
+ +==Abstract== + +This document specifies proposed changes to the Bitcoin transaction validity rules to restrict signatures to using low S values. + + +==Motivation== + +ECDSA signatures are inherently malleable as taking the negative of the number S inside (modulo the curve order) does not invalidate it. This is a nuisance malleability vector as any relay node on the network may transform the signature, with no access to the relevant private keys required. For non-segregated witness transactions, this malleability will change the txid and invalidate any unconfirmed child transactions. Although the txid of segregated witness ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) transactions is not third party malleable, this malleability vector will change the wtxid and may reduce the efficiency of compact block relay ([https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki BIP152]). + +To fix this malleability, we require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially restricting this value to its lower half range). The value S in signatures must be between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive). If S is too high, simply replace it by S' = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S. + + +==Specification== + +Every signature passed to OP_CHECKSIGIncluding pay-to-witness-public-key-hash (P2WPKH) described in BIP141, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, or OP_CHECKMULTISIGVERIFY, to which ECDSA verification is applied, MUST use a S value between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive) with strict DER encoding (see [https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66]). + +These operators all perform ECDSA verifications on pubkey/signature pairs, iterating from the top of the stack backwards. For each such verification, if the signature does not pass the Low S value check, the entire script evaluates to false immediately. If the signature is valid DER with low S value, but does not pass ECDSA verification, opcode execution continues as it used to, causing opcode execution to stop and push false on the stack (but not immediately fail the script) in some cases, which potentially skips further signatures (and thus does not subject them to Low S value check). + + +==Deployment== + +This BIP will be deployed by "version bits" [https://github.com/bitcoin/bips/blob/master/bip-0009.mediawiki BIP9] using the same parameters for BIP141 and BIP143, with the name "segwit" and using bit 1. + +For Bitcoin mainnet, the BIP9 starttime will be midnight TBD UTC (Epoch timestamp TBD) and BIP9 timeout will be midnight TBD UTC (Epoch timestamp TBD). + +For Bitcoin testnet, the BIP9 starttime will be midnight 1 May 2016 UTC (Epoch timestamp 1462060800) and BIP9 timeout will be midnight 1 May 2017 UTC (Epoch timestamp 1493596800). + + +==Compatibility== + +The reference client has produced compatible signatures since v0.9.0, and the requirement to have low S value signatures has been enforced as a relay policy by the reference client since v0.11.1. As of August 2016, very few transactions violating the requirement are being added to the chain. In addition, every non-compliant signature can trivially be converted into a compliant one, so there is no loss of functionality by this requirement. This proposal has the added benefit of reducing transaction malleability. + + +==Implementation== + +An implementation for the reference client is available at https://github.com/bitcoin/bitcoin/pull/8514 + + +==Footnotes== + + + +==Acknowledgements== + +This document is extracted from the previous [https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki BIP62] proposal which had input from various people. + + +==Copyright== + +This document is placed in the public domain. \ No newline at end of file From 55ea8052120c3e06993dd75b9f38d71d36565764 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 16 Aug 2016 19:43:53 +0000 Subject: [PATCH 07/14] Assign BIP 146: Low S values signatures --- README.mediawiki | 6 ++++++ bip-lows.mediawiki => bip-0146.mediawiki | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) rename bip-lows.mediawiki => bip-0146.mediawiki (98%) diff --git a/README.mediawiki b/README.mediawiki index 239294f..e01d878 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -512,6 +512,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Standard | Draft |- +| [[bip-0146.mediawiki|146]] +| Low S values signatures +| Pieter Wuille, Johnson Lau +| Standard +| Draft +|- | [[bip-0151.mediawiki|151]] | Peer-to-Peer Communication Encryption | Jonas Schnelli diff --git a/bip-lows.mediawiki b/bip-0146.mediawiki similarity index 98% rename from bip-lows.mediawiki rename to bip-0146.mediawiki index 1b5a950..f57aa21 100644 --- a/bip-lows.mediawiki +++ b/bip-0146.mediawiki @@ -1,5 +1,5 @@
-  BIP: ?
+  BIP: 146
   Title: Low S values signatures
   Author: Pieter Wuille 
           Johnson Lau 
@@ -57,4 +57,4 @@ This document is extracted from the previous [https://github.com/bitcoin/bips/bl
 
 ==Copyright==
 
-This document is placed in the public domain.
\ No newline at end of file
+This document is placed in the public domain.

From 5e49486769ec7dddb4689bdf270e587a91d74c0c Mon Sep 17 00:00:00 2001
From: Jonas Schnelli 
Date: Wed, 18 May 2016 09:19:24 +0200
Subject: [PATCH 08/14] Add BIP150 (Peer Authentication)

---
 README.mediawiki   |   6 ++
 bip-0150.mediawiki | 173 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 179 insertions(+)
 create mode 100644 bip-0150.mediawiki

diff --git a/README.mediawiki b/README.mediawiki
index e01d878..26c65f0 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -518,6 +518,12 @@ Those proposing changes should consider that ultimately consent may rest with th
 | Standard
 | Draft
 |-
+| [[bip-0150.mediawiki|150]]
+| Peer Authentication
+| Jonas Schnelli
+| Standard
+| Draft
+|-
 | [[bip-0151.mediawiki|151]]
 | Peer-to-Peer Communication Encryption
 | Jonas Schnelli
diff --git a/bip-0150.mediawiki b/bip-0150.mediawiki
new file mode 100644
index 0000000..1383ee9
--- /dev/null
+++ b/bip-0150.mediawiki
@@ -0,0 +1,173 @@
+
+  BIP: 150
+  Title: Peer Authentication
+  Author: Jonas Schnelli 
+  Status: Draft
+  Type: Standards Track
+  Created: 2016-03-23
+
+ +== Abstract == + +This BIP describes a way how peers can authenticate – without opening fingerprinting possibilities – to other peers to guarantee ownership and/or allowing to access additional or limited services. + +== Motivation == + +We assume peer operators want to limit the access of different services or increase datastream priorities to a selective subset of peers. Also we assume peers want to connect to specific peers to broadcast or filter transactions (or similar action that reveals sensitive informations) and therefore they want to authenticate the remote peer and make sure that they have not connected to a MITM. + +Benefits with peer authentication: +* Peers could detect MITM attacks when connecting to known peers +* Peers could allow resource hungry transaction filtering only to specific peers +* Peers could allow access to sensitive information that can lead to node fingerprinting (fee estimation) +* Peers could allow custom message types (private extensions) to authenticated peers + +A simple authentication scheme based on elliptic cryptography will allow peers to identify each other and selective allow access to restricted services or reject the connection if the identity could not be verified. + +== Specification == + +The authentication scheme proposed in this BIP uses ECDSA, '''secrets will never be transmitted'''. + +'''Authentication initialization must only happen if encrypted channels have been established (according to BIP-151 [1]).''' + +The '''encryption-session-ID''' is available once channels are encrypted (according to BIP-151 [1]). + +The identity-public-keys used for the authentication must be pre-shared over a different channel (Mail/PGP, physical paper exchange, etc.). This BIP does not cover a "trust on first use" (TOFU) concept. + +The authentication state must be kept until the encryption/connection terminates. + +Only one authentication process is allowed per connection. Re-authenticate require re-establishing the connection. + +=== Known-peers and authorized-peers database === +Each peer that supports p2p authentication must provide two users editable "databases" + +# '''known-peers''' contains known identity-public-keys together with a network identifier (IP & port), similar to the "known-host" file supported by openssh. +# '''authorized-peers''' contains authorized identity-public-keys + +=== Local identity key management === +Each peer can configure multiple identity-keys (ECC, 32 bytes). Peers should make sure, each network interface (IPv4, IPv6, tor) has its own identity-key (otherwise it would be possible to link a tor address to a IPvX address). +The identity-public-key(s) can be shared over a different channel with other node-operators (or non-validating clients) to grant authorized access. + +=== Authentication procedure === +Authentication after this BIP will require both sides to authenticate. Signatures/public-keys will only be revealed if the remote peer could prove that they already know the remote identity-public-key. + +# -> Requesting peer sends AUTHCHALLENGE (hash) +# <- Responding peer sends AUTHREPLY (signature) +# -> Requesting peer sends AUTHPROPOSE (hash) +# <- Responding peer sends AUTHCHALLENGE (hash) +# -> Requesting peer sends AUTHREPLY (signature) + +For privacy reasons, dropping the connection or aborting during the authentication process must not be possible. + +=== AUTHCHALLENGE message === +A peer can send an authentication challenge to see if the responding peer can produce a valid signature with the expected responding peers identity-public-key by sending an AUTHCHALLENGE-message to the remote peer. + +The responding peer needs to check if the hash matches the hash calculated with his own local identity-public-key. Fingerprinting the requesting peer is not possible. + +{|class="wikitable" +! Field Size !! Description !! Data type !! Comments +|- +| 32bytes || challenge-hash || hash || hash(encryption-session-ID || challenge_type || remote-peers-expected-identity-public-key) +|} + + +challenge_type is a single character. i if the AUTHCHALLENGE-message is the first, requesting challenge or r if it's the second, remote peers challenge message. + +=== AUTHREPLY message === +A peer must reply an AUTHCHALLENGE-message with an AUTHREPLY-message. + +{|class="wikitable" +! Field Size !! Description !! Data type !! Comments +|- +| 64bytes || signature || normalized comp.-signature || A signature of the encryption-session-ID done with the identity-key +|} + +If the challenge-hash from the AUTHCHALLENGE-message did not match the local authentication public-key, the signature must contain 64bytes of zeros. + +The requesting peer can check the responding peers identity by checking the validity of the sent signature against with the pre-shared remote peers identity-public-key. + +If the signature was invalid, the requesting peer must still proceed with the authentication by sending an AUTHPROPOSE-message with 32 random bytes. + +=== AUTHPROPOSE message === +A peer can propose authentication of the channel by sending an AUTHPROPOSE-message to the remote peer. + +If the signature sent in AUTHREPLY was invalid, the peer must still send an AUTHPROPOSE-message containing 32 random bytes. + +The AUTHPROPOSE message must be answered with an AUTHCHALLENGE-message – even if the proposed requesting-peers identity-public-key has not been found in the authorized_peers database. In case of no match, the responding AUTHCHALLENGE-message must contains 32 bytes of zeros. + +{|class="wikitable" +! Field Size !! Description !! Data type !! Comments +|- +| 32bytes || auth-propose-hash || hash || hash(encryption-session-ID || "p" || identity-public-key) +|} + +== Post-Authentication Re-Keying == + +After the second AUTHREPLY message (requesting peers signature -> responding peer), both clients must re-key the symmetric encryption according to BIP151 while using '''a slightly different re-key key derivation hash'''. + +They both re-key with hash(encryption-session-ID || old_symmetric_cipher_key || requesting-peer-identity-public-key || responding-peer-identity-public-key) + +== Identity-Addresses == +The peers should display/log the identity-public-key as an identity-address to the users, which is a base58-check encoded ripemd160(sha256) hash. The purpose of this is for better visual comparison (logs, accept-dialogs). +The base58check identity byte is 0x0F followed by an identity-address version number (=0xFF01). + +An identity address would look like TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA and can be interpreted as a remote peers fingerprint. + +== Compatibility == + +This proposal is backward compatible. Non-supporting peers will ignore the new AUTH* messages. + +== Example of an auth interaction == + +Before authentication (once during peer setup or upgrade) +# Requesting peer and responding peer create each an identity-keypair (standard ECC priv/pubkey) +# Requesting and responding peer share the identity-public-key over a different channel (PGP mail, physical exchange, etc.) +# Responding peer stores requesting peers identity-public-key in its authorized-peers database (A) +# Requesting peer stores responding peers identity-public-key in its known-peers database together with its IP and port (B) + +Encryption +# Encrypted channels must be established (according to BIP-151 [1]) + +Authentication +# Requesting peer sends an AUTHCHALLENGE message + AUTHCHALLENGE: + [32 bytes, hash(encryption-session-ID || "i" || )] + +# Responding peer does create the same hash (encryption-session-ID || "i" || ) with its local identity-public-key +# If the hash does not match, response with an AUTHREPLY message containing 64bytes of zeros. +# In case of a match, response with an AUTHREPLY message + AUTHREPLY: + [64 bytes normalized compact ECDSA signature (H)] (sig of the encryption-session-ID done with the identity-key) + +# Requesting peer does verify the signature with the remote-peers-identity-public-key +# If the signature is invalid, requesting peer answers with an AUTHREPLY message containing 32 random bytes +# In case of a valid signature, requesting peer sends an AUTHPROPOSE message + AUTHPROPOSE: + [32 bytes, hash(encryption-session-ID || "p" || )] + +# Responding peer iterates over authorized-peers database (A), hashes the identical data and looks for a match. +# If the hash does not match, responding peer answer with an AUTHCHALLENGE message containing 32 bytes of zeros. +# In case of a match, responding peer sends an AUTHCHALLENGE message with the hashed client public-key + AUTHCHALLENGE: + [32 bytes, hash(encryption-session-ID || "r" || )] +# Requesting peer sends an AUTHREPLY message containing 64 bytes of zeros if server failed to authenticate +# Otherwise, response with signature in the AUTHREPLY message + AUTHREPLY: + [64 bytes normalized compact ECDSA signature (H)] (sig of the encryption-session-ID done with the identity-key) +# Responding peer must verify the signature and can grant access to restricted services. +# Both peers re-key the encryption after BIP151 including the requesting-peer-identity-public-key and responding-peer-identity-public-key + +== Disadvantages == + +The protocol may be slow if a peer has a large authorized-peers database due to the requirement of iterating and hashing over all available authorized peers identity-public-keys. + +== Reference implementation == + +== References == + +* [1] [[bip-0151.mediawiki|BIP 151: Peer-to-Peer Communication Encryption]] + +== Acknowledgements == +* Gregory Maxwell and Pieter Wuille for most of the ideas in this BIP. + +== Copyright == +This work is placed in the public domain. From ffa155e452080b0820a6354081d0ef895c498000 Mon Sep 17 00:00:00 2001 From: Bryan Bishop Date: Tue, 16 Aug 2016 11:56:22 -0500 Subject: [PATCH 09/14] peer authentication bip draft editing --- bip-0150.mediawiki | 47 +++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/bip-0150.mediawiki b/bip-0150.mediawiki index 1383ee9..b1d46c1 100644 --- a/bip-0150.mediawiki +++ b/bip-0150.mediawiki @@ -9,19 +9,19 @@ == Abstract == -This BIP describes a way how peers can authenticate – without opening fingerprinting possibilities – to other peers to guarantee ownership and/or allowing to access additional or limited services. +This BIP describes a way for peers to authenticate to other peers to guarantee node ownership and/or allow peers to access additional or limited node services, without the possibility of fingerprinting. == Motivation == -We assume peer operators want to limit the access of different services or increase datastream priorities to a selective subset of peers. Also we assume peers want to connect to specific peers to broadcast or filter transactions (or similar action that reveals sensitive informations) and therefore they want to authenticate the remote peer and make sure that they have not connected to a MITM. +We assume peer operators want to limit the access of different node services or increase datastream priorities to a selective subset of peers. Also we assume that peers want to connect to specific peers to broadcast or filter transactions (or similar actions that reveal sensitive informations) and therefore operators want to authenticate the remote peer and ensure that they have not connected to a MITM (man-in-the-middle) attacker. -Benefits with peer authentication: -* Peers could detect MITM attacks when connecting to known peers -* Peers could allow resource hungry transaction filtering only to specific peers -* Peers could allow access to sensitive information that can lead to node fingerprinting (fee estimation) -* Peers could allow custom message types (private extensions) to authenticated peers +Benefits of peer authentication: +* Peers can detect MITM attacks when connecting to known peers +* Peers can allow resource hungry transaction filtering only to specific peers +* Peers can allow access to sensitive information that can lead to node fingerprinting (fee estimation) +* Peers can allow custom message types (private extensions) to authenticated peers -A simple authentication scheme based on elliptic cryptography will allow peers to identify each other and selective allow access to restricted services or reject the connection if the identity could not be verified. +A simple authentication scheme based on elliptic cryptography will allow peers to identify each other and selectively allow access to restricted services or reject the connection if the peer identity cannot be verified. == Specification == @@ -31,24 +31,24 @@ The authentication scheme proposed in this BIP uses ECDSA, '''secrets will never The '''encryption-session-ID''' is available once channels are encrypted (according to BIP-151 [1]). -The identity-public-keys used for the authentication must be pre-shared over a different channel (Mail/PGP, physical paper exchange, etc.). This BIP does not cover a "trust on first use" (TOFU) concept. +The identity-public-keys used for the authentication must be pre-shared over a different channel (mail/PGP, physical paper exchange, etc.). This BIP does not cover a "trust on first use" (TOFU) concept. The authentication state must be kept until the encryption/connection terminates. -Only one authentication process is allowed per connection. Re-authenticate require re-establishing the connection. +Only one authentication process is allowed per connection. Re-authentication require re-establishing the connection. === Known-peers and authorized-peers database === -Each peer that supports p2p authentication must provide two users editable "databases" +Each peer that supports p2p authentication must provide two user-editable "databases". # '''known-peers''' contains known identity-public-keys together with a network identifier (IP & port), similar to the "known-host" file supported by openssh. # '''authorized-peers''' contains authorized identity-public-keys === Local identity key management === -Each peer can configure multiple identity-keys (ECC, 32 bytes). Peers should make sure, each network interface (IPv4, IPv6, tor) has its own identity-key (otherwise it would be possible to link a tor address to a IPvX address). +Each peer can configure multiple identity-keys (ECC, 32 bytes). Peers should make sure that each network interface (IPv4, IPv6, tor) has its own identity-key (otherwise it would be possible to link a tor address to a IPvX address). The identity-public-key(s) can be shared over a different channel with other node-operators (or non-validating clients) to grant authorized access. === Authentication procedure === -Authentication after this BIP will require both sides to authenticate. Signatures/public-keys will only be revealed if the remote peer could prove that they already know the remote identity-public-key. +Authentication based on this BIP will require both sides to authenticate. Signatures/public-keys will only be revealed if the remote peer can prove that they already know the remote identity-public-key. # -> Requesting peer sends AUTHCHALLENGE (hash) # <- Responding peer sends AUTHREPLY (signature) @@ -56,10 +56,10 @@ Authentication after this BIP will require both sides to authenticate. Signature # <- Responding peer sends AUTHCHALLENGE (hash) # -> Requesting peer sends AUTHREPLY (signature) -For privacy reasons, dropping the connection or aborting during the authentication process must not be possible. +For privacy reasons, dropping the connection or aborting during the authentication process must not be allowed. === AUTHCHALLENGE message === -A peer can send an authentication challenge to see if the responding peer can produce a valid signature with the expected responding peers identity-public-key by sending an AUTHCHALLENGE-message to the remote peer. +A peer can send an authentication challenge to see if the responding peer can produce a valid signature with the expected responding peer's identity-public-key by sending an AUTHCHALLENGE-message to the remote peer. The responding peer needs to check if the hash matches the hash calculated with his own local identity-public-key. Fingerprinting the requesting peer is not possible. @@ -81,9 +81,9 @@ A peer must reply an AUTHCHALLENGE-message with an AUTHREPLY< | 64bytes || signature || normalized comp.-signature || A signature of the encryption-session-ID done with the identity-key |} -If the challenge-hash from the AUTHCHALLENGE-message did not match the local authentication public-key, the signature must contain 64bytes of zeros. +If the challenge-hash from the AUTHCHALLENGE-message did not match the local authentication public-key, the signature must contain 64 bytes of zeros. -The requesting peer can check the responding peers identity by checking the validity of the sent signature against with the pre-shared remote peers identity-public-key. +The requesting peer can check the responding peer's identity by checking the validity of the sent signature against with the pre-shared remote peers identity-public-key. If the signature was invalid, the requesting peer must still proceed with the authentication by sending an AUTHPROPOSE-message with 32 random bytes. @@ -92,7 +92,7 @@ A peer can propose authentication of the channel by sending an AUTHPROPOSE If the signature sent in AUTHREPLY was invalid, the peer must still send an AUTHPROPOSE-message containing 32 random bytes. -The AUTHPROPOSE message must be answered with an AUTHCHALLENGE-message – even if the proposed requesting-peers identity-public-key has not been found in the authorized_peers database. In case of no match, the responding AUTHCHALLENGE-message must contains 32 bytes of zeros. +The AUTHPROPOSE message must be answered with an AUTHCHALLENGE-message - even if the proposed requesting-peers identity-public-key has not been found in the authorized-peers database. In case of no match, the responding AUTHCHALLENGE-message must contains 32 bytes of zeros. {|class="wikitable" ! Field Size !! Description !! Data type !! Comments @@ -102,15 +102,15 @@ The AUTHPROPOSE message must be answered with an AUTHCHALLENG == Post-Authentication Re-Keying == -After the second AUTHREPLY message (requesting peers signature -> responding peer), both clients must re-key the symmetric encryption according to BIP151 while using '''a slightly different re-key key derivation hash'''. +After the second AUTHREPLY message (requesting peer's signature -> responding peer), both clients must re-key the symmetric encryption according to BIP151 while using '''a slightly different re-key key derivation hash'''. -They both re-key with hash(encryption-session-ID || old_symmetric_cipher_key || requesting-peer-identity-public-key || responding-peer-identity-public-key) +Both peers re-key with hash(encryption-session-ID || old_symmetric_cipher_key || requesting-peer-identity-public-key || responding-peer-identity-public-key) == Identity-Addresses == The peers should display/log the identity-public-key as an identity-address to the users, which is a base58-check encoded ripemd160(sha256) hash. The purpose of this is for better visual comparison (logs, accept-dialogs). The base58check identity byte is 0x0F followed by an identity-address version number (=0xFF01). -An identity address would look like TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA and can be interpreted as a remote peers fingerprint. +An identity address would look like TfG4ScDgysrSpodWD4Re5UtXmcLbY5CiUHA and can be interpreted as a remote peer's fingerprint. == Compatibility == @@ -120,7 +120,7 @@ This proposal is backward compatible. Non-supporting peers will ignore the new < Before authentication (once during peer setup or upgrade) # Requesting peer and responding peer create each an identity-keypair (standard ECC priv/pubkey) -# Requesting and responding peer share the identity-public-key over a different channel (PGP mail, physical exchange, etc.) +# Requesting and responding peer share the identity-public-key over a different channel (mail/PGP, physical paper exchange, etc.) # Responding peer stores requesting peers identity-public-key in its authorized-peers database (A) # Requesting peer stores responding peers identity-public-key in its known-peers database together with its IP and port (B) @@ -158,7 +158,7 @@ Authentication == Disadvantages == -The protocol may be slow if a peer has a large authorized-peers database due to the requirement of iterating and hashing over all available authorized peers identity-public-keys. +The protocol may be slow if a peer has a large authorized-peers database due to the requirement of iterating and hashing over all available authorized peer identity-public-keys. == Reference implementation == @@ -168,6 +168,7 @@ The protocol may be slow if a peer has a large authorized-peers database due to == Acknowledgements == * Gregory Maxwell and Pieter Wuille for most of the ideas in this BIP. +* Bryan Bishop for editing. == Copyright == This work is placed in the public domain. From 003cf078ff126a6fbb30a4575f8c2c28848c69ff Mon Sep 17 00:00:00 2001 From: Johnson Lau Date: Wed, 17 Aug 2016 19:57:01 +0800 Subject: [PATCH 10/14] BIP146: change title and add NULLDUMMY rules --- README.mediawiki | 2 +- bip-0146.mediawiki | 33 ++++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/README.mediawiki b/README.mediawiki index 26c65f0..070c9dc 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -513,7 +513,7 @@ Those proposing changes should consider that ultimately consent may rest with th | Draft |- | [[bip-0146.mediawiki|146]] -| Low S values signatures +| Dealing with signature malleability | Pieter Wuille, Johnson Lau | Standard | Draft diff --git a/bip-0146.mediawiki b/bip-0146.mediawiki index f57aa21..c92c54e 100644 --- a/bip-0146.mediawiki +++ b/bip-0146.mediawiki @@ -1,6 +1,6 @@
   BIP: 146
-  Title: Low S values signatures
+  Title: Dealing with signature malleability
   Author: Pieter Wuille 
           Johnson Lau 
   Status: Draft
@@ -10,22 +10,40 @@
 
 ==Abstract==
 
-This document specifies proposed changes to the Bitcoin transaction validity rules to restrict signatures to using low S values.
+This document specifies proposed changes to the Bitcoin transaction validity rules to fix signature malleability for common transaction types.
 
 
 ==Motivation==
 
-ECDSA signatures are inherently malleable as taking the negative of the number S inside (modulo the curve order) does not invalidate it. This is a nuisance malleability vector as any relay node on the network may transform the signature, with no access to the relevant private keys required. For non-segregated witness transactions, this malleability will change the txid and invalidate any unconfirmed child transactions. Although the txid of segregated witness ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) transactions is not third party malleable, this malleability vector will change the wtxid and may reduce the efficiency of compact block relay ([https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki BIP152]).
+Signature malleability refers to the ability of any relay node on the network to transform the signature in transactions, with no access to the relevant private keys required. For non-segregated witness transactions, signature malleability will change the txid and invalidate any unconfirmed child transactions. Although the txid of segregated witness ([https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki BIP141]) transactions is not third party malleable, this malleability vector will change the wtxid and may reduce the efficiency of compact block relay ([https://github.com/bitcoin/bips/blob/master/bip-0152.mediawiki BIP152]).
 
-To fix this malleability, we require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially restricting this value to its lower half range). The value S in signatures must be between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive). If S is too high, simply replace it by S' = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S.
+Since the enforcement of Strict DER signatures ([https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66]), there are 2 remaining known sources of malleability in the signature passed to ECDSA verification opcodes:
+
+# '''Inherent ECDSA signature malleability''': ECDSA signatures are inherently malleable as taking the negative of the number S inside (modulo the curve order) does not invalidate it.
+
+# '''Inputs ignored by scripts''': The (unnecessary) extra stack element consumed by OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY is not inspected in any manner, and could be replaced with any value.
+
+This document specifies new rules to fix the aforesaid signature malleability.
 
 
 ==Specification==
 
-Every signature passed to OP_CHECKSIGIncluding pay-to-witness-public-key-hash (P2WPKH) described in BIP141, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, or OP_CHECKMULTISIGVERIFY, to which ECDSA verification is applied, MUST use a S value between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive) with strict DER encoding (see [https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66]).
+To fix signature malleability, the following new rules are applied:
+
+
+===LOW_S===
+
+We require that the S value inside ECDSA signatures is at most the curve order divided by 2 (essentially restricting this value to its lower half range). Every signature passed to OP_CHECKSIGIncluding pay-to-witness-public-key-hash (P2WPKH) described in BIP141, OP_CHECKSIGVERIFY, OP_CHECKMULTISIG, or OP_CHECKMULTISIGVERIFY, to which ECDSA verification is applied, MUST use a S value between 0x1 and 0x7FFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF 5D576E73 57A4501D DFE92F46 681B20A0 (inclusive) with strict DER encoding (see [https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki BIP66]).
 
 These operators all perform ECDSA verifications on pubkey/signature pairs, iterating from the top of the stack backwards. For each such verification, if the signature does not pass the Low S value check, the entire script evaluates to false immediately. If the signature is valid DER with low S value, but does not pass ECDSA verification, opcode execution continues as it used to, causing opcode execution to stop and push false on the stack (but not immediately fail the script) in some cases, which potentially skips further signatures (and thus does not subject them to Low S value check).
 
+A high S value in signature could be trivially replaced by S' = 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141 - S.
+
+
+===NULLDUMMY===
+
+The extra stack element consumed by OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY MUST be the empty byte array (the result of OP_0). Anything else makes the script evaluate to false immediately.
+
 
 ==Deployment==
 
@@ -38,15 +56,16 @@ For Bitcoin testnet, the BIP9 starttime will be midnight 1 May 2016 UTC (Epoch t
 
 ==Compatibility==
 
-The reference client has produced compatible signatures since v0.9.0, and the requirement to have low S value signatures has been enforced as a relay policy by the reference client since v0.11.1. As of August 2016, very few transactions violating the requirement are being added to the chain. In addition, every non-compliant signature can trivially be converted into a compliant one, so there is no loss of functionality by this requirement. This proposal has the added benefit of reducing transaction malleability.
+The reference client has produced compatible signatures since v0.9.0, and NULLDUMMY and LOW_S have been enforced as relay policy by the reference client since v0.10.0 and v0.11.1 respectively. As of August 2016, very few transactions violating the requirement are being added to the chain. In addition, every non-compliant signature can trivially be converted into a compliant one, so there is no loss of functionality by this requirement.
 
 
 ==Implementation==
 
-An implementation for the reference client is available at https://github.com/bitcoin/bitcoin/pull/8514
+An implementation for the reference client is available at https://github.com/bitcoin/bitcoin/pull/8533
 
 
 ==Footnotes==
+
 
 
 

From d35a3d33da628fb3da543bb8652a2153d65562c5 Mon Sep 17 00:00:00 2001
From: Luke Dashjr 
Date: Sat, 20 Aug 2016 23:50:14 +0000
Subject: [PATCH 11/14] Promote BIP 9 Draft->Final

---
 README.mediawiki   | 4 ++--
 bip-0009.mediawiki | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/README.mediawiki b/README.mediawiki
index 070c9dc..8700b22 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -24,12 +24,12 @@ Those proposing changes should consider that ultimately consent may rest with th
 | Luke Dashjr
 | Process
 | Deferred
-|-
+|- style="background-color: #cfffcf"
 | [[bip-0009.mediawiki|9]]
 | Version bits with timeout and delay
 | Pieter Wuille, Peter Todd, Greg Maxwell, Rusty Russell
 | Informational
-| Draft
+| Final
 |- style="background-color: #ffcfcf"
 | [[bip-0010.mediawiki|10]]
 | Multi-Sig Transaction Distribution
diff --git a/bip-0009.mediawiki b/bip-0009.mediawiki
index 7270abd..536ef1f 100644
--- a/bip-0009.mediawiki
+++ b/bip-0009.mediawiki
@@ -5,7 +5,7 @@
           Peter Todd 
           Greg Maxwell 
           Rusty Russell 
-  Status: Draft
+  Status: Final
   Type: Informational
   Created: 2015-10-04
 
From 387fc6011bd804609fd751786e50439d5c11a097 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 23 Aug 2016 19:47:29 +0000 Subject: [PATCH 12/14] Promote BIPs 18, 39, 44, 67, 80, 81, 111, 125, 130, and 132 Draft->Accepted; change BIP 43 to Informational --- README.mediawiki | 38 +++++++++++++++++++------------------- bip-0018.mediawiki | 2 +- bip-0039.mediawiki | 2 +- bip-0043.mediawiki | 2 +- bip-0044.mediawiki | 2 +- bip-0067.mediawiki | 2 +- bip-0080.mediawiki | 2 +- bip-0081.mediawiki | 2 +- bip-0111.mediawiki | 2 +- bip-0125.mediawiki | 2 +- bip-0130.mediawiki | 2 +- bip-0132.mediawiki | 2 +- 12 files changed, 30 insertions(+), 30 deletions(-) diff --git a/README.mediawiki b/README.mediawiki index 8700b22..6f9d785 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -78,12 +78,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Luke Dashjr | Standard | Withdrawn -|- +|- style="background-color: #ffffcf" | [[bip-0018.mediawiki|18]] | hashScriptCheck | Luke Dashjr | Standard -| Draft +| Accepted |- | [[bip-0019.mediawiki|19]] | M-of-N Standard Transactions (Low SigOp) @@ -168,12 +168,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Mike Caldwell, Aaron Voisine | Standard | Draft -|- +|- style="background-color: #ffffcf" | [[bip-0039.mediawiki|39]] | Mnemonic code for generating deterministic keys | Marek Palatinus, Pavol Rusnak, Aaron Voisine, Sean Bowe | Standard -| Draft +| Accepted |- | 40 | Stratum wire protocol @@ -196,14 +196,14 @@ Those proposing changes should consider that ultimately consent may rest with th | [[bip-0043.mediawiki|43]] | Purpose Field for Deterministic Wallets | Marek Palatinus, Pavol Rusnak -| Standard +| Informational | Draft -|- +|- style="background-color: #ffffcf" | [[bip-0044.mediawiki|44]] | Multi-Account Hierarchy for Deterministic Wallets | Marek Palatinus, Pavol Rusnak | Standard -| Draft +| Accepted |- | [[bip-0045.mediawiki|45]] | Structure for Deterministic P2SH Multisignature Wallets @@ -265,12 +265,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Pieter Wuille | Standard | Final -|- +|- style="background-color: #ffffcf" | [[bip-0067.mediawiki|67]] | Deterministic Pay-to-script-hash multi-signature addresses through public key sorting | Thomas Kerin, Jean-Pierre Rupp, Ruben de Vries | Standard -| Draft +| Accepted |- style="background-color: #cfffcf" | [[bip-0068.mediawiki|68]] | Relative lock-time using consensus-enforced sequence numbers @@ -324,13 +324,13 @@ Those proposing changes should consider that ultimately consent may rest with th | Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets | Justus Ranvier, Jimmy Song | Informational -| Draft +| Deferred |- | [[bip-0081.mediawiki|81]] | Hierarchy for Colored Voting Pool Deterministic Multisig Wallets | Justus Ranvier, Jimmy Song | Informational -| Draft +| Deferred |- | [[bip-0083.mediawiki|83]] | Dynamic Hierarchical Deterministic Key Trees @@ -385,12 +385,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Gavin Andresen | Standard | Draft -|- +|- style="background-color: #ffffcf" | [[bip-0111.mediawiki|111]] | NODE_BLOOM service bit | Matt Corallo, Peter Todd | Standard -| Draft +| Accepted |- style="background-color: #cfffcf" | [[bip-0112.mediawiki|112]] | CHECKSEQUENCEVERIFY @@ -439,36 +439,36 @@ Those proposing changes should consider that ultimately consent may rest with th | Eric Lombrozo, William Swanson | Informational | Draft -|- +|- style="background-color: #ffffcf" | [[bip-0125.mediawiki|125]] | Opt-in Full Replace-by-Fee Signaling | David A. Harding, Peter Todd | Standard -| Draft +| Accepted |- | [[bip-0126.mediawiki|126]] | Best Practices for Heterogeneous Input Script Transactions | Kristov Atlas | Informational | Draft -|- +|- style="background-color: #ffffcf" | [[bip-0130.mediawiki|130]] | sendheaders message | Suhas Daftuar | Standard -| Draft +| Accepted |- | [[bip-0131.mediawiki|131]] | "Coalescing Transaction" Specification (wildcard inputs) | Chris Priest | Standard | Draft -|- +|- style="background-color: #ffcfcf" | [[bip-0132.mediawiki|132]] | Committee-based BIP Acceptance Process | Andy Chase | Process -| Draft +| Withdrawn |- | [[bip-0133.mediawiki|133]] | feefilter message diff --git a/bip-0018.mediawiki b/bip-0018.mediawiki index 023b2bf..fce4200 100644 --- a/bip-0018.mediawiki +++ b/bip-0018.mediawiki @@ -2,7 +2,7 @@ BIP: 18 Title: hashScriptCheck Author: Luke Dashjr - Status: Draft + Status: Accepted Type: Standards Track Created: 2012-01-27
diff --git a/bip-0039.mediawiki b/bip-0039.mediawiki index 6fd8bd0..3c95d4d 100644 --- a/bip-0039.mediawiki +++ b/bip-0039.mediawiki @@ -5,7 +5,7 @@ Pavol Rusnak Aaron Voisine Sean Bowe - Status: Draft + Status: Accepted Type: Standards Track Created: 2013-09-10 diff --git a/bip-0043.mediawiki b/bip-0043.mediawiki index 4c57935..686221a 100644 --- a/bip-0043.mediawiki +++ b/bip-0043.mediawiki @@ -4,7 +4,7 @@ Author: Marek Palatinus Pavol Rusnak Status: Draft - Type: Standards Track + Type: Informational Created: 2014-04-24 diff --git a/bip-0044.mediawiki b/bip-0044.mediawiki index 883677a..e17c73d 100644 --- a/bip-0044.mediawiki +++ b/bip-0044.mediawiki @@ -3,7 +3,7 @@ Title: Multi-Account Hierarchy for Deterministic Wallets Author: Marek Palatinus Pavol Rusnak - Status: Draft + Status: Accepted Type: Standards Track Created: 2014-04-24 diff --git a/bip-0067.mediawiki b/bip-0067.mediawiki index 3864c63..13e2ed9 100644 --- a/bip-0067.mediawiki +++ b/bip-0067.mediawiki @@ -4,7 +4,7 @@ Author: Thomas Kerin Jean-Pierre Rupp Ruben de Vries - Status: Draft + Status: Accepted Type: Standards Track Created: 2015-02-08 diff --git a/bip-0080.mediawiki b/bip-0080.mediawiki index 13d8597..05322e0 100644 --- a/bip-0080.mediawiki +++ b/bip-0080.mediawiki @@ -3,7 +3,7 @@ Title: Hierarchy for Non-Colored Voting Pool Deterministic Multisig Wallets Author: Justus Ranvier Jimmy Song - Status: Draft + Status: Deferred Type: Informational Created: 2014-08-11 diff --git a/bip-0081.mediawiki b/bip-0081.mediawiki index b306075..713cb57 100644 --- a/bip-0081.mediawiki +++ b/bip-0081.mediawiki @@ -3,7 +3,7 @@ Title: Hierarchy for Colored Voting Pool Deterministic Multisig Wallets Author: Justus Ranvier Jimmy Song - Status: Draft + Status: Deferred Type: Informational Created: 2014-08-11 diff --git a/bip-0111.mediawiki b/bip-0111.mediawiki index f759f5c..4557832 100644 --- a/bip-0111.mediawiki +++ b/bip-0111.mediawiki @@ -3,7 +3,7 @@ Title: NODE_BLOOM service bit Author: Matt Corallo Peter Todd - Status: Draft + Status: Accepted Type: Standards Track Created: 2015-08-20 diff --git a/bip-0125.mediawiki b/bip-0125.mediawiki index 7d88469..52dfe40 100644 --- a/bip-0125.mediawiki +++ b/bip-0125.mediawiki @@ -3,7 +3,7 @@ Title: Opt-in Full Replace-by-Fee Signaling Author: David A. Harding Peter Todd - Status: Draft + Status: Accepted Type: Standards Track Created: 2015-12-04 diff --git a/bip-0130.mediawiki b/bip-0130.mediawiki index 56184e3..ae1e602 100644 --- a/bip-0130.mediawiki +++ b/bip-0130.mediawiki @@ -2,7 +2,7 @@ BIP: 130 Title: sendheaders message Author: Suhas Daftuar - Status: Draft + Status: Accepted Type: Standards Track Created: 2015-05-08 diff --git a/bip-0132.mediawiki b/bip-0132.mediawiki index 90c09b1..03cc834 100644 --- a/bip-0132.mediawiki +++ b/bip-0132.mediawiki @@ -2,7 +2,7 @@ BIP: 132 Title: Committee-based BIP Acceptance Process Author: Andy Chase - Status: Draft + Status: Withdrawn Type: Process Created: 2015-08-31 From 04e1a86f513f9662c63656d220301aaca77eeaa9 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Thu, 25 Aug 2016 21:10:19 +0000 Subject: [PATCH 13/14] Promote BIP 45 Draft->Accepted --- README.mediawiki | 4 ++-- bip-0045.mediawiki | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.mediawiki b/README.mediawiki index 6f9d785..35387e1 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -204,12 +204,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Marek Palatinus, Pavol Rusnak | Standard | Accepted -|- +|- style="background-color: #ffffcf" | [[bip-0045.mediawiki|45]] | Structure for Deterministic P2SH Multisignature Wallets | Manuel Araoz, Ryan X. Charles, Matias Alejo Garcia | Standard -| Draft +| Accepted |- | [[bip-0047.mediawiki|47]] | Reusable Payment Codes for Hierarchical Deterministic Wallets diff --git a/bip-0045.mediawiki b/bip-0045.mediawiki index 1550467..757fc7f 100644 --- a/bip-0045.mediawiki +++ b/bip-0045.mediawiki @@ -4,7 +4,7 @@ Author: Manuel Araoz Ryan X. Charles Matias Alejo Garcia - Status: Draft + Status: Accepted Type: Standards Track Created: 2014-04-25 From 1501dd99bd12f9e6835f5169d21fd29fb41071db Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 27 Aug 2016 20:21:26 +0000 Subject: [PATCH 14/14] Promote BIP 69 Draft->Accepted --- README.mediawiki | 4 ++-- bip-0069.mediawiki | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.mediawiki b/README.mediawiki index 35387e1..8b48af1 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -277,12 +277,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Mark Friedenbach, BtcDrak, Nicolas Dorier, kinoshitajona | Standard | Final -|- +|- style="background-color: #ffffcf" | [[bip-0069.mediawiki|69]] | Lexicographical Indexing of Transaction Inputs and Outputs | Kristov Atlas | Informational -| Draft +| Accepted |- style="background-color: #cfffcf" | [[bip-0070.mediawiki|70]] | Payment Protocol diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki index 4094126..832438c 100644 --- a/bip-0069.mediawiki +++ b/bip-0069.mediawiki @@ -3,7 +3,7 @@ Title: Lexicographical Indexing of Transaction Inputs and Outputs Author: Kristov Atlas Editor: Daniel Cousens - Status: Draft + Status: Accepted Type: Informational Created: 2015-06-12