use crate::{
core::{
actually_used_field::ActuallyUsedField,
bounds::FieldBounds,
circuits::traits::general_circuit::GeneralCircuit,
expressions::expr::EvalFailure,
global_value::value::FieldValue,
},
traits::{GetBit, Select},
utils::field::{BaseField, ScalarField},
};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ConversionCircuit;
impl Default for ConversionCircuit {
fn default() -> Self {
Self
}
}
impl ConversionCircuit {
fn signed(&self) -> bool {
false
}
fn convert_plaintext<F: ActuallyUsedField, G: ActuallyUsedField>(&self, f_val: F) -> G {
f_val.to_unsigned_number().into()
}
fn convert_bounds<F: ActuallyUsedField, G: ActuallyUsedField>(
&self,
f_val: FieldBounds<F>,
) -> FieldBounds<G> {
let (min_abs, max_abs) = f_val.to_unsigned_number_pair();
if &max_abs - &min_abs < G::modulus() {
FieldBounds::new(min_abs.into(), max_abs.into())
} else {
FieldBounds::All
}
}
fn convert_mpc<F: ActuallyUsedField, G: ActuallyUsedField>(
&self,
f_val: FieldValue<F>,
) -> FieldValue<G> {
let mut result: FieldValue<G> = 0.into();
for idx in 0usize..(F::NUM_BITS as usize) {
let bit_val = f_val.get_bit(idx, self.signed());
result += bit_val.select(
FieldValue::from(G::power_of_two(idx)),
FieldValue::<G>::from(0),
);
}
result
}
}
impl GeneralCircuit for ConversionCircuit {
fn eval(
&self,
scalars: Vec<ScalarField>,
bases: Vec<BaseField>,
) -> Result<(Vec<ScalarField>, Vec<BaseField>), EvalFailure> {
let new_bases = scalars
.into_iter()
.map(|scalar| self.convert_plaintext(scalar))
.collect();
let new_scalars = bases
.into_iter()
.map(|base| self.convert_plaintext(base))
.collect();
Ok((new_bases, new_scalars))
}
fn bounds(
&self,
scalar_bounds: Vec<FieldBounds<ScalarField>>,
base_bounds: Vec<FieldBounds<BaseField>>,
) -> (Vec<FieldBounds<ScalarField>>, Vec<FieldBounds<BaseField>>) {
let new_base_bounds = scalar_bounds
.into_iter()
.map(|bounds| self.convert_bounds(bounds))
.collect();
let new_scalar_bounds = base_bounds
.into_iter()
.map(|bounds| self.convert_bounds(bounds))
.collect();
(new_base_bounds, new_scalar_bounds)
}
fn run(
&self,
scalar_vals: Vec<FieldValue<ScalarField>>,
base_vals: Vec<FieldValue<BaseField>>,
) -> (Vec<FieldValue<ScalarField>>, Vec<FieldValue<BaseField>>) {
let new_base_vals = scalar_vals
.into_iter()
.map(|val| self.convert_mpc(val))
.collect();
let new_scalar_vals = base_vals
.into_iter()
.map(|val| self.convert_mpc(val))
.collect();
(new_base_vals, new_scalar_vals)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::circuits::traits::general_circuit::tests::TestedGeneralCircuit;
use rand::Rng;
fn gen_vec_len<R: Rng + ?Sized>(rng: &mut R) -> usize {
let mut result = rng.gen_bool(0.75) as usize;
while rng.gen_bool(0.25) {
result += 1;
}
result
}
impl TestedGeneralCircuit for ConversionCircuit {
fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
ConversionCircuit
}
fn gen_n_scalars<R: Rng + ?Sized>(&self, rng: &mut R) -> usize {
gen_vec_len(rng)
}
fn gen_n_bases<R: Rng + ?Sized>(&self, rng: &mut R, _n_scalars: usize) -> usize {
gen_vec_len(rng)
}
}
#[test]
fn tested() {
ConversionCircuit::test(1, 16)
}
}