|
| 1 | +//! The #1698 exploit, as a compile-fail proof. |
| 2 | +//! |
| 3 | +//! Authorize an honest-looking ONE-MOJO description, then sign a spend of a BILLION mojos. Under |
| 4 | +//! dig-account 0.1.2 this compiled and both steps succeeded: the gate judged a `SpendSummary` while |
| 5 | +//! the signer signed `&[CoinSpend]`, and nothing connected the two. |
| 6 | +//! |
| 7 | +//! The property under test is the SHAPE, not a rejection. A regression test asserting `is_err()` |
| 8 | +//! would pass equally against a patched digest comparison — and would keep passing if that comparison |
| 9 | +//! were later moved, mis-scoped, or fed the wrong bytes. Only non-compilation pins that there are no |
| 10 | +//! longer two values that could disagree. |
| 11 | +//! |
| 12 | +//! Both halves of the exploit fail independently: |
| 13 | +//! 1. `authorize_op` no longer accepts a description at all — it takes the spends. |
| 14 | +//! 2. no signing method accepts loose coin spends, so there is nothing to sign them with. |
| 15 | +
|
| 16 | +use chia_protocol::CoinSpend; |
| 17 | +use dig_account::{MoneySigner, PolicyAuthorizer, SpendOpClass, SpendRecipient, SpendSummary, SpendTier}; |
| 18 | + |
| 19 | +fn exploit<S: MoneySigner>(gate: &PolicyAuthorizer, signer: &S, real_spends: &[CoinSpend]) { |
| 20 | + // A hand-built description of a one-mojo tip to a stranger. |
| 21 | + let honest_looking = SpendSummary::new( |
| 22 | + SpendTier::AutoSend, |
| 23 | + vec![SpendRecipient { |
| 24 | + address: "xch1qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq".to_string(), |
| 25 | + amount_mojos: 1, |
| 26 | + asset_id: None, |
| 27 | + }], |
| 28 | + 0, |
| 29 | + ); |
| 30 | + |
| 31 | + // (1) The gate will not judge a description. |
| 32 | + let _ = gate.authorize_op(&honest_looking, SpendOpClass::Tip); |
| 33 | + |
| 34 | + // (2) And nothing will sign the real, billion-mojo spends. |
| 35 | + let _ = signer.sign_coin_spends(real_spends); |
| 36 | +} |
| 37 | + |
| 38 | +fn main() {} |
0 commit comments