Skip to content

Commit abc9e84

Browse files
authored
Merge pull request bitcoin#1272 from JeremyRubin/patch-4
[BIP-119] Add notes and warnings about DoS during validation of CTV.
2 parents 0737622 + 526e979 commit abc9e84

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

bip-0119.mediawiki

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,21 +193,27 @@ specification for the semantics of OP_CHECKTEMPLATEVERIFY.
193193
Where
194194

195195
bool CheckDefaultCheckTemplateVerifyHash(const std::vector<unsigned char>& hash) {
196+
// note: for anti-DoS, a real implementation *must* cache parts of this computation
197+
// to avoid quadratic hashing DoS all variable length computations must be precomputed
198+
// including hashes of the scriptsigs, sequences, and outputs. See the section
199+
// "Denial of Service and Validation Costs" below.
196200
return GetDefaultCheckTemplateVerifyHash(current_tx, current_input_index) == uint256(hash);
197201
}
198202
199203
The hash is computed as follows:
200-
204+
// not DoS safe, for reference/testing!
201205
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, uint32_t input_index) {
202206
return GetDefaultCheckTemplateVerifyHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx), input_index);
203207
}
208+
// not DoS safe for reference/testing!
204209
uint256 GetDefaultCheckTemplateVerifyHash(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
205210
const uint32_t input_index) {
206211
bool skip_scriptSigs = std::find_if(tx.vin.begin(), tx.vin.end(),
207212
[](const CTxIn& c) { return c.scriptSig != CScript(); }) == tx.vin.end();
208213
return skip_scriptSigs ? GetDefaultCheckTemplateVerifyHashEmptyScript(tx, outputs_hash, sequences_hash, input_index) :
209214
GetDefaultCheckTemplateVerifyHashWithScript(tx, outputs_hash, sequences_hash, GetScriptSigsSHA256(tx), input_index);
210215
}
216+
// DoS safe, fixed length hash!
211217
uint256 GetDefaultCheckTemplateVerifyHashWithScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
212218
const uint256& scriptSig_hash, const uint32_t input_index) {
213219
auto h = CHashWriter(SER_GETHASH, 0)
@@ -221,6 +227,7 @@ The hash is computed as follows:
221227
<< input_index;
222228
return h.GetSHA256();
223229
}
230+
// DoS safe, fixed length hash!
224231
uint256 GetDefaultCheckTemplateVerifyHashEmptyScript(const CTransaction& tx, const uint256& outputs_hash, const uint256& sequences_hash,
225232
const uint32_t input_index) {
226233
auto h = CHashWriter(SER_GETHASH, 0)
@@ -512,6 +519,38 @@ unintentional introduction of the 'half spend' problem.
512519

513520
Templates, as restricted as they are, bear some risks.
514521

522+
====Denial of Service and Validation Costs====
523+
524+
CTV is designed to be able to be validated very cheaply without introducing DoS, either by checking a
525+
precomputed hash or computing a hash of fixed length arguments (some of which may be cached from more
526+
expensive computations).
527+
528+
In particular, CTV requires that clients cache the computation of a hash over all the scriptSigs, sequences,
529+
and outputs. Before CTV, the hash of the scriptSigs was not required. CTV also requires that the presence of
530+
any non-empty scriptSig be hashed, but this can be handled as a part of the scriptSigs hash.
531+
532+
As such, evaluating a CTV hash during consensus is always O(1) computation when the caches are available.
533+
These caches usually must be available due to similar issues in CHECKSIG behavior. Computing the caches
534+
is O(T) (the size of the transaction).
535+
536+
An example of a script that could experience an DoS issue without caching is:
537+
538+
```
539+
<H> CTV CTV CTV... CTV
540+
```
541+
542+
Such a script would cause the intepreter to compute hashes (supposing N CTV's) over O(N*T) data.
543+
If the scriptSigs non-nullity is not cached, then the O(T) transaction could be scanned over O(N)
544+
times as well (although cheaper than hashing, still a DoS). As such, CTV caches hashes and computations
545+
over all variable length fields in a transaction.
546+
547+
For CTV, the Denial-of-Service exposure and validation costs are relatively clear. Implementors must be careful
548+
to correctly code CTV to make use of existing caches and cache the (new for CTV) computations over scriptSigs.
549+
Other more flexible covenant proposals may have a more difficult time solving DoS issues as more complex computations may
550+
be less cacheable and expose issues around quadratic hashing, it is a tradeoff CTV makes in favor of cheap and secure
551+
validation at the expense of flexibility. For example, if CTV allowed the hashing only select outputs by a bitmask,
552+
caching of all combinations of outputs would not be possible and would cause a quadratic hashing DoS vulnerability.
553+
515554
====Permanently Unspendable Outputs====
516555

517556
The preimage argument passed to CHECKTEMPLATEVERIFY may be unknown or otherwise unsatisfiable.
@@ -603,6 +642,7 @@ Given the simplicity of this approach to implement and analyze, and the benefits
603642
applications, CHECKTEMPLATEVERIFY's template based approach is proposed in lieu of more complete
604643
covenants system.
605644

645+
606646
====Future Upgrades====
607647

608648
This section describes updates to OP_CHECKTEMPLATEVERIFY that are possible in

0 commit comments

Comments
 (0)