mirror of https://github.com/zcash/halo2.git
chip::add.rs: Use batch inversion for alpha, beta, gamma, delta
This commit is contained in:
parent
f655e38e3e
commit
6dabb16edc
|
@ -3,7 +3,7 @@ use std::array;
|
||||||
use super::{copy, CellValue, EccConfig, EccPoint, Var};
|
use super::{copy, CellValue, EccConfig, EccPoint, Var};
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use halo2::{
|
use halo2::{
|
||||||
arithmetic::{CurveAffine, FieldExt},
|
arithmetic::{BatchInvert, CurveAffine, FieldExt},
|
||||||
circuit::Region,
|
circuit::Region,
|
||||||
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Permutation, Selector},
|
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Permutation, Selector},
|
||||||
poly::Rotation,
|
poly::Rotation,
|
||||||
|
@ -218,8 +218,39 @@ impl<C: CurveAffine> Config<C> {
|
||||||
let (x_p, y_p) = (p.x.value(), p.y.value());
|
let (x_p, y_p) = (p.x.value(), p.y.value());
|
||||||
let (x_q, y_q) = (q.x.value(), q.y.value());
|
let (x_q, y_q) = (q.x.value(), q.y.value());
|
||||||
|
|
||||||
|
// [alpha, beta, gamma, delta]
|
||||||
|
// = [inv0(x_q - x_p), inv0(x_p), inv0(x_q), inv0(y_q + y_p)]
|
||||||
|
// where inv0(x) = 0 if x = 0, 1/x otherwise.
|
||||||
|
//
|
||||||
|
let (alpha, beta, gamma, delta) = {
|
||||||
|
let inverses = x_p
|
||||||
|
.zip(x_q)
|
||||||
|
.zip(y_p)
|
||||||
|
.zip(y_q)
|
||||||
|
.map(|(((x_p, x_q), y_p), y_q)| {
|
||||||
|
let alpha = x_q - x_p;
|
||||||
|
let beta = x_p;
|
||||||
|
let gamma = x_q;
|
||||||
|
let delta = y_q + y_p;
|
||||||
|
|
||||||
|
let mut inverses = vec![alpha, beta, gamma, delta];
|
||||||
|
inverses.batch_invert();
|
||||||
|
inverses
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(inverses) = inverses {
|
||||||
|
(
|
||||||
|
Some(inverses[0]),
|
||||||
|
Some(inverses[1]),
|
||||||
|
Some(inverses[2]),
|
||||||
|
Some(inverses[3]),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None, None, None)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Assign α = inv0(x_q - x_p)
|
// Assign α = inv0(x_q - x_p)
|
||||||
let alpha = x_p.zip(x_q).map(|(x_p, x_q)| inv0(x_q - x_p));
|
|
||||||
region.assign_advice(
|
region.assign_advice(
|
||||||
|| "α",
|
|| "α",
|
||||||
self.alpha,
|
self.alpha,
|
||||||
|
@ -232,10 +263,7 @@ impl<C: CurveAffine> Config<C> {
|
||||||
|| "β",
|
|| "β",
|
||||||
self.beta,
|
self.beta,
|
||||||
offset,
|
offset,
|
||||||
|| {
|
|| beta.ok_or(Error::SynthesisError),
|
||||||
let beta = x_p.map(inv0);
|
|
||||||
beta.ok_or(Error::SynthesisError)
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Assign γ = inv0(x_q)
|
// Assign γ = inv0(x_q)
|
||||||
|
@ -243,10 +271,7 @@ impl<C: CurveAffine> Config<C> {
|
||||||
|| "γ",
|
|| "γ",
|
||||||
self.gamma,
|
self.gamma,
|
||||||
offset,
|
offset,
|
||||||
|| {
|
|| gamma.ok_or(Error::SynthesisError),
|
||||||
let gamma = x_q.map(inv0);
|
|
||||||
gamma.ok_or(Error::SynthesisError)
|
|
||||||
},
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Assign δ = inv0(y_q + y_p) if x_q = x_p, 0 otherwise
|
// Assign δ = inv0(y_q + y_p) if x_q = x_p, 0 otherwise
|
||||||
|
@ -257,43 +282,42 @@ impl<C: CurveAffine> Config<C> {
|
||||||
|| {
|
|| {
|
||||||
let x_p = x_p.ok_or(Error::SynthesisError)?;
|
let x_p = x_p.ok_or(Error::SynthesisError)?;
|
||||||
let x_q = x_q.ok_or(Error::SynthesisError)?;
|
let x_q = x_q.ok_or(Error::SynthesisError)?;
|
||||||
let y_p = y_p.ok_or(Error::SynthesisError)?;
|
|
||||||
let y_q = y_q.ok_or(Error::SynthesisError)?;
|
|
||||||
|
|
||||||
let delta = if x_q == x_p {
|
let delta = if x_q == x_p {
|
||||||
inv0(y_q + y_p)
|
delta
|
||||||
} else {
|
} else {
|
||||||
C::Base::zero()
|
Some(C::Base::zero())
|
||||||
};
|
};
|
||||||
Ok(delta)
|
delta.ok_or(Error::SynthesisError)
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
#[allow(clippy::collapsible_else_if)]
|
#[allow(clippy::collapsible_else_if)]
|
||||||
// Assign lambda
|
// Assign lambda
|
||||||
let lambda = x_p
|
let lambda =
|
||||||
.zip(y_p)
|
x_p.zip(y_p)
|
||||||
.zip(x_q)
|
.zip(x_q)
|
||||||
.zip(y_q)
|
.zip(y_q)
|
||||||
.map(|(((x_p, y_p), x_q), y_q)| {
|
.zip(alpha)
|
||||||
if x_q != x_p {
|
.map(|((((x_p, y_p), x_q), y_q), alpha)| {
|
||||||
// λ = (y_q - y_p)/(x_q - x_p)
|
if x_q != x_p {
|
||||||
// Here, alpha = inv0(x_q - x_p), which suffices since we
|
// λ = (y_q - y_p)/(x_q - x_p)
|
||||||
// know that x_q != x_p in this branch.
|
// Here, alpha = inv0(x_q - x_p), which suffices since we
|
||||||
(y_q - y_p) * alpha.unwrap()
|
// know that x_q != x_p in this branch.
|
||||||
} else {
|
(y_q - y_p) * alpha
|
||||||
if y_p != C::Base::zero() {
|
|
||||||
// 3(x_p)^2
|
|
||||||
let three_x_p_sq = C::Base::from_u64(3) * x_p * x_p;
|
|
||||||
// 2(y_p)
|
|
||||||
let two_y_p = C::Base::from_u64(2) * y_p;
|
|
||||||
// λ = 3(x_p)^2 / 2(y_p)
|
|
||||||
three_x_p_sq * two_y_p.invert().unwrap()
|
|
||||||
} else {
|
} else {
|
||||||
C::Base::zero()
|
if y_p != C::Base::zero() {
|
||||||
|
// 3(x_p)^2
|
||||||
|
let three_x_p_sq = C::Base::from_u64(3) * x_p * x_p;
|
||||||
|
// 1 / 2(y_p)
|
||||||
|
let inv_two_y_p = y_p.invert().unwrap() * C::Base::TWO_INV;
|
||||||
|
// λ = 3(x_p)^2 / 2(y_p)
|
||||||
|
three_x_p_sq * inv_two_y_p
|
||||||
|
} else {
|
||||||
|
C::Base::zero()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
region.assign_advice(
|
region.assign_advice(
|
||||||
|| "λ",
|
|| "λ",
|
||||||
self.lambda,
|
self.lambda,
|
||||||
|
@ -378,15 +402,6 @@ impl<C: CurveAffine> Config<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// inv0(x) is 0 if x = 0, 1/x otherwise.
|
|
||||||
fn inv0<F: FieldExt>(x: F) -> F {
|
|
||||||
if x == F::zero() {
|
|
||||||
F::zero()
|
|
||||||
} else {
|
|
||||||
x.invert().unwrap()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use group::Curve;
|
use group::Curve;
|
||||||
|
|
Loading…
Reference in New Issue