2021-12-01 18:10:00 -08:00
|
|
|
|
use super::EccPoint;
|
2022-11-29 21:05:37 -08:00
|
|
|
|
|
|
|
|
|
use group::ff::PrimeField;
|
2022-01-27 15:28:02 -08:00
|
|
|
|
use halo2_proofs::{
|
2021-06-04 23:13:56 -07:00
|
|
|
|
circuit::Region,
|
2022-05-12 15:21:29 -07:00
|
|
|
|
plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector},
|
2021-06-04 23:13:56 -07:00
|
|
|
|
poly::Rotation,
|
|
|
|
|
};
|
2022-11-29 21:05:37 -08:00
|
|
|
|
use pasta_curves::pallas;
|
|
|
|
|
|
2021-06-11 15:29:05 -07:00
|
|
|
|
use std::collections::HashSet;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
2021-11-30 10:41:02 -08:00
|
|
|
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
2021-06-11 15:29:05 -07:00
|
|
|
|
pub struct Config {
|
2021-06-04 23:13:56 -07:00
|
|
|
|
q_add: Selector,
|
|
|
|
|
// lambda
|
|
|
|
|
lambda: Column<Advice>,
|
|
|
|
|
// x-coordinate of P in P + Q = R
|
|
|
|
|
pub x_p: Column<Advice>,
|
|
|
|
|
// y-coordinate of P in P + Q = R
|
|
|
|
|
pub y_p: Column<Advice>,
|
|
|
|
|
// x-coordinate of Q or R in P + Q = R
|
|
|
|
|
pub x_qr: Column<Advice>,
|
|
|
|
|
// y-coordinate of Q or R in P + Q = R
|
|
|
|
|
pub y_qr: Column<Advice>,
|
|
|
|
|
// α = inv0(x_q - x_p)
|
|
|
|
|
alpha: Column<Advice>,
|
|
|
|
|
// β = inv0(x_p)
|
|
|
|
|
beta: Column<Advice>,
|
|
|
|
|
// γ = inv0(x_q)
|
|
|
|
|
gamma: Column<Advice>,
|
|
|
|
|
// δ = inv0(y_p + y_q) if x_q = x_p, 0 otherwise
|
|
|
|
|
delta: Column<Advice>,
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 10:41:02 -08:00
|
|
|
|
impl Config {
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
|
|
|
|
pub(super) fn configure(
|
|
|
|
|
meta: &mut ConstraintSystem<pallas::Base>,
|
|
|
|
|
x_p: Column<Advice>,
|
|
|
|
|
y_p: Column<Advice>,
|
|
|
|
|
x_qr: Column<Advice>,
|
|
|
|
|
y_qr: Column<Advice>,
|
|
|
|
|
lambda: Column<Advice>,
|
|
|
|
|
alpha: Column<Advice>,
|
|
|
|
|
beta: Column<Advice>,
|
|
|
|
|
gamma: Column<Advice>,
|
|
|
|
|
delta: Column<Advice>,
|
|
|
|
|
) -> Self {
|
2022-01-04 21:28:16 -08:00
|
|
|
|
meta.enable_equality(x_p);
|
|
|
|
|
meta.enable_equality(y_p);
|
|
|
|
|
meta.enable_equality(x_qr);
|
|
|
|
|
meta.enable_equality(y_qr);
|
2021-11-30 10:41:02 -08:00
|
|
|
|
|
|
|
|
|
let config = Self {
|
|
|
|
|
q_add: meta.selector(),
|
|
|
|
|
x_p,
|
|
|
|
|
y_p,
|
|
|
|
|
x_qr,
|
|
|
|
|
y_qr,
|
|
|
|
|
lambda,
|
|
|
|
|
alpha,
|
|
|
|
|
beta,
|
|
|
|
|
gamma,
|
|
|
|
|
delta,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config.create_gate(meta);
|
|
|
|
|
|
|
|
|
|
config
|
2021-06-04 23:13:56 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-14 03:30:43 -07:00
|
|
|
|
pub(crate) fn output_columns(&self) -> HashSet<Column<Advice>> {
|
2022-04-27 05:17:36 -07:00
|
|
|
|
[self.x_qr, self.y_qr].into_iter().collect()
|
2021-07-14 03:30:43 -07:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-30 10:41:02 -08:00
|
|
|
|
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
2022-05-08 20:27:03 -07:00
|
|
|
|
// https://p.z.cash/halo2-0.1:ecc-complete-addition
|
2022-05-09 16:46:23 -07:00
|
|
|
|
meta.create_gate("complete addition", |meta| {
|
2021-06-04 23:13:56 -07:00
|
|
|
|
let q_add = meta.query_selector(self.q_add);
|
|
|
|
|
let x_p = meta.query_advice(self.x_p, Rotation::cur());
|
|
|
|
|
let y_p = meta.query_advice(self.y_p, Rotation::cur());
|
|
|
|
|
let x_q = meta.query_advice(self.x_qr, Rotation::cur());
|
|
|
|
|
let y_q = meta.query_advice(self.y_qr, Rotation::cur());
|
|
|
|
|
let x_r = meta.query_advice(self.x_qr, Rotation::next());
|
|
|
|
|
let y_r = meta.query_advice(self.y_qr, Rotation::next());
|
|
|
|
|
let lambda = meta.query_advice(self.lambda, Rotation::cur());
|
|
|
|
|
|
|
|
|
|
// α = inv0(x_q - x_p)
|
|
|
|
|
let alpha = meta.query_advice(self.alpha, Rotation::cur());
|
|
|
|
|
// β = inv0(x_p)
|
|
|
|
|
let beta = meta.query_advice(self.beta, Rotation::cur());
|
|
|
|
|
// γ = inv0(x_q)
|
|
|
|
|
let gamma = meta.query_advice(self.gamma, Rotation::cur());
|
|
|
|
|
// δ = inv0(y_p + y_q) if x_q = x_p, 0 otherwise
|
|
|
|
|
let delta = meta.query_advice(self.delta, Rotation::cur());
|
|
|
|
|
|
|
|
|
|
// Useful composite expressions
|
2022-05-09 16:46:23 -07:00
|
|
|
|
// (x_q − x_p)
|
|
|
|
|
let x_q_minus_x_p = x_q.clone() - x_p.clone();
|
|
|
|
|
// (x_p - x_r)
|
|
|
|
|
let x_p_minus_x_r = x_p.clone() - x_r.clone();
|
|
|
|
|
// (y_q + y_p)
|
|
|
|
|
let y_q_plus_y_p = y_q.clone() + y_p.clone();
|
2021-06-04 23:13:56 -07:00
|
|
|
|
// α ⋅(x_q - x_p)
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let if_alpha = x_q_minus_x_p.clone() * alpha;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
// β ⋅ x_p
|
|
|
|
|
let if_beta = x_p.clone() * beta;
|
|
|
|
|
// γ ⋅ x_q
|
|
|
|
|
let if_gamma = x_q.clone() * gamma;
|
2022-05-09 16:46:23 -07:00
|
|
|
|
// δ ⋅(y_q + y_p)
|
|
|
|
|
let if_delta = y_q_plus_y_p.clone() * delta;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Useful constants
|
2021-06-11 15:29:05 -07:00
|
|
|
|
let one = Expression::Constant(pallas::Base::one());
|
2021-12-07 09:47:03 -08:00
|
|
|
|
let two = Expression::Constant(pallas::Base::from(2));
|
|
|
|
|
let three = Expression::Constant(pallas::Base::from(3));
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (x_q − x_p)⋅((x_q − x_p)⋅λ − (y_q−y_p)) = 0
|
|
|
|
|
let poly1 = {
|
|
|
|
|
let y_q_minus_y_p = y_q.clone() - y_p.clone(); // (y_q − y_p)
|
|
|
|
|
let incomplete = x_q_minus_x_p.clone() * lambda.clone() - y_q_minus_y_p; // (x_q − x_p)⋅λ − (y_q−y_p)
|
|
|
|
|
|
|
|
|
|
// q_add ⋅(x_q − x_p)⋅((x_q − x_p)⋅λ − (y_q−y_p))
|
2022-05-09 16:46:23 -07:00
|
|
|
|
x_q_minus_x_p.clone() * incomplete
|
2021-06-04 23:13:56 -07:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// (1 - (x_q - x_p)⋅α)⋅(2y_p ⋅λ - 3x_p^2) = 0
|
|
|
|
|
let poly2 = {
|
2021-06-11 15:59:02 -07:00
|
|
|
|
let three_x_p_sq = three * x_p.clone().square(); // 3x_p^2
|
2021-06-04 23:13:56 -07:00
|
|
|
|
let two_y_p = two * y_p.clone(); // 2y_p
|
|
|
|
|
let tangent_line = two_y_p * lambda.clone() - three_x_p_sq; // (2y_p ⋅λ - 3x_p^2)
|
|
|
|
|
|
|
|
|
|
// q_add ⋅(1 - (x_q - x_p)⋅α)⋅(2y_p ⋅λ - 3x_p^2)
|
|
|
|
|
(one.clone() - if_alpha.clone()) * tangent_line
|
|
|
|
|
};
|
|
|
|
|
|
2022-05-09 16:46:23 -07:00
|
|
|
|
// (λ^2 - x_p - x_q - x_r)
|
2022-05-10 14:35:52 -07:00
|
|
|
|
let nonexceptional_x_r =
|
|
|
|
|
lambda.clone().square() - x_p.clone() - x_q.clone() - x_r.clone();
|
2022-05-09 16:46:23 -07:00
|
|
|
|
// (λ ⋅(x_p - x_r) - y_p - y_r)
|
2022-05-10 14:35:52 -07:00
|
|
|
|
let nonexceptional_y_r = lambda * x_p_minus_x_r - y_p.clone() - y_r.clone();
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
2022-05-09 16:46:23 -07:00
|
|
|
|
// x_p⋅x_q⋅(x_q - x_p)⋅(λ^2 - x_p - x_q - x_r) = 0
|
2022-05-10 14:35:52 -07:00
|
|
|
|
let poly3a =
|
|
|
|
|
x_p.clone() * x_q.clone() * x_q_minus_x_p.clone() * nonexceptional_x_r.clone();
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// x_p⋅x_q⋅(x_q - x_p)⋅(λ ⋅(x_p - x_r) - y_p - y_r) = 0
|
2022-05-10 14:35:52 -07:00
|
|
|
|
let poly3b = x_p.clone() * x_q.clone() * x_q_minus_x_p * nonexceptional_y_r.clone();
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// x_p⋅x_q⋅(y_q + y_p)⋅(λ^2 - x_p - x_q - x_r) = 0
|
2022-05-10 14:35:52 -07:00
|
|
|
|
let poly3c = x_p.clone() * x_q.clone() * y_q_plus_y_p.clone() * nonexceptional_x_r;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// x_p⋅x_q⋅(y_q + y_p)⋅(λ ⋅(x_p - x_r) - y_p - y_r) = 0
|
2022-05-10 14:35:52 -07:00
|
|
|
|
let poly3d = x_p.clone() * x_q.clone() * y_q_plus_y_p * nonexceptional_y_r;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (1 - x_p * β) * (x_r - x_q) = 0
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let poly4a = (one.clone() - if_beta.clone()) * (x_r.clone() - x_q);
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (1 - x_p * β) * (y_r - y_q) = 0
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let poly4b = (one.clone() - if_beta) * (y_r.clone() - y_q);
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (1 - x_q * γ) * (x_r - x_p) = 0
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let poly5a = (one.clone() - if_gamma.clone()) * (x_r.clone() - x_p);
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (1 - x_q * γ) * (y_r - y_p) = 0
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let poly5b = (one.clone() - if_gamma) * (y_r.clone() - y_p);
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// ((1 - (x_q - x_p) * α - (y_q + y_p) * δ)) * x_r
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let poly6a = (one.clone() - if_alpha.clone() - if_delta.clone()) * x_r;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// ((1 - (x_q - x_p) * α - (y_q + y_p) * δ)) * y_r
|
2022-05-09 16:46:23 -07:00
|
|
|
|
let poly6b = (one - if_alpha - if_delta) * y_r;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
2022-04-24 15:13:38 -07:00
|
|
|
|
Constraints::with_selector(
|
|
|
|
|
q_add,
|
2022-04-27 05:17:36 -07:00
|
|
|
|
[
|
2022-05-09 16:46:23 -07:00
|
|
|
|
("1", poly1),
|
|
|
|
|
("2", poly2),
|
|
|
|
|
("3a", poly3a),
|
|
|
|
|
("3b", poly3b),
|
|
|
|
|
("3c", poly3c),
|
|
|
|
|
("3d", poly3d),
|
|
|
|
|
("4a", poly4a),
|
|
|
|
|
("4b", poly4b),
|
|
|
|
|
("5a", poly5a),
|
|
|
|
|
("5b", poly5b),
|
|
|
|
|
("6a", poly6a),
|
|
|
|
|
("6b", poly6b),
|
2022-04-27 05:17:36 -07:00
|
|
|
|
],
|
2022-04-24 15:13:38 -07:00
|
|
|
|
)
|
2021-06-04 23:13:56 -07:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-10 10:09:04 -07:00
|
|
|
|
pub(super) fn assign_region(
|
2021-06-04 23:13:56 -07:00
|
|
|
|
&self,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
p: &EccPoint,
|
|
|
|
|
q: &EccPoint,
|
2021-06-04 23:13:56 -07:00
|
|
|
|
offset: usize,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
region: &mut Region<'_, pallas::Base>,
|
|
|
|
|
) -> Result<EccPoint, Error> {
|
2021-06-04 23:13:56 -07:00
|
|
|
|
// Enable `q_add` selector
|
|
|
|
|
self.q_add.enable(region, offset)?;
|
|
|
|
|
|
|
|
|
|
// Copy point `p` into `x_p`, `y_p` columns
|
2021-12-01 18:10:00 -08:00
|
|
|
|
p.x.copy_advice(|| "x_p", region, self.x_p, offset)?;
|
|
|
|
|
p.y.copy_advice(|| "y_p", region, self.y_p, offset)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Copy point `q` into `x_qr`, `y_qr` columns
|
2021-12-01 18:10:00 -08:00
|
|
|
|
q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?;
|
|
|
|
|
q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
let (x_p, y_p) = (p.x.value(), p.y.value());
|
|
|
|
|
let (x_q, y_q) = (q.x.value(), q.y.value());
|
|
|
|
|
|
|
|
|
|
// Assign α = inv0(x_q - x_p)
|
2022-06-08 13:37:52 -07:00
|
|
|
|
let alpha = (x_q - x_p).invert();
|
|
|
|
|
region.assign_advice(|| "α", self.alpha, offset, || alpha)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Assign β = inv0(x_p)
|
2022-06-08 13:37:52 -07:00
|
|
|
|
let beta = x_p.invert();
|
|
|
|
|
region.assign_advice(|| "β", self.beta, offset, || beta)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Assign γ = inv0(x_q)
|
2022-06-08 13:37:52 -07:00
|
|
|
|
let gamma = x_q.invert();
|
|
|
|
|
region.assign_advice(|| "γ", self.gamma, offset, || gamma)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Assign δ = inv0(y_q + y_p) if x_q = x_p, 0 otherwise
|
2022-05-12 15:21:29 -07:00
|
|
|
|
let delta = x_p
|
|
|
|
|
.zip(x_q)
|
|
|
|
|
.zip(y_p)
|
|
|
|
|
.zip(y_q)
|
|
|
|
|
.map(|(((x_p, x_q), y_p), y_q)| {
|
2021-06-11 15:36:26 -07:00
|
|
|
|
if x_q == x_p {
|
2022-05-12 15:21:29 -07:00
|
|
|
|
(y_q + y_p).invert()
|
2021-06-04 23:13:56 -07:00
|
|
|
|
} else {
|
2022-05-12 15:21:29 -07:00
|
|
|
|
Assigned::Zero
|
2021-06-11 15:36:26 -07:00
|
|
|
|
}
|
2022-05-12 15:21:29 -07:00
|
|
|
|
});
|
2022-06-08 13:37:52 -07:00
|
|
|
|
region.assign_advice(|| "δ", self.delta, offset, || delta)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
#[allow(clippy::collapsible_else_if)]
|
|
|
|
|
// Assign lambda
|
2021-06-10 21:05:21 -07:00
|
|
|
|
let lambda =
|
|
|
|
|
x_p.zip(y_p)
|
|
|
|
|
.zip(x_q)
|
|
|
|
|
.zip(y_q)
|
|
|
|
|
.zip(alpha)
|
|
|
|
|
.map(|((((x_p, y_p), x_q), y_q), alpha)| {
|
|
|
|
|
if x_q != x_p {
|
|
|
|
|
// λ = (y_q - y_p)/(x_q - x_p)
|
|
|
|
|
// Here, alpha = inv0(x_q - x_p), which suffices since we
|
|
|
|
|
// know that x_q != x_p in this branch.
|
|
|
|
|
(y_q - y_p) * alpha
|
2021-06-04 23:13:56 -07:00
|
|
|
|
} else {
|
2021-12-01 04:59:37 -08:00
|
|
|
|
if !y_p.is_zero_vartime() {
|
2021-06-10 21:05:21 -07:00
|
|
|
|
// 3(x_p)^2
|
2022-05-12 15:21:29 -07:00
|
|
|
|
let three_x_p_sq = x_p.square() * pallas::Base::from(3);
|
2021-06-10 21:05:21 -07:00
|
|
|
|
// 1 / 2(y_p)
|
2022-05-12 15:21:29 -07:00
|
|
|
|
let inv_two_y_p = y_p.invert() * pallas::Base::TWO_INV;
|
2021-06-10 21:05:21 -07:00
|
|
|
|
// λ = 3(x_p)^2 / 2(y_p)
|
|
|
|
|
three_x_p_sq * inv_two_y_p
|
|
|
|
|
} else {
|
2022-05-12 15:21:29 -07:00
|
|
|
|
Assigned::Zero
|
2021-06-10 21:05:21 -07:00
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
}
|
2021-06-10 21:05:21 -07:00
|
|
|
|
});
|
2022-06-08 13:37:52 -07:00
|
|
|
|
region.assign_advice(|| "λ", self.lambda, offset, || lambda)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
2021-06-11 15:59:02 -07:00
|
|
|
|
// Calculate (x_r, y_r)
|
|
|
|
|
let r =
|
2021-06-04 23:13:56 -07:00
|
|
|
|
x_p.zip(y_p)
|
|
|
|
|
.zip(x_q)
|
|
|
|
|
.zip(y_q)
|
|
|
|
|
.zip(lambda)
|
|
|
|
|
.map(|((((x_p, y_p), x_q), y_q), lambda)| {
|
2021-06-11 15:59:02 -07:00
|
|
|
|
{
|
2021-12-01 04:59:37 -08:00
|
|
|
|
if x_p.is_zero_vartime() {
|
2021-06-11 15:59:02 -07:00
|
|
|
|
// 0 + Q = Q
|
2021-12-01 16:10:00 -08:00
|
|
|
|
(*x_q, *y_q)
|
2021-12-01 04:59:37 -08:00
|
|
|
|
} else if x_q.is_zero_vartime() {
|
2021-06-11 15:59:02 -07:00
|
|
|
|
// P + 0 = P
|
2021-12-01 16:10:00 -08:00
|
|
|
|
(*x_p, *y_p)
|
|
|
|
|
} else if (x_q == x_p) && (*y_q == -y_p) {
|
2021-06-11 15:59:02 -07:00
|
|
|
|
// P + (-P) maps to (0,0)
|
2022-05-12 15:21:29 -07:00
|
|
|
|
(Assigned::Zero, Assigned::Zero)
|
2021-06-11 15:59:02 -07:00
|
|
|
|
} else {
|
|
|
|
|
// x_r = λ^2 - x_p - x_q
|
|
|
|
|
let x_r = lambda.square() - x_p - x_q;
|
|
|
|
|
// y_r = λ(x_p - x_r) - y_p
|
|
|
|
|
let y_r = lambda * (x_p - x_r) - y_p;
|
|
|
|
|
(x_r, y_r)
|
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
}
|
|
|
|
|
});
|
2021-06-11 15:59:02 -07:00
|
|
|
|
|
|
|
|
|
// Assign x_r
|
|
|
|
|
let x_r = r.map(|r| r.0);
|
2022-06-08 13:37:52 -07:00
|
|
|
|
let x_r_cell = region.assign_advice(|| "x_r", self.x_qr, offset + 1, || x_r)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Assign y_r
|
2021-06-11 15:59:02 -07:00
|
|
|
|
let y_r = r.map(|r| r.1);
|
2022-06-08 13:37:52 -07:00
|
|
|
|
let y_r_cell = region.assign_advice(|| "y_r", self.y_qr, offset + 1, || y_r)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
2022-09-09 10:53:31 -07:00
|
|
|
|
let result = EccPoint::from_coordinates_unchecked(x_r_cell, y_r_cell);
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
// Check that the correct sum is obtained.
|
|
|
|
|
{
|
|
|
|
|
use group::Curve;
|
|
|
|
|
|
|
|
|
|
let p = p.point();
|
|
|
|
|
let q = q.point();
|
|
|
|
|
let real_sum = p.zip(q).map(|(p, q)| p + q);
|
|
|
|
|
let result = result.point();
|
|
|
|
|
|
2022-06-08 13:37:52 -07:00
|
|
|
|
real_sum
|
|
|
|
|
.zip(result)
|
|
|
|
|
.assert_if_known(|(real_sum, result)| &real_sum.to_affine() == result);
|
2021-06-04 23:13:56 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(result)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
pub mod tests {
|
2021-06-11 15:29:05 -07:00
|
|
|
|
use group::{prime::PrimeCurveAffine, Curve};
|
2022-06-08 13:37:52 -07:00
|
|
|
|
use halo2_proofs::{
|
|
|
|
|
circuit::{Layouter, Value},
|
|
|
|
|
plonk::Error,
|
|
|
|
|
};
|
2021-06-11 15:29:05 -07:00
|
|
|
|
use pasta_curves::{arithmetic::CurveExt, pallas};
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
2022-01-27 13:53:10 -08:00
|
|
|
|
use crate::ecc::{chip::EccPoint, EccInstructions, NonIdentityPoint};
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
#[allow(clippy::too_many_arguments)]
|
2021-09-28 09:39:41 -07:00
|
|
|
|
pub fn test_add<
|
|
|
|
|
EccChip: EccInstructions<pallas::Affine, Point = EccPoint> + Clone + Eq + std::fmt::Debug,
|
|
|
|
|
>(
|
2021-06-04 23:13:56 -07:00
|
|
|
|
chip: EccChip,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
|
|
|
|
p_val: pallas::Affine,
|
2021-09-27 01:49:08 -07:00
|
|
|
|
p: &NonIdentityPoint<pallas::Affine, EccChip>,
|
2021-06-11 15:29:05 -07:00
|
|
|
|
q_val: pallas::Affine,
|
2021-09-27 01:49:08 -07:00
|
|
|
|
q: &NonIdentityPoint<pallas::Affine, EccChip>,
|
|
|
|
|
p_neg: &NonIdentityPoint<pallas::Affine, EccChip>,
|
2021-06-04 23:13:56 -07:00
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
|
// Make sure P and Q are not the same point.
|
|
|
|
|
assert_ne!(p_val, q_val);
|
|
|
|
|
|
|
|
|
|
// Check complete addition P + (-P)
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let zero = {
|
2021-06-13 06:26:30 -07:00
|
|
|
|
let result = p.add(layouter.namespace(|| "P + (-P)"), p_neg)?;
|
2022-06-08 13:37:52 -07:00
|
|
|
|
result
|
|
|
|
|
.inner()
|
|
|
|
|
.is_identity()
|
|
|
|
|
.assert_if_known(|is_identity| *is_identity);
|
2021-09-27 03:14:01 -07:00
|
|
|
|
result
|
|
|
|
|
};
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Check complete addition 𝒪 + 𝒪
|
2021-06-13 06:26:30 -07:00
|
|
|
|
{
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), &zero)?;
|
|
|
|
|
result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), &zero)?;
|
2021-06-13 06:26:30 -07:00
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// Check P + Q
|
2021-06-13 06:26:30 -07:00
|
|
|
|
{
|
|
|
|
|
let result = p.add(layouter.namespace(|| "P + Q"), q)?;
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let witnessed_result = NonIdentityPoint::new(
|
2021-06-13 06:26:30 -07:00
|
|
|
|
chip.clone(),
|
|
|
|
|
layouter.namespace(|| "witnessed P + Q"),
|
2022-06-08 13:37:52 -07:00
|
|
|
|
Value::known((p_val + q_val).to_affine()),
|
2021-06-13 06:26:30 -07:00
|
|
|
|
)?;
|
|
|
|
|
result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?;
|
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// P + P
|
2021-06-13 06:26:30 -07:00
|
|
|
|
{
|
|
|
|
|
let result = p.add(layouter.namespace(|| "P + P"), p)?;
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let witnessed_result = NonIdentityPoint::new(
|
2021-06-13 06:26:30 -07:00
|
|
|
|
chip.clone(),
|
|
|
|
|
layouter.namespace(|| "witnessed P + P"),
|
2022-06-08 13:37:52 -07:00
|
|
|
|
Value::known((p_val + p_val).to_affine()),
|
2021-06-13 06:26:30 -07:00
|
|
|
|
)?;
|
|
|
|
|
result.constrain_equal(layouter.namespace(|| "constrain P + P"), &witnessed_result)?;
|
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// P + 𝒪
|
2021-06-13 06:26:30 -07:00
|
|
|
|
{
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let result = p.add(layouter.namespace(|| "P + 𝒪"), &zero)?;
|
2021-06-13 06:26:30 -07:00
|
|
|
|
result.constrain_equal(layouter.namespace(|| "P + 𝒪 = P"), p)?;
|
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// 𝒪 + P
|
2021-06-13 06:26:30 -07:00
|
|
|
|
{
|
|
|
|
|
let result = zero.add(layouter.namespace(|| "𝒪 + P"), p)?;
|
|
|
|
|
result.constrain_equal(layouter.namespace(|| "𝒪 + P = P"), p)?;
|
|
|
|
|
}
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (x, y) + (ζx, y) should behave like normal P + Q.
|
|
|
|
|
let endo_p = p_val.to_curve().endo();
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let endo_p = NonIdentityPoint::new(
|
2021-06-04 23:13:56 -07:00
|
|
|
|
chip.clone(),
|
2021-06-11 15:36:26 -07:00
|
|
|
|
layouter.namespace(|| "endo(P)"),
|
2022-06-08 13:37:52 -07:00
|
|
|
|
Value::known(endo_p.to_affine()),
|
2021-06-04 23:13:56 -07:00
|
|
|
|
)?;
|
|
|
|
|
p.add(layouter.namespace(|| "P + endo(P)"), &endo_p)?;
|
|
|
|
|
|
|
|
|
|
// (x, y) + (ζx, -y) should also behave like normal P + Q.
|
|
|
|
|
let endo_p_neg = (-p_val).to_curve().endo();
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let endo_p_neg = NonIdentityPoint::new(
|
2021-06-04 23:13:56 -07:00
|
|
|
|
chip.clone(),
|
2021-06-11 15:36:26 -07:00
|
|
|
|
layouter.namespace(|| "endo(-P)"),
|
2022-06-08 13:37:52 -07:00
|
|
|
|
Value::known(endo_p_neg.to_affine()),
|
2021-06-04 23:13:56 -07:00
|
|
|
|
)?;
|
|
|
|
|
p.add(layouter.namespace(|| "P + endo(-P)"), &endo_p_neg)?;
|
|
|
|
|
|
|
|
|
|
// (x, y) + ((ζ^2)x, y)
|
|
|
|
|
let endo_2_p = p_val.to_curve().endo().endo();
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let endo_2_p = NonIdentityPoint::new(
|
2021-06-04 23:13:56 -07:00
|
|
|
|
chip.clone(),
|
2021-06-11 15:36:26 -07:00
|
|
|
|
layouter.namespace(|| "endo^2(P)"),
|
2022-06-08 13:37:52 -07:00
|
|
|
|
Value::known(endo_2_p.to_affine()),
|
2021-06-04 23:13:56 -07:00
|
|
|
|
)?;
|
2021-06-11 15:36:26 -07:00
|
|
|
|
p.add(layouter.namespace(|| "P + endo^2(P)"), &endo_2_p)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
// (x, y) + ((ζ^2)x, -y)
|
|
|
|
|
let endo_2_p_neg = (-p_val).to_curve().endo().endo();
|
2021-09-27 03:14:01 -07:00
|
|
|
|
let endo_2_p_neg = NonIdentityPoint::new(
|
2021-06-04 23:13:56 -07:00
|
|
|
|
chip,
|
2021-06-11 15:36:26 -07:00
|
|
|
|
layouter.namespace(|| "endo^2(-P)"),
|
2022-06-08 13:37:52 -07:00
|
|
|
|
Value::known(endo_2_p_neg.to_affine()),
|
2021-06-04 23:13:56 -07:00
|
|
|
|
)?;
|
2021-06-11 15:36:26 -07:00
|
|
|
|
p.add(layouter.namespace(|| "P + endo^2(-P)"), &endo_2_p_neg)?;
|
2021-06-04 23:13:56 -07:00
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|