@@ -161,124 +161,88 @@ forming a "Payment Pool".
161161
162162==Detailed Specification ==
163163
164- The below code is the main logic for verifying CHECKTEMPLATEVERIFY, and is the canonical
165- specification for the semantics of OP_CHECKTEMPLATEVERIFY.
166-
167- case OP_CHECKTEMPLATEVERIFY:
168- {
169- // if flags not enabled; treat as a NOP4
170- if (!(flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH)) {
171- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
172- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
173- break;
174- }
175-
176- if (stack.size() < 1)
177- return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
178-
179- // If the argument was not 32 bytes, treat as OP_NOP4:
180- switch (stack.back().size()) {
181- case 32:
182- if (!checker.CheckDefaultCheckTemplateVerifyHash(stack.back())) {
183- return set_error(serror, SCRIPT_ERR_TEMPLATE_MISMATCH);
184- }
185- break;
186- default:
187- // future upgrade can add semantics for this opcode with different length args
188- // so discourage use when applicable
189- if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
190- return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
191- }
192- }
193- }
194- break;
195-
196- Where
197-
198- bool CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) {
199- // note: for anti-DoS, a real implementation *must* cache parts of this computation
200- // to avoid quadratic hashing DoS all variable length computations must be precomputed
201- // including hashes of the scriptsigs, sequences, and outputs. See the section
202- // "Denial of Service and Validation Costs" below.
203- return GetDefaultCheckTemplateVerifyHash(current_tx, current_input_index) == uint256(hash);
204- }
205-
206- The hash is computed as follows, where the outputs_hash and sequences_hash are computed as defined in BIP-341.
207-
208- /** Compute the (single) SHA256 of the concatenation of all scriptSigs in a tx. */
209- template <class T>
210- uint256 GetScriptSigsSHA256(const T& txTo)
211- {
212- CHashWriter ss(SER_GETHASH, 0);
213- for (const auto& in : txTo.vin) {
214- ss << in.scriptSig;
215- }
216- return ss.GetSHA256();
217- }
218- // not DoS safe, for reference/testing!
219- uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, uint32_t input_index) {
220- return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx), input_index);
221- }
222- // not DoS safe for reference/testing!
223- uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
224- const uint32_t input_index) {
225- bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(),
226- [](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end();
227- return skip_scriptSigs ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
228- GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
229- }
230- // DoS safe, fixed length hash!
231- uint256 GetDefaultCheckTemplateVerifyHashWithScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
232- const uint256& scriptSig_hash, const uint32_t input_index) {
233- auto h = CHashWriter(SER_GETHASH, 0)
234- << tx.nVersion
235- << tx.nLockTime
236- << scriptSig_hash
237- << uint32_t(tx.vin.size())
238- << sequences_hash
239- << uint32_t(tx.vout.size())
240- << outputs_hash
241- << input_index;
242- return h.GetSHA256();
243- }
244- // DoS safe, fixed length hash!
245- uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
246- const uint32_t input_index) {
247- auto h = CHashWriter(SER_GETHASH, 0)
248- << tx.nVersion
249- << tx.nLockTime
250- << uint32_t(tx.vin.size())
251- << sequences_hash
252- << uint32_t(tx.vout.size())
253- << outputs_hash
254- << input_index;
255- return h.GetSHA256();
256- }
257-
258- In python, this can be written as (but note this implementation is DoS-able).
259-
260- def get_default_check_template_hash(self, nIn):
164+ The below code is the main logic for verifying CHECKTEMPLATEVERIFY, described
165+ in pythonic pseduocode. The canonical specification for the semantics of
166+ OP_CHECKTEMPLATEVERIFY as implemented in C++ in the context of Bitcoin Core can
167+ be seen in the reference implementation.
168+
169+ The execution of the opcode is as follows:
170+ def execute_bip_119(self):
171+ # Before soft-fork activation / failed activation
172+ if not self.flags.script_verify_default_check_template_verify_hash:
173+ # Potentially set for node-local policy to discourage premature use
174+ if self.flags.script_verify_discourage_upgradable_nops:
175+ return self.errors_with(errors.script_err_discourage_upgradable_nops)
176+ return self.return_as_nop()
177+ # CTV always requires at least one stack argument
178+ if len(self.stack) < 1:
179+ return self.errors_with(errors.script_err_invalid_stack_operation)
180+ # CTV only verifies the hash against a 32 byte argument
181+ if len(self.stack[-1]) == 32:
182+ # Ensure the precomputed data required for anti-DoS is available,
183+ # or cache it on first use
184+ if self.context.precomputed_ctv_data == None:
185+ self.context.precomputed_ctv_data = self.context.tx.get_default_check_template_precomputed_data()
186+ if stack[-1] != self.context.tx.get_default_check_template_hash(self.context.nIn, self.context.precomputed_ctv_data)
187+ return self.errors_with(errors.script_err_template_mismatch)
188+ return self.return_as_nop()
189+ # future upgrade can add semantics for this opcode with different length args
190+ # so discourage use when applicable
191+ if self.flags.script_verify_discourage_upgradable_nops:
192+ return self.errors_with(errors.script_err_discourage_upgradable_nops)
193+ else:
194+ return self.return_as_nop()
195+
196+ The computation of this hash can be implemented as specified below (where self
197+ is the transaction type). Care must be taken that in any validation context,
198+ the precomputed data must be initialized to prevent Denial-of-Service attacks.
199+ Any implementation *must* cache these parts of the hash computation to avoid
200+ quadratic hashing DoS. All variable length computations must be precomputed
201+ including hashes of the scriptsigs, sequences, and outputs. See the section
202+ "Denial of Service and Validation Costs" below. This is not a performance
203+ optimization.
204+
205+ def get_default_check_template_precomputed_data(self):
206+ result = {}
207+ # If there are no scriptSigs we do not need to precompute a hash
208+ if any(inp.scriptSig for inp in self.vin):
209+ result["scriptSigs"] = sha256(b"".join(ser_string(inp.scriptSig) for inp in self.vin))
210+ # The same value is also pre-computed for and defined in BIP-341 and can be shared
211+ result["sequences"] = sha256(b"".join(struct.pack("<I", inp.nSequence) for inp in self.vin))
212+ # The same value is also pre-computed for and defined in BIP-341 and can be shared
213+ result["outputs"] = sha256(b"".join(out.serialize() for out in self.vout))
214+ return result
215+
216+ # parameter precomputed must be passed in for DoS resistance
217+ def get_default_check_template_hash(self, nIn, precomputed = None):
218+ if precomputed == None:
219+ precomputed = self.get_default_check_template_precomputed_data()
261220 r = b""
221+ # pack as 4 byte signed integer
262222 r += struct.pack("<i", self.nVersion)
223+ # pack as 4 byte unsigned integer
263224 r += struct.pack("<I", self.nLockTime)
264- if any(inp.scriptSig for inp in self.vin):
265- r += sha256(b"".join(ser_string(inp.scriptSig) for inp in self.vin))
225+ # we do not include the hash in the case where there is no
226+ # scriptSigs
227+ if "scriptSigs" in precomputed:
228+ r += precomputed["scriptSigs"]
229+ # pack as 4 byte unsigned integer
266230 r += struct.pack("<I", len(self.vin))
267- r += sha256(b"".join(struct.pack("<I", inp.nSequence) for inp in self.vin))
231+ r += precomputed["sequences"]
232+ # pack as 4 byte unsigned integer
268233 r += struct.pack("<I", len(self.vout))
269- r += sha256(b"".join(out.serialize() for out in self.vout))
234+ r += precomputed["outputs"]
235+ # pack as 4 byte unsigned integer
270236 r += struct.pack("<I", nIn)
271237 return sha256(r)
272238
239+
273240A PayToBareDefaultCheckTemplateVerifyHash output matches the following template:
274241
275- bool CScript::IsPayToBareDefaultCheckTemplateVerifyHash() const
276- {
277- // Extra-fast test for pay-to-basic-standard-template CScripts:
278- return (this->size() == 34 &&
279- (*this)[0] == 0x20 &&
280- (*this)[33] == OP_CHECKTEMPLATEVERIFY);
281- }
242+ # Extra-fast test for pay-to-basic-standard-template CScripts:
243+ def is_pay_to_bare_default_check_template_verify_hash(self):
244+ return len(self) == 34 and self[0] == 0x20 and self[-1 ] == OP_CHECKTEMPLATEVERIFY
245+
282246
283247==Deployment ==
284248
@@ -567,9 +531,7 @@ is O(T) (the size of the transaction).
567531
568532An example of a script that could experience an DoS issue without caching is:
569533
570- ```
571- <H> CTV CTV CTV... CTV
572- ```
534+ <H> CTV CTV CTV... CTV
573535
574536Such a script would cause the intepreter to compute hashes (supposing N CTV's) over O(N*T) data.
575537If the scriptSigs non-nullity is not cached, then the O(T) transaction could be scanned over O(N)
0 commit comments