Consensus Cleanup BIP draft #1800

pull darosior wants to merge 1 commits into bitcoin:master from darosior:consensus_cleanup changing 1 files +207 −0
  1. darosior commented at 5:22 pm on March 26, 2025: member

    This is a BIP draft for a Consensus Cleanup soft fork.

    This proposal builds upon Matt Corallo’s 2019 proposal, which i set to revive at the end of 2023. I eventually shared my research in a Delving Bitcoin post in early 2024 (along with a semi-private companion post for the redacted sensitive details). A number of people contributed ideas, testing and otherwise fruitful discussion. This led to settling on a list of mitigations, which i updated the mailing list about in February 2025.

    I think it’s now ready to be officially published as a BIP.

  2. Consensus Cleanup BIP draft 098894f04f
  3. jonatack added the label New BIP on Mar 26, 2025
  4. in bip-cc.md:14 in 098894f04f
     9+  Type: Standards Track
    10+  Created: 2025-03-17
    11+  License: CC0-1.0
    12+```
    13+
    14+# Abstract
    


    vostrnad commented at 8:17 pm on March 26, 2025:

    (applies to the other headings as well)

    0## Abstract
    
  5. in bip-cc.md:18 in 098894f04f
    13+
    14+# Abstract
    15+
    16+Introduce new consensus rules in order to fix the timewarp attack, reduce the worst case block
    17+validation, prevent Merkle tree weaknesses and avoid duplicate transactions without
    18+[bip-0030][BIP30] validation.
    


    vostrnad commented at 8:17 pm on March 26, 2025:

    The abstract should usually start with “This BIP/document proposes/introduces…”, something like:

    0This document proposes changes to consensus rules in order to fix the timewarp attack, reduce the worst case block
    1validation time, prevent Merkle tree weaknesses and avoid duplicate transactions without
    2[bip-0030][BIP30] validation.
    
  6. in bip-cc.md:22 in 098894f04f
    17+validation, prevent Merkle tree weaknesses and avoid duplicate transactions without
    18+[bip-0030][BIP30] validation.
    19+
    20+# Motivation
    21+
    22+This proposal addresses a number of long standing vulnerabilities and weaknesses in the Bitcoin
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0This proposal addresses a number of long-standing vulnerabilities and weaknesses in the Bitcoin
    
  7. in bip-cc.md:23 in 098894f04f
    18+[bip-0030][BIP30] validation.
    19+
    20+# Motivation
    21+
    22+This proposal addresses a number of long standing vulnerabilities and weaknesses in the Bitcoin
    23+protocol. Bundling those fixes together allows to overcome the fixed cost of deploying a Bitcoin
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0protocol. Bundling these fixes together allows to overcome the fixed cost of deploying a Bitcoin
    
  8. in bip-cc.md:26 in 098894f04f
    21+
    22+This proposal addresses a number of long standing vulnerabilities and weaknesses in the Bitcoin
    23+protocol. Bundling those fixes together allows to overcome the fixed cost of deploying a Bitcoin
    24+soft fork.
    25+
    26+The timewarp bug permits a majority hashrate attacker to arbitrarily increase the block rate,
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    A bullet list might be better than paragraphs for describing the individual vulnerabilities.

    Sjors commented at 9:28 am on March 27, 2025:
    Agreed, at least something to guide the reader when the topic changes.
  9. in bip-cc.md:37 in 098894f04f
    32+of short-sighted miners as well as short-sighted users to exploit this vulnerability in a small
    33+enough proportion to increase the block rate without fatally hurting the network, as the effectively
    34+increased block space would - all others things equal - bring fee rates down for users.
    35+
    36+Specially crafted blocks may be expensive to process, with validation times ranging from a few
    37+minutes up to more than a hour on lower end devices. Long block validation times are a nuisance to
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0minutes up to more than an hour on lower-end devices. Long block validation times are a nuisance to
    
  10. in bip-cc.md:40 in 098894f04f
    35+
    36+Specially crafted blocks may be expensive to process, with validation times ranging from a few
    37+minutes up to more than a hour on lower end devices. Long block validation times are a nuisance to
    38+users, increasing the cost to independently fully validate the consensus rules. In addition they can
    39+be used by miners to attack their competition, creating perverse incentives, centralization
    40+pressures and reduced network security.
    


    vostrnad commented at 8:17 pm on March 26, 2025:

    This sentence needs improving, how about:

    0be used by miners to attack their competition, creating perverse incentives and centralization
    1pressures and reducing network security.
    
  11. in bip-cc.md:42 in 098894f04f
    37+minutes up to more than a hour on lower end devices. Long block validation times are a nuisance to
    38+users, increasing the cost to independently fully validate the consensus rules. In addition they can
    39+be used by miners to attack their competition, creating perverse incentives, centralization
    40+pressures and reduced network security.
    41+
    42+In computing a block's Merkle root, a 64 bytes transaction can be interpreted as an intermediate
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0In computing a block's Merkle root, a 64-byte transaction can be interpreted as an intermediate
    
  12. in bip-cc.md:44 in 098894f04f
    39+be used by miners to attack their competition, creating perverse incentives, centralization
    40+pressures and reduced network security.
    41+
    42+In computing a block's Merkle root, a 64 bytes transaction can be interpreted as an intermediate
    43+node in the tree in addition to a leaf. This makes it possible to fake inclusion proofs by
    44+pretending a 64 bytes block transaction is an inner node, as well as to pretend the inner nodes on
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0pretending a 64-byte block transaction is an inner node, as well as to pretend the inner nodes on
    
  13. in bip-cc.md:51 in 098894f04f
    46+
    47+Since [bip-0034][BIP34] activation, explicit [bip-0030][BIP30] validation is not necessary until
    48+block height 1,983,702[^0].  Mandating new coinbase transactions be different from the early
    49+[bip-0034][BIP34] violations makes it possible to get rid of [bip-0030][BIP30] validation forever.
    50+Besides its unnecessary cost, another downside of [bip-0030][BIP30] validation is that it cannot be
    51+performed by Utreexo clients. Finally, leveraging the coinbase transaction's `nLockTime` field
    


    vostrnad commented at 8:17 pm on March 26, 2025:

    utreexo is usually not capitalized:

    0performed by utreexo clients. Finally, leveraging the coinbase transaction's `nLockTime` field
    
  14. in bip-cc.md:53 in 098894f04f
    48+block height 1,983,702[^0].  Mandating new coinbase transactions be different from the early
    49+[bip-0034][BIP34] violations makes it possible to get rid of [bip-0030][BIP30] validation forever.
    50+Besides its unnecessary cost, another downside of [bip-0030][BIP30] validation is that it cannot be
    51+performed by Utreexo clients. Finally, leveraging the coinbase transaction's `nLockTime` field
    52+allows applications to recover the block height corresponding to a coinbase transaction without
    53+having to parse Bitcoin Script.
    


    vostrnad commented at 8:17 pm on March 26, 2025:

    The “Bitcoin” disambiguation is definitely not needed here:

    0having to parse Script.
    
  15. in bip-cc.md:59 in 098894f04f
    54+
    55+# Specification
    56+
    57+For all blocks after activation the following new rules apply.
    58+
    59+Given a block at height `N`:
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    Just like in the previous section, a bullet list might be better than paragraphs for describing the individual fixes. (see also the original consensus cleanup draft for formatting)
  16. in bip-cc.md:60 in 098894f04f
    55+# Specification
    56+
    57+For all blocks after activation the following new rules apply.
    58+
    59+Given a block at height `N`:
    60+- if `N % 2016` is equal to `0` the `nTime` field of the block must be set to a value higher than or
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    Not all implementation call the timestamp nTime, so just calling it “timestamp” might be preferable.
  17. in bip-cc.md:73 in 098894f04f
    68+scriptSig and previous output's scriptPubKey, including the P2SH redeemScript. If the total is
    69+strictly higher than `2500`, the transaction is invalid. The accounting is the same as for
    70+[bip-0016][BIP16 specs]: a `CHECKSIG` operation accounts for `1` and a `CHECKMULTISIG` accounts for
    71+the number of public keys associated, or `20` if the number of public keys is greater than `16`. A
    72+`CHECKMULTISIG` not directly preceded by a minimally-pushed number between `1` and `16` (included)
    73+accounts for `20`.
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    This should probably be rewritten, as it first introduces one accounting method (count the number of CHECKSIG and CHECKMULTISIG and check if the count is less than or equal to 2500) and only then changes the accounting for CHECKMULTISIG.
  18. in bip-cc.md:83 in 098894f04f
    78+and its `nSequence` field must not be equal to `0xffffffff`.
    79+
    80+# Rationale
    81+
    82+The restrictions on the timestamp of the first and last blocks of a difficulty adjustment period fix
    83+the timewarp and Murch-Zawy vulnerabilities[^3]. The latter poses mostly theoretical concerns but is
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0the timewarp and Murch–Zawy vulnerabilities[^3]. The latter poses mostly theoretical concerns but is
    
  19. in bip-cc.md:86 in 098894f04f
    81+
    82+The restrictions on the timestamp of the first and last blocks of a difficulty adjustment period fix
    83+the timewarp and Murch-Zawy vulnerabilities[^3]. The latter poses mostly theoretical concerns but is
    84+extremely low risk to fix: the duration of an adjustment period has never been, and should never be,
    85+negative. The former is fixed by preventing the timestamp of the first block of a difficulty period
    86+to be lower than the previous block's, with a two hours grace period. A [previous
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0from being lower than the previous block's, with a two-hour grace period. A [previous
    
  20. in bip-cc.md:87 in 098894f04f
    82+The restrictions on the timestamp of the first and last blocks of a difficulty adjustment period fix
    83+the timewarp and Murch-Zawy vulnerabilities[^3]. The latter poses mostly theoretical concerns but is
    84+extremely low risk to fix: the duration of an adjustment period has never been, and should never be,
    85+negative. The former is fixed by preventing the timestamp of the first block of a difficulty period
    86+to be lower than the previous block's, with a two hours grace period. A [previous
    87+proposal][BIP-XXXX] to fix timewarp used a ten minutes grace period instead, also adopted for
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0proposal][BIP-XXXX] to fix timewarp used a ten-minute grace period instead, also adopted for
    
  21. in bip-cc.md:89 in 098894f04f
    84+extremely low risk to fix: the duration of an adjustment period has never been, and should never be,
    85+negative. The former is fixed by preventing the timestamp of the first block of a difficulty period
    86+to be lower than the previous block's, with a two hours grace period. A [previous
    87+proposal][BIP-XXXX] to fix timewarp used a ten minutes grace period instead, also adopted for
    88+[testnet4][BIP94 timewarp]. Out of an abundance of caution and because it only trivially worsens the
    89+block rate increase under attack, a two hours grace period is used here[^4].
    


    vostrnad commented at 8:17 pm on March 26, 2025:
    0block rate increase under attack, a two-hour grace period is used here[^4].
    
  22. in bip-cc.md:102 in 098894f04f
     97+Such a limit reduces the worst case block validation time by a factor of 40 and drastically
     98+increases the preparation cost of an attack to make it uneconomical for a miner[^6]. The `2500`
     99+value was chosen as the tightest value that did not make any non-pathological standard transaction
    100+invalid[^7].
    101+
    102+In the presence of 64 bytes transactions a block header's Merkle root may be valid for different
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0In the presence of 64-byte transactions a block header's Merkle root may be valid for different
    
  23. in bip-cc.md:103 in 098894f04f
     98+increases the preparation cost of an attack to make it uneconomical for a miner[^6]. The `2500`
     99+value was chosen as the tightest value that did not make any non-pathological standard transaction
    100+invalid[^7].
    101+
    102+In the presence of 64 bytes transactions a block header's Merkle root may be valid for different
    103+sets of transactions. This is because in the Merkle tree construction a 64 bytes transaction may be
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0sets of transactions. This is because in the Merkle tree construction a 64-byte transaction may be
    
  24. in bip-cc.md:104 in 098894f04f
     99+value was chosen as the tightest value that did not make any non-pathological standard transaction
    100+invalid[^7].
    101+
    102+In the presence of 64 bytes transactions a block header's Merkle root may be valid for different
    103+sets of transactions. This is because in the Merkle tree construction a 64 bytes transaction may be
    104+interpreted as the catenation of two 32 bytes hashes, or the catenation of two 32 bytes hashes may
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0interpreted as the catenation of two 32-byte hashes, or the catenation of two 32-byte hashes may
    
  25. in bip-cc.md:107 in 098894f04f
    102+In the presence of 64 bytes transactions a block header's Merkle root may be valid for different
    103+sets of transactions. This is because in the Merkle tree construction a 64 bytes transaction may be
    104+interpreted as the catenation of two 32 bytes hashes, or the catenation of two 32 bytes hashes may
    105+be interpreted as a transaction. The former allows to fake a block inclusion proof and the latter
    106+makes it such that for a valid block the Merkle root in the block header is not a unique identifier
    107+for the corresponding list of valid transactions[^8]. 64 bytes transactions can only contain an
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0for the corresponding list of valid transactions[^8]. 64-byte transactions can only contain an
    
  26. in bip-cc.md:108 in 098894f04f
    103+sets of transactions. This is because in the Merkle tree construction a 64 bytes transaction may be
    104+interpreted as the catenation of two 32 bytes hashes, or the catenation of two 32 bytes hashes may
    105+be interpreted as a transaction. The former allows to fake a block inclusion proof and the latter
    106+makes it such that for a valid block the Merkle root in the block header is not a unique identifier
    107+for the corresponding list of valid transactions[^8]. 64 bytes transactions can only contain an
    108+output Script that lets anyone spend the funds, or burns them.  They have also been non-standard for
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0output script that lets anyone spend the funds, or burns them.  They have also been non-standard for
    

    Sjors commented at 9:56 am on March 27, 2025:

    64 bytes transactions can only contain an output Script that lets anyone spend the funds, or burns them.

    It would be good to elaborate on these two specific claims.

    If you can additionally demonstrate that any 64 byte transaction is (“third party”) malleable in a way that adds or removes a byte, then that would completely alleviate any concerns about confiscatory surface.


    Sjors commented at 10:35 am on March 27, 2025:

    @Christewart’s draft BIP seems to to make the claim that this is indeed the case:

    Pre-segwit 64-byte transactions that spend a nonstandard utxo that are inherently malleable.

    https://github.com/Christewart/bips/blob/2024-12-20-64bytetxs/bip-XXXX.mediawiki#pre-segwit-64-byte-transactions

    I don’t fully understand the reasoning though.


  27. in bip-cc.md:111 in 098894f04f
    106+makes it such that for a valid block the Merkle root in the block header is not a unique identifier
    107+for the corresponding list of valid transactions[^8]. 64 bytes transactions can only contain an
    108+output Script that lets anyone spend the funds, or burns them.  They have also been non-standard for
    109+6 years at the time this is written. It was suggested the known vulnerabilities could instead be
    110+mitigated by committing to the Merkle tree depth in the header's version field[^9]. The authors
    111+believe it is preferable to address the root cause by invalidating 64 bytes transactions. This
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0believe it is preferable to address the root cause by invalidating 64-byte transactions. This
    
  28. in bip-cc.md:115 in 098894f04f
    110+mitigated by committing to the Merkle tree depth in the header's version field[^9]. The authors
    111+believe it is preferable to address the root cause by invalidating 64 bytes transactions. This
    112+approach also fixes the vulnerability without developers of SPV verifiers having to implement the
    113+mitigation or to know it is necessary in the first place.
    114+
    115+Several blocks prior to [bip-0034][BIP34] activation contain a coinbase transaction such as its
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0Several blocks prior to [bip-0034][BIP34] activation contain a coinbase transaction whose
    
  29. in bip-cc.md:154 in 098894f04f
    149+[^1]: Technically this limit *cannot* apply to a coinbase transaction as the size of its sole
    150+input's scriptSig is limited.
    151+[^2]: The locktime validation, which is also performed for coinbase transactions, enforces that the
    152+nLockTime value is the last block at which a transaction is invalid, not the first one at which it
    153+is valid.
    154+[^3]: The timewarp attack is described [here][SE timewarp] and the Murch-Zawy attack [here][Delving
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0[^3]: The timewarp attack is described [here][SE timewarp] and the Murch–Zawy attack [here][Delving
    
  30. in bip-cc.md:174 in 098894f04f
    169+[^7]: A non-pathological transaction would have a public key per signature operation and at least
    170+one signature per input. Per standardness a single P2SH input may not have more than 15 signature
    171+operations. Even by using 1-of-15 `CHECKMULTISIG`s a transaction would bump against the maximum
    172+standard transaction size before running into the newly introduced limit. To run against the newly
    173+introduced limit but not the transaction size a transaction would need to spend P2SH inputs with a
    174+redeem script similar to `CHECKSIG DROP CHECKSIG DROP ..`. This type of redeem script serves no
    


    vostrnad commented at 8:18 pm on March 26, 2025:
    0redeem script similar to `CHECKSIG DROP CHECKSIG DROP ...`. This type of redeem script serves no
    
  31. vostrnad commented at 8:19 pm on March 26, 2025: contributor
    First pass of review, mostly copy editing suggestions so far.
  32. in bip-cc.md:61 in 098894f04f
    56+
    57+For all blocks after activation the following new rules apply.
    58+
    59+Given a block at height `N`:
    60+- if `N % 2016` is equal to `0` the `nTime` field of the block must be set to a value higher than or
    61+  equal to the value of the `nTime` field of block at height `N-1` minus `7200`;
    


    mzumsande commented at 9:13 pm on March 26, 2025:
    Maybe reword this to make it clearer that minus 7200 is subtracted from the value of nTime, and not from height N-1 (so that no one unfamiliar with the context could read it as “block at height N - 7201”).
  33. in bip-cc.md:65 in 098894f04f
    60+- if `N % 2016` is equal to `0` the `nTime` field of the block must be set to a value higher than or
    61+  equal to the value of the `nTime` field of block at height `N-1` minus `7200`;
    62+- if `N % 2016` is equal to `2015` the `nTime` field of the block must be set to a value higher than
    63+  or equal to the value of the `nTime` field of block at height `N-2015`.
    64+
    65+A limit is set on the number of potentially executed signature operations in validating a
    


    Sjors commented at 9:35 am on March 27, 2025:

    Maybe:

    … in validating the inputs of a transaction.

    And then explain the coinbase exception:

    [^1]: The scriptSig of a coinbase input is not executed. Even if it were, its size is constrained such that the limit introduced in this BIP can’t be reached.

  34. in bip-cc.md:68 in 098894f04f
    63+  or equal to the value of the `nTime` field of block at height `N-2015`.
    64+
    65+A limit is set on the number of potentially executed signature operations in validating a
    66+transaction. It applies to all transactions in the block except the coinbase transaction[^1]. For
    67+each input in the transaction, count the number of `CHECKSIG` and `CHECKMULTISIG` in the input
    68+scriptSig and previous output's scriptPubKey, including the P2SH redeemScript. If the total is
    


    Sjors commented at 9:42 am on March 27, 2025:

    Let’s also explictly state that, unlike sigops accounting:

    1. The witness is ignored
    2. There is no 4x adjustment for non-segwit, because of (1)

    I assume you also want to include OP_CHECKSIGVERIFY and OP_CHECKMULTISIGVERIFY, even though they require actually valid signatures to keep going.

  35. in bip-cc.md:130 in 098894f04f
    125+# Backward compatibility
    126+
    127+This proposal only tightens the block validation rules: there is no block that is valid under the
    128+rules proposed in this BIP but not under the existing Bitcoin consensus rules. As a consequence
    129+these changes are backward-compatible with unupgraded node software. That said, the authors strongly
    130+encourage node operators to upgrade in order to fully validate all consensus rules.
    


    Sjors commented at 10:09 am on March 27, 2025:

    You should elaborate on the changes miners SHOULD and MUST make. Either in this section or one specifically for miners.

    • “MUST” in order to avoid accidentally producing an invalid block under the new rules
    • “SHOULD” to avoid accidentally producing an invalid block under the current rules, as well to ensure that they only have to upgrade their node software when the fork activates.

    They MUST run software that respects the mintime field of getblocktemplate (BIP 22 / 33) at the time of activation. They SHOULD do so already

    They SHOULD run node software that sets mintime in a way that doesn’t violate the timewarp rule, i.e. Bitcoin Core >= v29.

    They MUST set nLockTime in their coinbase transactions once the rule takes effect. They MAY or SHOULD (?) do it earlier.

    They MUST run bitcoin node software that considers 64 byte transactions non-standard (e.g. Bitcoin Core > v?).

    They MUST run bitcoin node software with standardness rules that already effectively enforce the new sigop restriction.

    If they mine non-standard transactions, they MUST carefully consider the risks.

  36. Sjors commented at 10:22 am on March 27, 2025: member

    Concept ACK on the timewarp and Murch-Zawy fix, as well as the 64 byte transaction ban.

    I still need to think about the worst case validation fix more, though the approach seems reasonable.

    With respect to the nLockTime change, I need to get a sense of what pool software should take into account, especially since Bitoin Core does not construct the coinbase transaction.

    We don’t strictly need this change until height 1,983,702, but it seems better to enforce it at the same time as the rest of these changes. Otherwise we might end up with accidental forks several decades from now with nobody remembering this BIP.

    I also still need to see and study the implementation(s), outside the timewarp fix, which I’m fairly familiar with by now.

  37. in bip-cc.md:156 in 098894f04f
    151+[^2]: The locktime validation, which is also performed for coinbase transactions, enforces that the
    152+nLockTime value is the last block at which a transaction is invalid, not the first one at which it
    153+is valid.
    154+[^3]: The timewarp attack is described [here][SE timewarp] and the Murch-Zawy attack [here][Delving
    155+Murch-Zawy].
    156+[^4]: A bug in testnet4 pushed blocks' timestamps in the future when exploited, revealing how some
    


    fjahr commented at 4:00 pm on March 27, 2025:
    nit: FWIW, the min-difficulty blocks were definitely a feature, requested to be kept around from Testnet3 in the Testnet4 PR (here, here) and specified in the BIP. Instead of exploited I would say “overused” or “maxed out”
  38. in bip-cc.md:55 in 098894f04f
    50+Besides its unnecessary cost, another downside of [bip-0030][BIP30] validation is that it cannot be
    51+performed by Utreexo clients. Finally, leveraging the coinbase transaction's `nLockTime` field
    52+allows applications to recover the block height corresponding to a coinbase transaction without
    53+having to parse Bitcoin Script.
    54+
    55+# Specification
    


    fjahr commented at 4:06 pm on March 27, 2025:
    I agree with @Christewart on the ML that it would be better to have this split up into multiple BIPs. If you decide to keep it as one BIP you should probably number the new rules so they can be more easily referenced. This is something that was requested of BIP94 in #1782 as well.

    darosior commented at 2:41 pm on March 28, 2025:
    As i replied on the mailing list thread, i am not going to split this BIP into parts as i think it would unnecessarily increase overhead and could impede progress. I am happy to assign numbers to the rules though, if you find it makes them easier to be referenced.
  39. ariard commented at 10:07 pm on March 28, 2025: none

    There might be a problem with the math in this BIP.

    Exposing said problem clearly might be a $5k a day wreck the whole LN style of exploit.

    Asking for a friend who is curious on how to handle said problem.

  40. darosior commented at 4:43 pm on March 30, 2025: member
    @ariard i made sure you are on the private thread, if you want to discuss potentially sensitive details please do so there. Alternatively feel free to contact me privately.

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-03-31 20:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me