logicaffeine_proof/revgate.rs
1//! Certify reversible logic gates as bijections.
2//!
3//! The Silicon tier maps each VM stencil family to a functional unit,
4//! and the adiabatic datapath demands those units be reversible. A unit over `n` bits is reversible
5//! iff its truth table is a permutation of `{0..2ⁿ}` — a bijection whose inverse is the inverse
6//! permutation, i.e. a real constructive reverse gate. A purely-linear (CNOT/XOR) block is reversible
7//! iff its GF(2) transfer matrix is invertible (`∈ GL(n,2)`) — reused from [`crate::gf2`].
8//!
9//! This is the hardware-gate complement to the software-level Z3 bijectivity proofs in
10//! `logicaffeine_synth::reversible`: there the abelian `Rev*` opcodes are proved bijective as BV64
11//! maps; here the universal reversible generators they compile to — CNOT (the `BitXor→CNOT`
12//! embedding), Toffoli (the `BitAnd→Toffoli` embedding), and Fredkin — are certified as gates.
13
14use crate::gf2::is_invertible_gf2;
15
16/// A reversibility certificate for a functional unit.
17#[derive(Debug, PartialEq, Eq)]
18pub enum GateCert {
19 /// Reversible: `inverse[output] = input`, the constructive reverse gate (itself a truth table).
20 Reversible { inverse: Vec<usize> },
21 /// Irreversible: two distinct inputs collide to the same output — information is erased (the
22 /// Landauer cost the adiabatic tier forbids). Carries the witnessing collision.
23 Collision {
24 input_a: usize,
25 input_b: usize,
26 output: usize,
27 },
28}
29
30/// Certify an `n`-bit functional unit from its truth table (`table[input] = output`, each a state
31/// index `0..2ⁿ`). Reversible iff the table is a permutation; returns the inverse gate, or the first
32/// erasing collision that proves it is not.
33pub fn certify_gate(n: u32, table: &[usize]) -> GateCert {
34 let size = 1usize << n;
35 assert_eq!(
36 table.len(),
37 size,
38 "an n-bit truth table must have exactly 2^n rows"
39 );
40 let mut inverse = vec![usize::MAX; size];
41 for (input, &output) in table.iter().enumerate() {
42 assert!(
43 output < size,
44 "truth-table output {output} out of range for {n} bits"
45 );
46 if inverse[output] != usize::MAX {
47 // A second input mapping to `output` means the map is not injective — it erases.
48 return GateCert::Collision {
49 input_a: inverse[output],
50 input_b: input,
51 output,
52 };
53 }
54 inverse[output] = input;
55 }
56 GateCert::Reversible { inverse }
57}
58
59/// CNOT (2-bit): `(a,b) ↦ (a, a⊕b)`, state encoded `a | b<<1`. The universal reversible XOR
60/// generator — `RevXor` lifted to a gate.
61pub fn cnot() -> Vec<usize> {
62 (0..4)
63 .map(|s| {
64 let (a, b) = (s & 1, (s >> 1) & 1);
65 a | ((a ^ b) << 1)
66 })
67 .collect()
68}
69
70/// Toffoli / CCNOT (3-bit): `(a,b,c) ↦ (a, b, c⊕(a∧b))`. The universal reversible AND generator.
71pub fn toffoli() -> Vec<usize> {
72 (0..8)
73 .map(|s| {
74 let (a, b, c) = (s & 1, (s >> 1) & 1, (s >> 2) & 1);
75 a | (b << 1) | ((c ^ (a & b)) << 2)
76 })
77 .collect()
78}
79
80/// Fredkin / CSWAP (3-bit): swap `b` and `c` when `a = 1`. Conserves 1-count; self-inverse.
81pub fn fredkin() -> Vec<usize> {
82 (0..8)
83 .map(|s| {
84 let (a, b, c) = (s & 1, (s >> 1) & 1, (s >> 2) & 1);
85 let (b2, c2) = if a == 1 { (c, b) } else { (b, c) };
86 a | (b2 << 1) | (c2 << 2)
87 })
88 .collect()
89}
90
91/// Certify a purely-LINEAR `n`-bit block reversible: its GF(2) transfer matrix (`rows[v]` a bitmask
92/// of which input bits XOR into output bit `v`) must be invertible (`∈ GL(n,2)`), giving a linear
93/// inverse. This is the fast path for CNOT-only (XOR) datapaths.
94pub fn certify_linear(n: u32, rows: &[u64]) -> bool {
95 is_invertible_gf2(n, rows)
96}
97
98#[cfg(test)]
99#[path = "../../logicaffeine_tests/unit/logicaffeine_proof/revgate/tests.rs"]
100mod tests;