#[cfg(test)]
mod tests {
use crate::{
core::{
bounds::FieldBounds,
circuits::{
boolean::byte::Byte,
traits::{
arithmetic_circuit::{tests::TestedArithmeticCircuit, ArithmeticCircuit},
curve_circuit::{tests::TestedCurveCircuit, CurveCircuit},
},
},
expressions::expr::EvalFailure,
global_value::{curve_value::CurveValue, value::FieldValue},
},
utils::{
curve_point::CurvePoint,
elliptic_curve::{AffineEdwardsPoint, ProjectiveEdwardsPoint, EIGHT_INV_MOD_ELL},
field::{BaseField, ScalarField},
},
};
use rand::{thread_rng, Rng};
#[derive(Debug, Clone)]
struct ConversionFromCurveValue;
impl CurveCircuit for ConversionFromCurveValue {
fn eval(
&self,
curve_points: Vec<CurvePoint>,
_scalars: Vec<ScalarField>,
) -> Result<Vec<CurvePoint>, EvalFailure> {
assert!(curve_points.len() == 1);
Ok(curve_points)
}
fn run(
&self,
curve_vals: Vec<CurveValue>,
_scalar_vals: Vec<FieldValue<ScalarField>>,
) -> Vec<CurveValue> {
curve_vals
.into_iter()
.map(|point| CurveValue::from_projective(point.to_projective()))
.collect::<Vec<CurveValue>>()
}
}
#[derive(Debug, Clone)]
struct ConversionFromProjectiveEdwardsPoint {
test_infinity: bool,
}
impl ArithmeticCircuit<BaseField> for ConversionFromProjectiveEdwardsPoint {
fn eval(&self, x: Vec<BaseField>) -> Result<Vec<BaseField>, EvalFailure> {
if self.test_infinity {
Ok(vec![
AffineEdwardsPoint::identity().x,
AffineEdwardsPoint::identity().y,
])
} else {
let y = x[1];
let (is_on_curve, affine_point) = AffineEdwardsPoint::try_from_y(y);
if is_on_curve {
let cleared = affine_point
.to_projective()
.mul_bits(vec![false, false, false, true])
.mul_bits(
EIGHT_INV_MOD_ELL
.into_iter()
.flat_map(|byte| Byte::<bool>::from(byte).to_vec())
.collect::<Vec<bool>>(),
)
.to_affine();
Ok(vec![cleared.x, cleared.y])
} else {
Ok(vec![
AffineEdwardsPoint::identity().x,
AffineEdwardsPoint::identity().y,
])
}
}
}
fn bounds(&self, _bounds: Vec<FieldBounds<BaseField>>) -> Vec<FieldBounds<BaseField>> {
vec![FieldBounds::All; 2]
}
#[allow(non_snake_case)]
fn run(&self, vals: Vec<FieldValue<BaseField>>) -> Vec<FieldValue<BaseField>> {
let point = if self.test_infinity {
let mut rng = thread_rng();
let X = vals[0];
let Y = vals[1];
let point_at_infinity = if rng.gen_bool(0.5) {
ProjectiveEdwardsPoint::new(
(FieldValue::from(0), Y, FieldValue::from(0)),
false,
false,
)
} else {
ProjectiveEdwardsPoint::new((X, Y, FieldValue::from(0)), false, false)
};
CurveValue::from_projective(point_at_infinity)
} else {
let y = vals[1];
let (_, affine_point) = AffineEdwardsPoint::try_from_y(y);
CurveValue::from_affine(affine_point)
};
let converted = point.to_affine();
vec![converted.x, converted.y]
}
}
impl TestedCurveCircuit for ConversionFromCurveValue {
fn gen_desc<R: rand::Rng + ?Sized>(_rng: &mut R) -> Self {
Self
}
fn gen_n_points<R: rand::Rng + ?Sized>(&self, _rng: &mut R) -> usize {
1
}
fn gen_n_scalars<R: rand::Rng + ?Sized>(&self, _rng: &mut R, _n_points: usize) -> usize {
0
}
}
impl TestedArithmeticCircuit<BaseField> for ConversionFromProjectiveEdwardsPoint {
fn gen_desc<R: rand::Rng + ?Sized>(rng: &mut R) -> Self {
Self {
test_infinity: rng.gen_bool(0.5),
}
}
fn gen_n_inputs<R: rand::Rng + ?Sized>(&self, _rng: &mut R) -> usize {
2
}
}
#[test]
fn test_conversion_from_curve_value() {
ConversionFromCurveValue::test(1, 4)
}
#[test]
fn test_conversion_from_projective_edwards_point() {
ConversionFromProjectiveEdwardsPoint::test(1, 4)
}
}