use crate::{
core::{
bounds::FieldBounds,
circuits::{
boolean::{
boolean_value::{Boolean, BooleanValue},
byte::Byte,
},
traits::arithmetic_circuit::ArithmeticCircuit,
},
expressions::expr::EvalFailure,
global_value::value::FieldValue,
},
traits::{Equal, FromLeBytes, GetBit, GreaterEqual, Select},
utils::{
elliptic_curve::{
AffineEdwardsPoint,
EDWARDS25519_D,
EIGHT_INV_MOD_ELL,
F25519,
SQRT_NEG_ONE,
},
field::BaseField,
used_field::UsedField,
},
};
use ff::Field;
use std::ops::Shr;
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub struct BaseFieldToEdwards25519EncodingCircuit {
d: BaseField,
kappa: i32,
}
impl Default for BaseFieldToEdwards25519EncodingCircuit {
fn default() -> Self {
Self::new()
}
}
impl BaseFieldToEdwards25519EncodingCircuit {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
d: BaseField::from_le_bytes(EDWARDS25519_D),
kappa: 64,
}
}
#[cfg(test)]
pub fn get_d(&self) -> BaseField {
self.d
}
}
impl BaseFieldToEdwards25519EncodingCircuit {
fn encode<
B: Boolean + Select<T, T, T>,
T: F25519 + GetBit<Output = B> + Equal<T, Output = B> + From<B>,
>(
&self,
m: T,
) -> AffineEdwardsPoint<T> {
let m_offset = m + T::from(2);
let mut points = (0..self.kappa)
.map(|i| {
let y = m_offset * T::from(self.kappa) + T::from(i);
let (is_on_curve, point) = AffineEdwardsPoint::<T>::try_from_y(y);
(is_on_curve, point.x, point.y)
})
.collect::<Vec<(B, T, T)>>();
let (x, y) = points.split_off(1).into_iter().fold(
(points[0].1, points[0].2),
|(x_current, y_current), (is_on_curve_cand, x_cand, y_cand)| {
let x = is_on_curve_cand.select(x_cand, x_current);
let y = is_on_curve_cand.select(y_cand, y_current);
(x, y)
},
);
AffineEdwardsPoint::new((x, y), true, false)
.to_projective()
.mul_str("0001")
.to_affine()
}
}
impl ArithmeticCircuit<BaseField> for BaseFieldToEdwards25519EncodingCircuit {
fn eval(&self, x: Vec<BaseField>) -> Result<Vec<BaseField>, EvalFailure> {
if x.len() != 1 {
panic!("Base field to Edwards25519 encoding requires input of length 1");
}
if x[0] > BaseField::power_of_two(128) {
EvalFailure::err_ub("Input must be at most 2^128")
} else {
let (x, y) = Self::encode::<bool, _>(self, x[0]).inner();
Ok(vec![x, y])
}
}
fn bounds(&self, _bounds: Vec<FieldBounds<BaseField>>) -> Vec<FieldBounds<BaseField>> {
vec![FieldBounds::All, FieldBounds::All]
}
fn run(&self, vals: Vec<FieldValue<BaseField>>) -> Vec<FieldValue<BaseField>> {
if vals.len() != 1 {
panic!("Base field to Edwards25519 encoding requires input of length 1");
}
let (x, y) = Self::encode::<BooleanValue, _>(self, vals[0]).inner();
vec![x, y]
}
}
#[derive(Clone, Debug)]
#[allow(dead_code)]
pub struct Edwards25519ToBaseFieldDecodingCircuit {
d: BaseField,
kappa: i32,
}
impl Default for Edwards25519ToBaseFieldDecodingCircuit {
fn default() -> Self {
Self::new()
}
}
impl Edwards25519ToBaseFieldDecodingCircuit {
#[allow(dead_code)]
pub fn new() -> Self {
Self {
d: BaseField::from_le_bytes(EDWARDS25519_D),
kappa: 64,
}
}
}
#[allow(non_snake_case, dead_code)]
impl Edwards25519ToBaseFieldDecodingCircuit {
fn recover_message<
B: Boolean + Select<T, T, T>,
T: F25519 + Shr<usize, Output = T> + GreaterEqual<T, Output = B>,
>(
&self,
P: AffineEdwardsPoint<T>,
P_plus_Q: AffineEdwardsPoint<T>,
) -> T {
let sqrt_neg_one = T::from(BaseField::from_le_bytes(SQRT_NEG_ONE));
let mut y_coordinates = vec![
P.y,
-P.y,
sqrt_neg_one * P.x,
-sqrt_neg_one * P.x,
P_plus_Q.y,
-P_plus_Q.y,
sqrt_neg_one * P_plus_Q.x,
-sqrt_neg_one * P_plus_Q.x,
];
y_coordinates.split_off(1).into_iter().fold(
y_coordinates[0] >> (self.kappa.ilog2() as usize),
|current, cand| {
let cand = cand >> (self.kappa.ilog2() as usize);
(cand.lt(current)).select(cand, current)
},
) - T::from(2)
}
fn decode<
B: Boolean + Select<T, T, T>,
T: F25519 + Shr<usize, Output = T> + GreaterEqual<T, Output = B>,
>(
&self,
P: AffineEdwardsPoint<T>,
) -> T {
let P_prime = P
.to_projective()
.mul_bits(
EIGHT_INV_MOD_ELL
.into_iter()
.flat_map(|byte| Byte::<bool>::from(byte).to_vec())
.collect::<Vec<bool>>(),
)
.to_affine();
let P_prime_plus_Q = P_prime + AffineEdwardsPoint::eight_torsion_point();
Self::recover_message(self, P_prime, P_prime_plus_Q)
}
}
impl ArithmeticCircuit<BaseField> for Edwards25519ToBaseFieldDecodingCircuit {
#[allow(non_snake_case)]
fn eval(&self, x: Vec<BaseField>) -> Result<Vec<BaseField>, EvalFailure> {
if x.len() != 2 {
panic!("Edwards25519 to Base field decoding requires input of length 2");
}
let P = AffineEdwardsPoint::new((x[0], x[1]), false, false);
let m = Self::decode::<_, _>(self, P);
if m > BaseField::power_of_two(128) {
EvalFailure::err_ub("Circuit only supported for decoded messages of at most 2^128")
} else {
Ok(vec![m])
}
}
fn bounds(&self, _bounds: Vec<FieldBounds<BaseField>>) -> Vec<FieldBounds<BaseField>> {
vec![FieldBounds::new(
BaseField::ZERO,
BaseField::power_of_two(128),
)]
}
#[allow(non_snake_case)]
fn run(&self, vals: Vec<FieldValue<BaseField>>) -> Vec<FieldValue<BaseField>> {
if vals.len() != 2 {
panic!("Edwards25519 to Base field decoding requires input of length 2");
}
let P = AffineEdwardsPoint::new((vals[0], vals[1]), false, false);
vec![Self::decode::<_, _>(self, P)]
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::circuits::traits::arithmetic_circuit::tests::TestedArithmeticCircuit;
use rand::Rng;
#[test]
#[allow(non_snake_case)]
fn test_encoding_decoding() {
let rng = &mut crate::utils::test_rng::get();
let encoding_circuit = BaseFieldToEdwards25519EncodingCircuit::new();
let decoding_circuit = Edwards25519ToBaseFieldDecodingCircuit::new();
for _ in 0..2 {
for magnitude in [8, 128] {
let m = BaseField::gen_inclusive_range(
&mut *rng,
BaseField::ZERO,
BaseField::power_of_two(magnitude),
);
let P = encoding_circuit.encode::<bool, _>(m);
let (x, y) = P.inner();
let x2 = x * x;
let y2 = y * y;
assert_eq!(
-x2 + y2,
BaseField::ONE + encoding_circuit.get_d() * x2 * y2
);
let m_dec = decoding_circuit.decode::<_, _>(P);
assert_eq!(m_dec, m);
}
}
}
impl TestedArithmeticCircuit<BaseField> for BaseFieldToEdwards25519EncodingCircuit {
fn gen_desc<R: Rng + ?Sized>(_rng: &mut R) -> Self {
Self::new()
}
fn gen_n_inputs<R: Rng + ?Sized>(&self, _rng: &mut R) -> usize {
1
}
fn extra_checks(&self, inputs: Vec<BaseField>, outputs: Vec<BaseField>) {
let decoding_circuit = Edwards25519ToBaseFieldDecodingCircuit::new();
let decoded = decoding_circuit.eval(outputs).unwrap();
assert_eq!(inputs, decoded);
}
}
#[test]
fn tested_base_field_to_edwards25519_encoding() {
BaseFieldToEdwards25519EncodingCircuit::test(1, 4)
}
}