use crate::{
math::{U256, add_reduce, mac_reduce, mac_sub_reduce, sub_reduce},
uint::{
add::trace::UintAddRequires,
mul::trace::UintMulRequires,
trace::{Uint, UintPtr, UintStoreRequires},
},
};
#[derive(Debug)]
pub struct UintRequire<'a> {
store: &'a mut UintStoreRequires,
add: &'a mut UintAddRequires,
mul: &'a mut UintMulRequires,
}
impl<'a> UintRequire<'a> {
pub fn new(
store: &'a mut UintStoreRequires,
add: &'a mut UintAddRequires,
mul: &'a mut UintMulRequires,
) -> Self {
Self { store, add, mul }
}
pub fn intern(&mut self, value: U256, bound: UintPtr) -> UintPtr {
self.store.intern(value, bound)
}
pub fn value(&self, ptr: UintPtr) -> U256 {
self.store.uint(ptr).value
}
fn resolve(&self, ptr: UintPtr) -> (Uint, U256) {
let u = *self.store.uint(ptr);
(u, self.store.uint(u.bound_ptr).value)
}
pub fn add(&mut self, a_ptr: UintPtr, b_ptr: UintPtr) -> UintPtr {
let (a, bound) = self.resolve(a_ptr);
let (b, _) = self.resolve(b_ptr);
assert_eq!(a.bound_ptr, b.bound_ptr, "add operands must share a modulus");
let c = add_reduce(a.value, b.value, bound);
let c_ptr = self.store.intern(c, a.bound_ptr);
self.add.record(a_ptr, b_ptr, c_ptr, a.bound_ptr, 1);
c_ptr
}
pub fn sub(&mut self, x_ptr: UintPtr, y_ptr: UintPtr) -> UintPtr {
let (x, bound) = self.resolve(x_ptr);
let (y, _) = self.resolve(y_ptr);
assert_eq!(x.bound_ptr, y.bound_ptr, "sub operands must share a modulus");
let z = sub_reduce(x.value, y.value, bound);
let z_ptr = self.store.intern(z, x.bound_ptr);
self.add.record(y_ptr, z_ptr, x_ptr, x.bound_ptr, 1);
z_ptr
}
pub fn sub_nonzero(&mut self, x_ptr: UintPtr, y_ptr: UintPtr) -> UintPtr {
let (x, bound) = self.resolve(x_ptr);
let (y, _) = self.resolve(y_ptr);
assert_eq!(x.bound_ptr, y.bound_ptr, "sub operands must share a modulus");
assert_ne!(x.value, y.value, "sub_nonzero requires x ≠ y");
let z = sub_reduce(x.value, y.value, bound);
let z_ptr = self.store.intern(z, x.bound_ptr);
self.add.record_nz(y_ptr, z_ptr, x_ptr, x.bound_ptr, 1);
z_ptr
}
pub fn neg(&mut self, v_ptr: UintPtr) -> UintPtr {
let (v, bound) = self.resolve(v_ptr);
let z = sub_reduce(U256::ZERO, v.value, bound);
let z_ptr = self.store.intern(z, v.bound_ptr);
self.add.record_to_zero(v_ptr, z_ptr, v.bound_ptr, 1);
z_ptr
}
pub fn add_to_zero(&mut self, a_ptr: UintPtr, b_ptr: UintPtr) {
let (a, bound) = self.resolve(a_ptr);
let (b, _) = self.resolve(b_ptr);
assert_eq!(a.bound_ptr, b.bound_ptr, "add operands must share a modulus");
assert_eq!(add_reduce(a.value, b.value, bound), U256::ZERO, "a + b must reduce to zero",);
self.add.record_to_zero(a_ptr, b_ptr, a.bound_ptr, 1);
}
pub fn value_eq(&mut self, a_ptr: UintPtr, c_ptr: UintPtr) {
let (a, _) = self.resolve(a_ptr);
let (c, _) = self.resolve(c_ptr);
assert_eq!(a.bound_ptr, c.bound_ptr, "eq operands must share a modulus");
assert_eq!(a.value, c.value, "a must equal c");
self.add.record_eq(a_ptr, c_ptr, a.bound_ptr, 1);
}
pub fn mac(
&mut self,
kappa_a: u16,
a_ptr: UintPtr,
b_ptr: UintPtr,
kappa_c: u16,
c_ptr: UintPtr,
) -> UintPtr {
let (a, bound) = self.resolve(a_ptr);
let (b, _) = self.resolve(b_ptr);
let (c, _) = self.resolve(c_ptr);
assert!(
a.bound_ptr == b.bound_ptr && a.bound_ptr == c.bound_ptr,
"mac operands must share a modulus",
);
let r = mac_reduce(kappa_a, a.value, b.value, kappa_c, c.value, bound);
let r_ptr = self.store.intern(r, a.bound_ptr);
self.mul.record(kappa_a, a_ptr, b_ptr, kappa_c, c_ptr, r_ptr, a.bound_ptr, 1);
r_ptr
}
pub fn mac_sub(
&mut self,
kappa_a: u16,
a_ptr: UintPtr,
b_ptr: UintPtr,
kappa_c: u16,
c_ptr: UintPtr,
) -> UintPtr {
let (a, bound) = self.resolve(a_ptr);
let (b, _) = self.resolve(b_ptr);
let (c, _) = self.resolve(c_ptr);
assert!(
a.bound_ptr == b.bound_ptr && a.bound_ptr == c.bound_ptr,
"mac operands must share a modulus",
);
let r = mac_sub_reduce(kappa_a, a.value, b.value, kappa_c, c.value, bound);
let r_ptr = self.store.intern(r, a.bound_ptr);
self.mul
.record_sub(kappa_a, a_ptr, b_ptr, kappa_c, c_ptr, r_ptr, a.bound_ptr, 1);
r_ptr
}
pub fn mac_into(
&mut self,
kappa_a: u16,
a_ptr: UintPtr,
b_ptr: UintPtr,
kappa_c: u16,
c_ptr: UintPtr,
r_ptr: UintPtr,
) {
let (a, bound) = self.resolve(a_ptr);
let (b, _) = self.resolve(b_ptr);
let (c, _) = self.resolve(c_ptr);
let (r, _) = self.resolve(r_ptr);
assert!(
a.bound_ptr == b.bound_ptr && a.bound_ptr == c.bound_ptr && a.bound_ptr == r.bound_ptr,
"mac operands must share a modulus",
);
assert_eq!(
mac_reduce(kappa_a, a.value, b.value, kappa_c, c.value, bound),
r.value,
"κₐ·a·b + κ_c·c must reduce to the stored r",
);
self.mul.record(kappa_a, a_ptr, b_ptr, kappa_c, c_ptr, r_ptr, a.bound_ptr, 1);
}
}
#[derive(Debug, Default)]
pub struct UintStores {
pub(crate) store: UintStoreRequires,
pub(crate) add: UintAddRequires,
pub(crate) mul: UintMulRequires,
}
impl UintStores {
pub fn new() -> Self {
Self::default()
}
pub fn require(&mut self) -> UintRequire<'_> {
UintRequire::new(&mut self.store, &mut self.add, &mut self.mul)
}
}