1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use num_traits::{One, Zero};

use crate::{CombineOperation, Operation};

pub trait Identity<T> {
    /*! Trait related to buffer gates. If the gate doesn't change its input value (ie adding zero,
    multiplying by one), then we say this is an "identity" gate, eligible to be folded out. !*/

    fn is_identity(&self) -> bool;

    /// Used to produce an identity gate on the current field when needed.
    fn identity(w_out: usize, w_in: usize) -> Self;
}

// /// Rustc won't let us use any generics here because `bool` might implement Zero and One in
// /// the future (though it currently doesn't) and also won't allow us to rectify this problem
// /// ourselves by just implementing it locally, since it's a foreign trait. Cursed.
// impl<T: Zero + One + WireValue> Identity for Operation<T>{
//     fn is_identity(&self) -> bool {
//         match self {
//             Operation::AddConst(_, _, c) => {c.is_zero()}
//             Operation::SubConst(_, _, c) => {c.is_zero()}
//             Operation::MulConst(_, _, c) => {c.is_one()}
//             _ => {false}
//         }
//     }
// }

impl Identity<u64> for Operation<u64> {
    fn is_identity(&self) -> bool {
        match self {
            Operation::AddConst(_, _, c) => c.is_zero(),
            Operation::SubConst(_, _, c) => c.is_zero(),
            Operation::MulConst(_, _, c) => c.is_one(),
            _ => false,
        }
    }

    fn identity(w_out: usize, w_in: usize) -> Self {
        Self::AddConst(w_out, w_in, 0u64)
    }
}

impl Identity<bool> for Operation<bool> {
    fn is_identity(&self) -> bool {
        match *self {
            Operation::AddConst(_, _, c) => !c,
            Operation::SubConst(_, _, c) => !c,
            Operation::MulConst(_, _, c) => c,
            _ => false,
        }
    }

    fn identity(w_out: usize, w_in: usize) -> Self {
        Self::AddConst(w_out, w_in, false)
    }
}

impl Identity<u64> for CombineOperation {
    fn is_identity(&self) -> bool {
        match self {
            Self::Z64(g) => g.is_identity(),
            _ => false,
        }
    }

    fn identity(w_out: usize, w_in: usize) -> Self {
        Self::Z64(Operation::identity(w_out, w_in))
    }
}

impl Identity<bool> for CombineOperation {
    fn is_identity(&self) -> bool {
        match self {
            Self::GF2(g) => g.is_identity(),
            _ => false,
        }
    }

    fn identity(w_out: usize, w_in: usize) -> Self {
        Self::GF2(Operation::identity(w_out, w_in))
    }
}