use crate::constraint_system::ecc::WitnessPoint;
use crate::constraint_system::TurboComposer;
use dusk_bls12_381::BlsScalar;
use dusk_jubjub::{JubJubAffine, JubJubExtended};
impl TurboComposer {
pub fn component_add_point(
&mut self,
a: WitnessPoint,
b: WitnessPoint,
) -> WitnessPoint {
let x_1 = a.x;
let y_1 = a.y;
let x_2 = b.x;
let y_2 = b.y;
let p1 = JubJubAffine::from_raw_unchecked(
self.witnesses[&x_1],
self.witnesses[&y_1],
);
let p2 = JubJubAffine::from_raw_unchecked(
self.witnesses[&x_2],
self.witnesses[&y_2],
);
let point: JubJubAffine = (JubJubExtended::from(p1) + p2).into();
let x_3 = point.get_x();
let y_3 = point.get_y();
let x1_y2 = self.witnesses[&x_1] * self.witnesses[&y_2];
let x_1_y_2 = self.append_witness(x1_y2);
let x_3 = self.append_witness(x_3);
let y_3 = self.append_witness(y_3);
self.w_l.extend(&[x_1, x_3]);
self.w_r.extend(&[y_1, y_3]);
self.w_o.extend(&[x_2, Self::constant_zero()]);
self.w_4.extend(&[y_2, x_1_y_2]);
let zeros = [BlsScalar::zero(), BlsScalar::zero()];
self.q_l.extend(&zeros);
self.q_r.extend(&zeros);
self.q_c.extend(&zeros);
self.q_o.extend(&zeros);
self.q_m.extend(&zeros);
self.q_4.extend(&zeros);
self.q_arith.extend(&zeros);
self.q_range.extend(&zeros);
self.q_logic.extend(&zeros);
self.q_fixed_group_add.extend(&zeros);
self.q_lookup.extend(&zeros);
self.q_variable_group_add.push(BlsScalar::one());
self.q_variable_group_add.push(BlsScalar::zero());
self.perm.add_variables_to_map(x_1, y_1, x_2, y_2, self.n);
self.n += 1;
self.perm.add_variables_to_map(
x_3,
y_3,
Self::constant_zero(),
x_1_y_2,
self.n,
);
self.n += 1;
WitnessPoint { x: x_3, y: y_3 }
}
}
#[cfg(feature = "std")]
#[cfg(test)]
mod test {
use super::*;
use crate::constraint_system::helper::*;
use crate::constraint_system::Constraint;
use dusk_jubjub::{EDWARDS_D, GENERATOR, GENERATOR_EXTENDED};
pub fn classical_point_addition(
composer: &mut TurboComposer,
a: WitnessPoint,
b: WitnessPoint,
) -> WitnessPoint {
let x1 = a.x;
let y1 = a.y;
let x2 = b.x;
let y2 = b.y;
let constraint = Constraint::new().mult(1).a(x1).b(y2);
let x1_y2 = composer.gate_mul(constraint);
let constraint = Constraint::new().mult(1).a(y1).b(x2);
let y1_x2 = composer.gate_mul(constraint);
let constraint = Constraint::new().mult(1).a(y1).b(y2);
let y1_y2 = composer.gate_mul(constraint);
let constraint = Constraint::new().mult(1).a(x1).b(x2);
let x1_x2 = composer.gate_mul(constraint);
let constraint = Constraint::new().mult(EDWARDS_D).a(x1_x2).b(y1_y2);
let d_x1_x2_y1_y2 = composer.gate_mul(constraint);
let constraint = Constraint::new().left(1).right(1).a(x1_y2).b(y1_x2);
let x_numerator = composer.gate_add(constraint);
let constraint = Constraint::new().left(1).right(1).a(y1_y2).b(x1_x2);
let y_numerator = composer.gate_add(constraint);
let constraint = Constraint::new().left(1).constant(1).a(d_x1_x2_y1_y2);
let x_denominator = composer.gate_add(constraint);
let inv_x_denom = unsafe {
composer.evaluate_witness(&x_denominator).invert().unwrap()
};
let inv_x_denom = composer.append_witness(inv_x_denom);
let constraint = Constraint::new()
.mult(1)
.constant(-BlsScalar::one())
.a(x_denominator)
.b(inv_x_denom);
composer.append_gate(constraint);
let constraint = Constraint::new()
.left(-BlsScalar::one())
.constant(1)
.a(d_x1_x2_y1_y2);
let y_denominator = composer.gate_add(constraint);
let inv_y_denom = unsafe {
composer.evaluate_witness(&y_denominator).invert().unwrap()
};
let inv_y_denom = composer.append_witness(inv_y_denom);
let constraint = Constraint::new()
.mult(1)
.constant(-BlsScalar::one())
.a(y_denominator)
.b(inv_y_denom);
composer.append_gate(constraint);
let constraint =
Constraint::new().mult(1).a(inv_x_denom).b(x_numerator);
let x_3 = composer.gate_mul(constraint);
let constraint =
Constraint::new().mult(1).a(inv_y_denom).b(y_numerator);
let y_3 = composer.gate_mul(constraint);
WitnessPoint { x: x_3, y: y_3 }
}
#[test]
fn test_curve_addition() {
gadget_tester(
|composer| {
let expected = GENERATOR_EXTENDED + GENERATOR_EXTENDED;
let point_a = composer.append_point(GENERATOR);
let point_b = composer.append_point(GENERATOR);
let point = composer.component_add_point(point_a, point_b);
let point2 =
classical_point_addition(composer, point_a, point_b);
composer.assert_equal_point(point, point2);
composer.assert_equal_public_point(point, expected);
},
2000,
)
.expect("Curve addition failed");
}
}