Skip to main content

zk_scribble/
mutation.rs

1use crate::target::Target;
2
3/// A trace tamper. `Clone + Debug` are
4/// required for proptest shrinking output.
5#[derive(Clone, Debug, PartialEq, Eq)]
6pub enum Mutation {
7    /// XOR `mask` (truncated to column width)
8    /// into a single cell.
9    BitFlip {
10        target: Target,
11        col: usize,
12        row: usize,
13        mask: u128,
14    },
15
16    /// Inject a value the AIR packing
17    /// accepts but range-checks must reject.
18    OutOfBounds {
19        target: Target,
20        col: usize,
21        row: usize,
22        value: u128,
23    },
24
25    /// Toggle a `Bit` cell. Targets
26    /// must be `Bit`-typed columns.
27    FlipSelector {
28        target: Target,
29        col: usize,
30        row: usize,
31    },
32
33    /// Swap every column between two rows.
34    SwapRows {
35        target: Target,
36        row_a: usize,
37        row_b: usize,
38    },
39
40    /// Dispatch-swap primitive:
41    /// rearrange data while leaving the columns
42    /// outside `cols` (selectors, RAM bindings)
43    /// in place.
44    SwapColumns {
45        target: Target,
46        cols: Vec<usize>,
47        row_a: usize,
48        row_b: usize,
49    },
50
51    /// Char-2 duplication:
52    /// copy every column of `src_row` onto `dst_row`.
53    DuplicateRow {
54        target: Target,
55        src_row: usize,
56        dst_row: usize,
57    },
58    CopyColumns {
59        target: Target,
60        cols: Vec<usize>,
61        src_row: usize,
62        dst_row: usize,
63    },
64
65    /// Overwrite every row of `col` with the
66    /// same `value` (truncated to column width).
67    /// Catches "column should be non-trivial
68    /// somewhere" gaps the row-local AIR misses.
69    ColumnUniformWrite {
70        target: Target,
71        col: usize,
72        value: u128,
73    },
74
75    /// Zero every cell in the cross product
76    /// of `rows` and `cols`. Catches padding-
77    /// block forgeries and trace-tail filler.
78    RowSegmentZero {
79        target: Target,
80        rows: Vec<usize>,
81        cols: Vec<usize>,
82    },
83
84    /// Replace `col` with `base + i * step`
85    /// at row `i` (truncated to column width).
86    /// Catches CLK rewinds, address-sorted-
87    /// permutation forgeries, monotonic-counter
88    /// bypasses.
89    MonotonicReplace {
90        target: Target,
91        col: usize,
92        base: u128,
93        step: u128,
94    },
95
96    /// Apply mutations as one tamper.
97    /// Enables coordinated cross-trace
98    /// (chiplet + main) attacks the
99    /// per-table checks alone cannot catch.
100    Compound(Vec<Mutation>),
101}
102
103/// Layer-1 (proptest-discoverable) variants.
104/// `SwapColumns`, `CopyColumns`, and `Compound`
105/// are excluded, their search space defeats
106/// random discovery.
107#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
108pub enum MutationKind {
109    BitFlip,
110    OutOfBounds,
111    FlipSelector,
112    SwapRows,
113    DuplicateRow,
114    ColumnUniformWrite,
115    RowSegmentZero,
116    MonotonicReplace,
117}
118
119impl Mutation {
120    /// `Some` for Layer-1 variants;
121    /// `None` for `SwapColumns`, `CopyColumns`,
122    /// and `Compound` (Layer 2, hand-crafted only).
123    pub fn kind(&self) -> Option<MutationKind> {
124        match self {
125            Mutation::BitFlip { .. } => Some(MutationKind::BitFlip),
126            Mutation::OutOfBounds { .. } => Some(MutationKind::OutOfBounds),
127            Mutation::FlipSelector { .. } => Some(MutationKind::FlipSelector),
128            Mutation::SwapRows { .. } => Some(MutationKind::SwapRows),
129            Mutation::DuplicateRow { .. } => Some(MutationKind::DuplicateRow),
130            Mutation::ColumnUniformWrite { .. } => Some(MutationKind::ColumnUniformWrite),
131            Mutation::RowSegmentZero { .. } => Some(MutationKind::RowSegmentZero),
132            Mutation::MonotonicReplace { .. } => Some(MutationKind::MonotonicReplace),
133            Mutation::SwapColumns { .. } | Mutation::CopyColumns { .. } | Mutation::Compound(_) => {
134                None
135            }
136        }
137    }
138}