Skip to content

Commit 084ebd5

Browse files
committed
sca: wip
1 parent c7e2e07 commit 084ebd5

File tree

2 files changed

+90
-23
lines changed

2 files changed

+90
-23
lines changed

patronus-sca/src/lib.rs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
// released under BSD 3-Clause License
33
// author: Kevin Laeufer <laeufer@cornell.edu>
44

5-
mod backwards;
5+
mod rewrite;
66

7-
use crate::backwards::backwards_sub;
7+
use crate::rewrite::{backwards_sub, build_gate_polynomial};
88
use baa::{BitVecOps, BitVecValue, BitVecValueRef};
99
use patronus::expr::*;
1010
use polysub::{Coef, Term, VarIndex};
@@ -33,12 +33,6 @@ pub fn verify_word_level_equality(ctx: &mut Context, p: ScaEqualityProblem) -> S
3333
};
3434
println!("word-level polynomial: {word_poly}");
3535

36-
// the actual reference polynomial needs to contain the output bits as well
37-
let output_poly = poly_for_bv_expr(ctx, p.word_level);
38-
word_poly.scale(&Coef::from_i64(-1, word_poly.get_mod()));
39-
word_poly.add_assign(&output_poly);
40-
let spec = word_poly;
41-
4236
// collect all (bit-level) input variables
4337
let input_vars: FxHashSet<VarIndex> = inputs
4438
.iter()
@@ -51,6 +45,14 @@ pub fn verify_word_level_equality(ctx: &mut Context, p: ScaEqualityProblem) -> S
5145
})
5246
.collect();
5347

48+
let gate_poly = build_gate_polynomial(ctx, &input_vars, word_poly.get_mod(), p.gate_level);
49+
50+
// the actual reference polynomial needs to contain the output bits as well
51+
let output_poly = poly_for_bv_expr(ctx, p.word_level);
52+
word_poly.scale(&Coef::from_i64(-1, word_poly.get_mod()));
53+
word_poly.add_assign(&output_poly);
54+
let spec = word_poly;
55+
5456
// create todos for all output variables
5557
let gate_outputs: Vec<_> = (0..width)
5658
.map(|ii| {
Lines changed: 80 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
use crate::{DefaultCoef, Poly, expr_to_var};
66
use baa::BitVecOps;
77
use patronus::expr::{
8-
Context, DenseExprSet, Expr, ExprRef, ExprSet, ForEachChild, count_expr_uses,
8+
Context, DenseExprSet, Expr, ExprRef, ExprSet, ForEachChild, count_expr_uses, traversal,
99
};
10-
use polysub::{PhaseOptPolynom, VarIndex};
10+
use polysub::{Coef, Mod, PhaseOptPolynom, VarIndex};
1111
use rustc_hash::FxHashSet;
1212
use std::collections::VecDeque;
1313

1414
/// Used for backwards substitution
15-
type PolyOpt = polysub::PhaseOptPolynom<DefaultCoef>;
15+
type PolyOpt = PhaseOptPolynom<DefaultCoef>;
1616

1717
pub fn backwards_sub(
1818
ctx: &Context,
@@ -33,10 +33,11 @@ pub fn backwards_sub(
3333
let mut seen = DenseExprSet::default();
3434

3535
while !todo.is_empty() {
36-
//try_exhaustive(ctx, input_vars, &spec, todo.iter().cloned());
36+
let min_idx = try_exhaustive(ctx, input_vars, &spec, todo.iter().cloned());
37+
let (output_var, gate) = todo.swap_remove_back(min_idx).unwrap();
3738

3839
// chose variable to replace
39-
let (output_var, gate) = todo.pop_back().unwrap();
40+
//let (output_var, gate) = todo.pop_back().unwrap();
4041

4142
replaced.push(output_var);
4243
println!(
@@ -153,15 +154,79 @@ fn try_exhaustive(
153154
input_vars: &FxHashSet<VarIndex>,
154155
spec: &PolyOpt,
155156
todo: impl Iterator<Item = (VarIndex, ExprRef)>,
156-
) {
157-
for (ii, (output_var, gate)) in todo.enumerate() {
158-
let mut s = spec.clone();
159-
replace_gate(ctx, input_vars, &mut s, output_var, gate);
160-
println!(
161-
" {ii:>3}: {output_var} {:?}: {} -> {}",
162-
&ctx[gate],
163-
spec.size(),
157+
) -> usize {
158+
let sizes: Vec<_> = todo
159+
.enumerate()
160+
.map(|(ii, (output_var, gate))| {
161+
let mut s = spec.clone();
162+
replace_gate(ctx, input_vars, &mut s, output_var, gate);
164163
s.size()
165-
);
166-
}
164+
})
165+
.collect();
166+
let min = sizes.iter().cloned().min().unwrap();
167+
let max = sizes.iter().cloned().max().unwrap();
168+
let first_min = sizes.iter().position(|s| *s == min).unwrap();
169+
println!("{} -> {min}/{max}", spec.size());
170+
first_min
171+
}
172+
173+
/// tries to build the gate-level polynomial from the bottom up.
174+
pub fn build_gate_polynomial(
175+
ctx: &Context,
176+
input_vars: &FxHashSet<VarIndex>,
177+
m: Mod,
178+
e: ExprRef,
179+
) -> Poly {
180+
traversal::bottom_up(ctx, e, |ctx, gate, children: &[Poly]| {
181+
let var = expr_to_var(gate);
182+
183+
// if this is an input, we just want to return the variable
184+
if input_vars.contains(&var) {
185+
return Poly::from_monoms(m, [(Coef::from_i64(1, m), vec![var].into())].into_iter());
186+
}
187+
188+
match (ctx[gate].clone(), children) {
189+
(Expr::BVOr(_, _, 1), [a, b]) => {
190+
// a + b - ab
191+
let mut r = a.mul(b);
192+
r.scale(&Coef::from_i64(-1, m));
193+
r.add_assign(a);
194+
r.add_assign(b);
195+
r
196+
}
197+
(Expr::BVXor(_, _, 1), [a, b]) => {
198+
// a + b - 2ab
199+
let mut r = a.mul(b);
200+
r.scale(&Coef::from_i64(-2, m));
201+
r.add_assign(a);
202+
r.add_assign(b);
203+
r
204+
}
205+
(Expr::BVAnd(_, _, 1), [a, b]) => {
206+
// ab
207+
a.mul(b)
208+
}
209+
(Expr::BVNot(_, 1), [a]) => {
210+
// 1 - a
211+
let one = Poly::from_monoms(m, [(Coef::from_i64(1, m), vec![].into())].into_iter());
212+
let mut r = a.clone();
213+
r.scale(&Coef::from_i64(-1, m));
214+
r.add_assign(&one);
215+
r
216+
}
217+
(Expr::BVSlice { .. }, [_]) => {
218+
todo!("should not get here!")
219+
}
220+
(Expr::BVLiteral(value), _) => {
221+
let value = value.get(ctx);
222+
debug_assert_eq!(value.width(), 1);
223+
if value.is_true() {
224+
Poly::from_monoms(m, [(Coef::from_i64(1, m), vec![].into())].into_iter())
225+
} else {
226+
Poly::from_monoms(m, [(Coef::from_i64(0, m), vec![].into())].into_iter())
227+
}
228+
}
229+
other => todo!("add support for {other:?}"),
230+
}
231+
})
167232
}

0 commit comments

Comments
 (0)