1#[macro_use]
12extern crate variant_count;
13
14use num_traits::Zero;
15use rand::distributions::{Distribution, Standard};
16use rand::Rng;
17use serde::{Deserialize, Serialize};
18
19pub use eval::{dump_vcd, evaluate_composite_program, largest_wires, smallest_wires, VcdDumper};
20pub use has_const::HasConst;
21pub use has_io::HasIO;
22pub use identity::Identity;
23pub use parsers::Parse;
24pub use translatable::Translatable;
25
26mod analysis;
27mod eval;
28pub mod exporters;
29mod has_const;
30mod has_io;
31mod identity;
32mod io_extractors;
33pub mod parsers;
34mod tests;
35mod translatable;
36
37pub trait WireValue: Copy + PartialEq + std::fmt::Debug + Serialize {
40 fn is_zero(&self) -> bool;
41
42 fn to_le_bytes(&self) -> [u8; 8];
43}
44
45impl WireValue for bool {
46 fn is_zero(&self) -> bool {
47 !*self
48 }
49
50 fn to_le_bytes(&self) -> [u8; 8] {
51 [if *self { 1u8 } else { 0u8 }, 0, 0, 0, 0, 0, 0, 0]
52 }
53}
54
55impl WireValue for u64 {
56 fn is_zero(&self) -> bool {
57 Zero::is_zero(self)
58 }
59
60 fn to_le_bytes(&self) -> [u8; 8] {
61 u64::to_le_bytes(*self)
62 }
63}
64
65#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, VariantCount)]
67pub enum Operation<T: WireValue> {
68 Input(usize),
70 Random(usize),
72 Add(usize, usize, usize),
74 AddConst(usize, usize, T),
76 Sub(usize, usize, usize),
78 SubConst(usize, usize, T),
80 Mul(usize, usize, usize),
82 MulConst(usize, usize, T),
84 AssertZero(usize),
86 Const(usize, T),
88}
89
90#[derive(Clone, Copy)]
92enum OpType<T: WireValue> {
93 Input(fn(usize) -> Operation<T>),
95 InputConst(fn(usize, T) -> Operation<T>),
97 Output(fn(usize) -> Operation<T>),
99 Binary(fn(usize, usize, usize) -> Operation<T>),
101 BinaryConst(fn(usize, usize, T) -> Operation<T>),
103}
104
105#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
107pub enum CombineOperation {
108 GF2(Operation<bool>),
110 Z64(Operation<u64>),
112
113 B2A(usize, usize),
118
119 SizeHint(usize, usize),
122}
123
124impl<T: WireValue> Operation<T> {
125 fn random_variant<R: Rng + ?Sized>(rng: &mut R) -> OpType<T> {
127 match rng.gen_range(0..Operation::<T>::VARIANT_COUNT) {
128 0 => OpType::Input(Operation::Input),
129 1 => OpType::Input(Operation::Random),
130 2 => OpType::Binary(Operation::Add),
131 3 => OpType::BinaryConst(Operation::AddConst),
132 4 => OpType::Binary(Operation::Sub),
133 5 => OpType::BinaryConst(Operation::SubConst),
134 6 => OpType::Binary(Operation::Mul),
135 7 => OpType::BinaryConst(Operation::MulConst),
136 8 => OpType::Output(Operation::AssertZero),
137 9 => OpType::InputConst(Operation::Const),
138 _ => {
139 unimplemented!("Operation.random_variant is missing some variants")
140 }
141 }
142 }
143
144 fn construct<I1, I2>(
146 ty: OpType<T>,
147 mut inputs: I1,
148 mut outputs: I2,
149 constant: Option<T>,
150 ) -> Operation<T>
151 where
152 I1: Iterator<Item = usize>,
153 I2: Iterator<Item = usize>,
154 {
155 match ty {
156 OpType::Input(op) => op(outputs.next().expect("Input op requires an output wire")),
157 OpType::InputConst(op) => op(
158 outputs
159 .next()
160 .expect("InputConst op requires an output wire"),
161 constant.expect("InputConst op requires a constant operand"),
162 ),
163 OpType::Output(op) => op(inputs.next().expect("Output op requires an input wire")),
164 OpType::Binary(op) => op(
165 outputs.next().expect("Binary op requires an output wire"),
166 inputs.next().expect("Binary op requires two input wires"),
167 inputs.next().expect("Binary op requires two input wires"),
168 ),
169 OpType::BinaryConst(op) => op(
170 outputs
171 .next()
172 .expect("BinaryConst op requires an output wire"),
173 inputs
174 .next()
175 .expect("BinaryConst op requires an input wire"),
176 constant.expect("BinaryConst op requires a constant operand"),
177 ),
178 }
179 }
180}
181
182impl From<Operation<bool>> for CombineOperation {
183 fn from(op: Operation<bool>) -> Self {
184 CombineOperation::GF2(op)
185 }
186}
187
188impl From<Operation<u64>> for CombineOperation {
189 fn from(op: Operation<u64>) -> Self {
190 CombineOperation::Z64(op)
191 }
192}
193
194impl<T: WireValue> Distribution<Operation<T>> for Standard
195where
196 Standard: Distribution<(usize, usize, usize, T)>,
197{
198 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Operation<T> {
199 let (out, i0, i1, c): (usize, usize, usize, T) = rand::random();
200 Operation::<T>::construct(
201 Operation::<T>::random_variant(rng),
202 [i0, i1].iter().copied(),
203 [out].iter().copied(),
204 Some(c),
205 )
206 }
207}
208
209pub trait Gate<T>: HasIO + HasConst<T> + Translatable + Identity<T> {}
211impl Gate<u64> for Operation<u64> {}
212impl Gate<bool> for Operation<bool> {}
213impl<T: WireValue> Gate<T> for CombineOperation where CombineOperation: HasConst<T> + Identity<T> {}