2021-07-10 08:56:24 -07:00
|
|
|
use std::{array, convert::TryInto};
|
2021-06-04 23:34:44 -07:00
|
|
|
|
2021-11-29 12:39:41 -08:00
|
|
|
use super::super::{EccPoint, EccScalarFixedShort, FixedPoints, L_SCALAR_SHORT, NUM_WINDOWS_SHORT};
|
2022-01-27 13:53:10 -08:00
|
|
|
use crate::{ecc::chip::MagnitudeSign, utilities::bool_check};
|
2021-06-04 23:34:44 -07:00
|
|
|
|
2022-01-27 15:28:02 -08:00
|
|
|
use halo2_proofs::{
|
2021-12-07 18:16:59 -08:00
|
|
|
circuit::{Layouter, Region},
|
2021-07-09 22:19:42 -07:00
|
|
|
plonk::{ConstraintSystem, Error, Expression, Selector},
|
2021-06-04 23:34:44 -07:00
|
|
|
poly::Rotation,
|
|
|
|
};
|
2021-07-17 08:59:25 -07:00
|
|
|
use pasta_curves::pallas;
|
2021-06-04 23:34:44 -07:00
|
|
|
|
2021-08-19 21:21:46 -07:00
|
|
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
2021-08-18 23:59:39 -07:00
|
|
|
pub struct Config<Fixed: FixedPoints<pallas::Affine>> {
|
2021-06-04 23:34:44 -07:00
|
|
|
// Selector used for fixed-base scalar mul with short signed exponent.
|
|
|
|
q_mul_fixed_short: Selector,
|
2021-08-18 23:59:39 -07:00
|
|
|
super_config: super::Config<Fixed>,
|
2021-06-04 23:34:44 -07:00
|
|
|
}
|
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
2021-11-30 19:20:24 -08:00
|
|
|
pub(crate) fn configure(
|
|
|
|
meta: &mut ConstraintSystem<pallas::Base>,
|
2021-08-18 23:59:39 -07:00
|
|
|
super_config: super::Config<Fixed>,
|
2021-11-30 19:20:24 -08:00
|
|
|
) -> Self {
|
|
|
|
let config = Self {
|
|
|
|
q_mul_fixed_short: meta.selector(),
|
|
|
|
super_config,
|
|
|
|
};
|
|
|
|
|
|
|
|
config.create_gate(meta);
|
|
|
|
|
|
|
|
config
|
2021-06-04 23:34:44 -07:00
|
|
|
}
|
|
|
|
|
2021-11-30 19:20:24 -08:00
|
|
|
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
2021-06-04 23:34:44 -07:00
|
|
|
meta.create_gate("Short fixed-base mul gate", |meta| {
|
|
|
|
let q_mul_fixed_short = meta.query_selector(self.q_mul_fixed_short);
|
|
|
|
let y_p = meta.query_advice(self.super_config.y_p, Rotation::cur());
|
|
|
|
let y_a = meta.query_advice(self.super_config.add_config.y_qr, Rotation::cur());
|
2021-07-10 08:56:24 -07:00
|
|
|
// z_21
|
|
|
|
let last_window = meta.query_advice(self.super_config.u, Rotation::cur());
|
2021-06-04 23:34:44 -07:00
|
|
|
let sign = meta.query_advice(self.super_config.window, Rotation::cur());
|
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
let one = Expression::Constant(pallas::Base::one());
|
|
|
|
|
|
|
|
// Check that last window is either 0 or 1.
|
2021-11-18 10:47:30 -08:00
|
|
|
let last_window_check = bool_check(last_window);
|
2021-07-10 08:56:24 -07:00
|
|
|
// Check that sign is either 1 or -1.
|
|
|
|
let sign_check = sign.clone() * sign.clone() - one;
|
|
|
|
|
2021-06-04 23:34:44 -07:00
|
|
|
// `(x_a, y_a)` is the result of `[m]B`, where `m` is the magnitude.
|
|
|
|
// We conditionally negate this result using `y_p = y_a * s`, where `s` is the sign.
|
|
|
|
|
|
|
|
// Check that the final `y_p = y_a` or `y_p = -y_a`
|
2021-07-26 05:54:27 -07:00
|
|
|
let y_check = (y_p.clone() - y_a.clone()) * (y_p.clone() + y_a.clone());
|
2021-06-04 23:34:44 -07:00
|
|
|
|
|
|
|
// Check that the correct sign is witnessed s.t. sign * y_p = y_a
|
|
|
|
let negation_check = sign * y_p - y_a;
|
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
array::IntoIter::new([
|
|
|
|
("last_window_check", last_window_check),
|
|
|
|
("sign_check", sign_check),
|
|
|
|
("y_check", y_check),
|
|
|
|
("negation_check", negation_check),
|
|
|
|
])
|
|
|
|
.map(move |(name, poly)| (name, q_mul_fixed_short.clone() * poly))
|
2021-06-04 23:34:44 -07:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
fn decompose(
|
2021-07-09 22:19:42 -07:00
|
|
|
&self,
|
|
|
|
region: &mut Region<'_, pallas::Base>,
|
|
|
|
offset: usize,
|
2021-12-07 18:16:59 -08:00
|
|
|
magnitude_sign: MagnitudeSign,
|
2021-07-09 22:19:42 -07:00
|
|
|
) -> Result<EccScalarFixedShort, Error> {
|
2021-07-10 08:56:24 -07:00
|
|
|
let (magnitude, sign) = magnitude_sign;
|
2021-07-09 22:19:42 -07:00
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
// Decompose magnitude
|
2021-11-30 19:00:07 -08:00
|
|
|
let running_sum = self.super_config.running_sum_config.copy_decompose(
|
2021-07-16 21:10:13 -07:00
|
|
|
region,
|
|
|
|
offset,
|
2021-12-01 04:51:33 -08:00
|
|
|
magnitude.clone(),
|
2021-07-16 21:10:13 -07:00
|
|
|
true,
|
2021-11-29 12:39:41 -08:00
|
|
|
L_SCALAR_SHORT,
|
2021-07-16 21:10:13 -07:00
|
|
|
NUM_WINDOWS_SHORT,
|
|
|
|
)?;
|
2021-07-09 22:19:42 -07:00
|
|
|
|
|
|
|
Ok(EccScalarFixedShort {
|
|
|
|
magnitude,
|
2021-07-10 08:56:24 -07:00
|
|
|
sign,
|
|
|
|
running_sum: (*running_sum).as_slice().try_into().unwrap(),
|
2021-07-09 22:19:42 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-07-06 20:26:32 -07:00
|
|
|
pub fn assign(
|
2021-06-04 23:34:44 -07:00
|
|
|
&self,
|
2021-07-06 20:26:32 -07:00
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
2021-12-07 18:16:59 -08:00
|
|
|
magnitude_sign: MagnitudeSign,
|
2021-08-18 23:59:39 -07:00
|
|
|
base: &<Fixed as FixedPoints<pallas::Affine>>::ShortScalar,
|
|
|
|
) -> Result<(EccPoint, EccScalarFixedShort), Error>
|
|
|
|
where
|
|
|
|
<Fixed as FixedPoints<pallas::Affine>>::ShortScalar:
|
|
|
|
super::super::FixedPoint<pallas::Affine>,
|
|
|
|
{
|
2021-07-09 22:19:42 -07:00
|
|
|
let (scalar, acc, mul_b) = layouter.assign_region(
|
2021-07-07 21:00:52 -07:00
|
|
|
|| "Short fixed-base mul (incomplete addition)",
|
2021-07-06 20:26:32 -07:00
|
|
|
|mut region| {
|
|
|
|
let offset = 0;
|
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
// Decompose the scalar
|
2021-12-01 04:51:33 -08:00
|
|
|
let scalar = self.decompose(&mut region, offset, magnitude_sign.clone())?;
|
2021-07-06 20:26:32 -07:00
|
|
|
|
2021-08-18 23:59:39 -07:00
|
|
|
let (acc, mul_b) = self
|
|
|
|
.super_config
|
|
|
|
.assign_region_inner::<_, NUM_WINDOWS_SHORT>(
|
|
|
|
&mut region,
|
|
|
|
offset,
|
|
|
|
&(&scalar).into(),
|
|
|
|
base,
|
2022-01-28 07:38:22 -08:00
|
|
|
self.super_config.running_sum_config.q_range_check(),
|
2021-08-18 23:59:39 -07:00
|
|
|
)?;
|
2021-07-09 22:19:42 -07:00
|
|
|
|
|
|
|
Ok((scalar, acc, mul_b))
|
2021-07-07 21:00:52 -07:00
|
|
|
},
|
|
|
|
)?;
|
2021-07-06 20:26:32 -07:00
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
// Last window
|
2021-07-07 21:00:52 -07:00
|
|
|
let result = layouter.assign_region(
|
|
|
|
|| "Short fixed-base mul (most significant word)",
|
|
|
|
|mut region| {
|
|
|
|
let offset = 0;
|
2021-07-06 20:26:32 -07:00
|
|
|
// Add to the cumulative sum to get `[magnitude]B`.
|
|
|
|
let magnitude_mul = self.super_config.add_config.assign_region(
|
2021-12-01 04:51:33 -08:00
|
|
|
&mul_b.clone().into(),
|
|
|
|
&acc.clone().into(),
|
2021-07-07 21:00:52 -07:00
|
|
|
offset,
|
2021-07-06 20:26:32 -07:00
|
|
|
&mut region,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
// Increase offset by 1 after complete addition
|
|
|
|
let offset = offset + 1;
|
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
// Copy sign to `window` column
|
2021-12-01 18:10:00 -08:00
|
|
|
let sign = scalar.sign.copy_advice(
|
2021-07-06 20:26:32 -07:00
|
|
|
|| "sign",
|
2021-12-01 18:10:00 -08:00
|
|
|
&mut region,
|
2021-07-06 20:26:32 -07:00
|
|
|
self.super_config.window,
|
2021-07-07 21:00:52 -07:00
|
|
|
offset,
|
2021-07-06 20:26:32 -07:00
|
|
|
)?;
|
|
|
|
|
2021-07-16 09:44:56 -07:00
|
|
|
// Copy last window to `u` column.
|
|
|
|
// (Although the last window is not a `u` value; we are copying it into the `u`
|
|
|
|
// column because there is an available cell there.)
|
2021-12-01 04:51:33 -08:00
|
|
|
let z_21 = scalar.running_sum[21].clone();
|
2021-12-01 18:10:00 -08:00
|
|
|
z_21.copy_advice(|| "last_window", &mut region, self.super_config.u, offset)?;
|
2021-07-10 08:56:24 -07:00
|
|
|
|
2021-07-06 20:26:32 -07:00
|
|
|
// Conditionally negate `y`-coordinate
|
|
|
|
let y_val = if let Some(sign) = sign.value() {
|
2021-12-01 16:10:00 -08:00
|
|
|
if sign == &-pallas::Base::one() {
|
|
|
|
magnitude_mul.y.value().cloned().map(|y: pallas::Base| -y)
|
2021-06-04 23:34:44 -07:00
|
|
|
} else {
|
2021-12-01 16:10:00 -08:00
|
|
|
magnitude_mul.y.value().cloned()
|
2021-07-06 20:26:32 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
// Enable mul_fixed_short selector on final row
|
2021-07-07 21:00:52 -07:00
|
|
|
self.q_mul_fixed_short.enable(&mut region, offset)?;
|
2021-07-06 20:26:32 -07:00
|
|
|
|
|
|
|
// Assign final `y` to `y_p` column and return final point
|
|
|
|
let y_var = region.assign_advice(
|
|
|
|
|| "y_var",
|
|
|
|
self.super_config.y_p,
|
2021-07-07 21:00:52 -07:00
|
|
|
offset,
|
2021-11-23 16:21:44 -08:00
|
|
|
|| y_val.ok_or(Error::Synthesis),
|
2021-07-06 20:26:32 -07:00
|
|
|
)?;
|
|
|
|
|
2021-07-07 21:00:52 -07:00
|
|
|
Ok(EccPoint {
|
2021-07-06 20:26:32 -07:00
|
|
|
x: magnitude_mul.x,
|
2021-12-01 17:10:00 -08:00
|
|
|
y: y_var,
|
2021-07-07 21:00:52 -07:00
|
|
|
})
|
2021-07-06 20:26:32 -07:00
|
|
|
},
|
2021-07-07 21:00:52 -07:00
|
|
|
)?;
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
// Check that the correct multiple is obtained.
|
2021-07-10 18:49:23 -07:00
|
|
|
// This inlined test is only done for valid 64-bit magnitudes
|
|
|
|
// and valid +/- 1 signs.
|
|
|
|
// Invalid values result in constraint failures which are
|
|
|
|
// tested at the circuit-level.
|
2021-07-07 21:00:52 -07:00
|
|
|
{
|
2021-08-18 23:59:39 -07:00
|
|
|
use super::super::FixedPoint;
|
2021-12-07 10:02:03 -08:00
|
|
|
use group::{ff::PrimeField, Curve};
|
2021-07-07 21:00:52 -07:00
|
|
|
|
2021-07-10 18:49:23 -07:00
|
|
|
if let (Some(magnitude), Some(sign)) = (scalar.magnitude.value(), scalar.sign.value()) {
|
2021-12-07 09:47:03 -08:00
|
|
|
let magnitude_is_valid = magnitude <= &pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64);
|
2021-07-10 18:49:23 -07:00
|
|
|
let sign_is_valid = sign * sign == pallas::Base::one();
|
|
|
|
if magnitude_is_valid && sign_is_valid {
|
|
|
|
let scalar = scalar.magnitude.value().zip(scalar.sign.value()).map(
|
|
|
|
|(magnitude, sign)| {
|
|
|
|
// Move magnitude from base field into scalar field (which always fits
|
|
|
|
// for Pallas).
|
2021-12-07 10:02:03 -08:00
|
|
|
let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap();
|
2021-07-10 18:49:23 -07:00
|
|
|
|
2021-12-01 16:10:00 -08:00
|
|
|
let sign = if sign == &pallas::Base::one() {
|
2021-07-10 18:49:23 -07:00
|
|
|
pallas::Scalar::one()
|
|
|
|
} else {
|
|
|
|
-pallas::Scalar::one()
|
|
|
|
};
|
|
|
|
|
|
|
|
magnitude * sign
|
|
|
|
},
|
|
|
|
);
|
|
|
|
let real_mul = scalar.map(|scalar| base.generator() * scalar);
|
|
|
|
|
|
|
|
let result = result.point();
|
|
|
|
|
|
|
|
if let (Some(real_mul), Some(result)) = (real_mul, result) {
|
|
|
|
assert_eq!(real_mul.to_affine(), result);
|
|
|
|
}
|
|
|
|
}
|
2021-07-07 21:00:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-09 22:19:42 -07:00
|
|
|
Ok((result, scalar))
|
2021-06-04 23:34:44 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
pub mod tests {
|
2021-12-07 10:02:03 -08:00
|
|
|
use group::{ff::PrimeField, Curve};
|
2022-01-27 15:28:02 -08:00
|
|
|
use halo2_proofs::{
|
2021-11-23 16:21:44 -08:00
|
|
|
arithmetic::CurveAffine,
|
2021-12-01 18:51:46 -08:00
|
|
|
circuit::{AssignedCell, Chip, Layouter},
|
2021-07-20 01:22:08 -07:00
|
|
|
plonk::{Any, Error},
|
2021-07-10 08:56:24 -07:00
|
|
|
};
|
2021-06-04 23:34:44 -07:00
|
|
|
use pasta_curves::{arithmetic::FieldExt, pallas};
|
|
|
|
|
2022-01-27 13:53:10 -08:00
|
|
|
use crate::{
|
2021-12-07 18:16:59 -08:00
|
|
|
ecc::{
|
2021-08-18 23:59:39 -07:00
|
|
|
chip::{EccChip, FixedPoint, MagnitudeSign},
|
2022-01-27 13:15:41 -08:00
|
|
|
tests::{Short, TestFixedBases},
|
2021-12-07 18:16:59 -08:00
|
|
|
FixedPointShort, NonIdentityPoint, Point,
|
|
|
|
},
|
2021-12-01 18:51:46 -08:00
|
|
|
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
|
2021-07-10 08:56:24 -07:00
|
|
|
};
|
2021-06-04 23:34:44 -07:00
|
|
|
|
|
|
|
#[allow(clippy::op_ref)]
|
2022-01-27 13:15:41 -08:00
|
|
|
pub(crate) fn test_mul_fixed_short(
|
|
|
|
chip: EccChip<TestFixedBases>,
|
2021-06-04 23:34:44 -07:00
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
2021-07-08 00:06:47 -07:00
|
|
|
) -> Result<(), Error> {
|
2022-01-27 13:15:41 -08:00
|
|
|
// test_short
|
|
|
|
let base_val = Short.generator();
|
|
|
|
let test_short = FixedPointShort::from_inner(chip.clone(), Short);
|
2021-06-04 23:34:44 -07:00
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
fn load_magnitude_sign(
|
2022-01-27 13:15:41 -08:00
|
|
|
chip: EccChip<TestFixedBases>,
|
2021-07-10 08:56:24 -07:00
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
|
|
|
magnitude: pallas::Base,
|
|
|
|
sign: pallas::Base,
|
2021-12-07 18:16:59 -08:00
|
|
|
) -> Result<MagnitudeSign, Error> {
|
2021-07-10 08:56:24 -07:00
|
|
|
let column = chip.config().advices[0];
|
|
|
|
let magnitude =
|
|
|
|
chip.load_private(layouter.namespace(|| "magnitude"), column, Some(magnitude))?;
|
|
|
|
let sign = chip.load_private(layouter.namespace(|| "sign"), column, Some(sign))?;
|
|
|
|
|
|
|
|
Ok((magnitude, sign))
|
|
|
|
}
|
|
|
|
|
2021-09-27 03:14:01 -07:00
|
|
|
fn constrain_equal_non_id(
|
2022-01-27 13:15:41 -08:00
|
|
|
chip: EccChip<TestFixedBases>,
|
2021-07-08 00:06:47 -07:00
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
|
|
|
base_val: pallas::Affine,
|
|
|
|
scalar_val: pallas::Scalar,
|
2022-01-27 13:15:41 -08:00
|
|
|
result: Point<pallas::Affine, EccChip<TestFixedBases>>,
|
2021-07-08 00:06:47 -07:00
|
|
|
) -> Result<(), Error> {
|
2021-09-27 03:14:01 -07:00
|
|
|
let expected = NonIdentityPoint::new(
|
2021-07-08 00:06:47 -07:00
|
|
|
chip,
|
|
|
|
layouter.namespace(|| "expected point"),
|
|
|
|
Some((base_val * scalar_val).to_affine()),
|
|
|
|
)?;
|
|
|
|
result.constrain_equal(layouter.namespace(|| "constrain result"), &expected)
|
|
|
|
}
|
|
|
|
|
2021-07-10 08:56:24 -07:00
|
|
|
let magnitude_signs = [
|
2021-12-07 09:47:03 -08:00
|
|
|
("random [a]B", pallas::Base::from(rand::random::<u64>()), {
|
|
|
|
let mut random_sign = pallas::Base::one();
|
|
|
|
if rand::random::<bool>() {
|
|
|
|
random_sign = -random_sign;
|
|
|
|
}
|
|
|
|
random_sign
|
|
|
|
}),
|
2021-07-10 08:56:24 -07:00
|
|
|
(
|
|
|
|
"[2^64 - 1]B",
|
2021-12-07 09:47:03 -08:00
|
|
|
pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64),
|
2021-07-10 08:56:24 -07:00
|
|
|
pallas::Base::one(),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"-[2^64 - 1]B",
|
2021-12-07 09:47:03 -08:00
|
|
|
pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64),
|
2021-07-10 08:56:24 -07:00
|
|
|
-pallas::Base::one(),
|
|
|
|
),
|
|
|
|
// There is a single canonical sequence of window values for which a doubling occurs on the last step:
|
|
|
|
// 1333333333333333333334 in octal.
|
|
|
|
// [0xB6DB_6DB6_DB6D_B6DC] B
|
|
|
|
(
|
|
|
|
"mul_with_double",
|
2021-12-07 09:47:03 -08:00
|
|
|
pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64),
|
2021-07-10 08:56:24 -07:00
|
|
|
pallas::Base::one(),
|
|
|
|
),
|
2021-07-14 21:30:14 -07:00
|
|
|
(
|
|
|
|
"mul_with_double negative",
|
2021-12-07 09:47:03 -08:00
|
|
|
pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64),
|
2021-07-14 21:30:14 -07:00
|
|
|
-pallas::Base::one(),
|
|
|
|
),
|
2021-07-10 08:56:24 -07:00
|
|
|
];
|
|
|
|
|
|
|
|
for (name, magnitude, sign) in magnitude_signs.iter() {
|
|
|
|
let (result, _) = {
|
|
|
|
let magnitude_sign = load_magnitude_sign(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| *name),
|
|
|
|
*magnitude,
|
|
|
|
*sign,
|
|
|
|
)?;
|
2022-01-27 13:15:41 -08:00
|
|
|
test_short.mul(layouter.namespace(|| *name), magnitude_sign)?
|
2021-07-10 08:56:24 -07:00
|
|
|
};
|
|
|
|
// Move from base field into scalar field
|
|
|
|
let scalar = {
|
2021-12-07 10:02:03 -08:00
|
|
|
let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap();
|
2021-07-10 08:56:24 -07:00
|
|
|
let sign = if *sign == pallas::Base::one() {
|
|
|
|
pallas::Scalar::one()
|
|
|
|
} else {
|
|
|
|
-pallas::Scalar::one()
|
|
|
|
};
|
|
|
|
magnitude * sign
|
|
|
|
};
|
2021-09-27 03:14:01 -07:00
|
|
|
constrain_equal_non_id(
|
2021-06-04 23:34:44 -07:00
|
|
|
chip.clone(),
|
2021-07-10 08:56:24 -07:00
|
|
|
layouter.namespace(|| *name),
|
2021-07-08 00:06:47 -07:00
|
|
|
base_val,
|
2021-07-10 08:56:24 -07:00
|
|
|
scalar,
|
2021-07-08 00:06:47 -07:00
|
|
|
result,
|
2021-06-04 23:34:44 -07:00
|
|
|
)?;
|
|
|
|
}
|
|
|
|
|
2021-09-27 03:14:01 -07:00
|
|
|
let zero_magnitude_signs = [
|
|
|
|
("mul by +zero", pallas::Base::zero(), pallas::Base::one()),
|
|
|
|
("mul by -zero", pallas::Base::zero(), -pallas::Base::one()),
|
|
|
|
];
|
|
|
|
|
|
|
|
for (name, magnitude, sign) in zero_magnitude_signs.iter() {
|
|
|
|
let (result, _) = {
|
|
|
|
let magnitude_sign = load_magnitude_sign(
|
|
|
|
chip.clone(),
|
|
|
|
layouter.namespace(|| *name),
|
|
|
|
*magnitude,
|
|
|
|
*sign,
|
|
|
|
)?;
|
2022-01-27 13:15:41 -08:00
|
|
|
test_short.mul(layouter.namespace(|| *name), magnitude_sign)?
|
2021-09-27 03:14:01 -07:00
|
|
|
};
|
2021-12-08 16:49:01 -08:00
|
|
|
if let Some(is_identity) = result.inner().is_identity() {
|
|
|
|
assert!(is_identity);
|
|
|
|
}
|
2021-09-27 03:14:01 -07:00
|
|
|
}
|
|
|
|
|
2021-06-04 23:34:44 -07:00
|
|
|
Ok(())
|
|
|
|
}
|
2021-07-10 18:49:23 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn invalid_magnitude_sign() {
|
2022-01-27 13:53:10 -08:00
|
|
|
use crate::{
|
2021-08-18 23:59:39 -07:00
|
|
|
ecc::chip::{EccConfig, FixedPoint},
|
|
|
|
utilities::UtilitiesInstructions,
|
|
|
|
};
|
2022-01-27 15:28:02 -08:00
|
|
|
use halo2_proofs::{
|
2021-07-10 18:49:23 -07:00
|
|
|
circuit::{Layouter, SimpleFloorPlanner},
|
2022-01-04 23:02:21 -08:00
|
|
|
dev::{FailureLocation, MockProver, VerifyFailure},
|
2021-07-10 18:49:23 -07:00
|
|
|
plonk::{Circuit, ConstraintSystem, Error},
|
|
|
|
};
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
struct MyCircuit {
|
|
|
|
magnitude: Option<pallas::Base>,
|
|
|
|
sign: Option<pallas::Base>,
|
2021-11-23 16:21:44 -08:00
|
|
|
// For test checking
|
|
|
|
magnitude_error: Option<pallas::Base>,
|
2021-07-10 18:49:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl UtilitiesInstructions<pallas::Base> for MyCircuit {
|
2021-12-01 18:51:46 -08:00
|
|
|
type Var = AssignedCell<pallas::Base, pallas::Base>;
|
2021-07-10 18:49:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Circuit<pallas::Base> for MyCircuit {
|
2022-01-27 13:15:41 -08:00
|
|
|
type Config = EccConfig<TestFixedBases>;
|
2021-07-10 18:49:23 -07:00
|
|
|
type FloorPlanner = SimpleFloorPlanner;
|
|
|
|
|
|
|
|
fn without_witnesses(&self) -> Self {
|
|
|
|
Self::default()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
|
|
|
|
let advices = [
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
meta.advice_column(),
|
|
|
|
];
|
2021-07-27 10:32:32 -07:00
|
|
|
let lookup_table = meta.lookup_table_column();
|
2021-07-21 04:13:47 -07:00
|
|
|
let lagrange_coeffs = [
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
meta.fixed_column(),
|
|
|
|
];
|
2021-07-15 04:52:15 -07:00
|
|
|
|
2021-07-20 01:22:08 -07:00
|
|
|
// Shared fixed column for loading constants
|
|
|
|
let constants = meta.fixed_column();
|
|
|
|
meta.enable_constant(constants);
|
|
|
|
|
2021-07-21 07:59:08 -07:00
|
|
|
let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table);
|
2022-01-27 13:15:41 -08:00
|
|
|
EccChip::<TestFixedBases>::configure(meta, advices, lagrange_coeffs, range_check)
|
2021-07-10 18:49:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn synthesize(
|
|
|
|
&self,
|
|
|
|
config: Self::Config,
|
|
|
|
mut layouter: impl Layouter<pallas::Base>,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let column = config.advices[0];
|
|
|
|
|
2021-11-30 19:20:24 -08:00
|
|
|
let short_config = config.mul_fixed_short;
|
2021-07-10 18:49:23 -07:00
|
|
|
let magnitude_sign = {
|
|
|
|
let magnitude = self.load_private(
|
|
|
|
layouter.namespace(|| "load magnitude"),
|
|
|
|
column,
|
|
|
|
self.magnitude,
|
|
|
|
)?;
|
|
|
|
let sign =
|
|
|
|
self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?;
|
|
|
|
(magnitude, sign)
|
|
|
|
};
|
|
|
|
|
2022-01-27 13:15:41 -08:00
|
|
|
short_config.assign(layouter, magnitude_sign, &Short)?;
|
2021-07-10 18:49:23 -07:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-27 15:28:02 -08:00
|
|
|
// Copied from halo2_proofs::dev::util
|
2021-11-23 16:21:44 -08:00
|
|
|
fn format_value(v: pallas::Base) -> String {
|
|
|
|
use ff::Field;
|
|
|
|
if v.is_zero_vartime() {
|
|
|
|
"0".into()
|
|
|
|
} else if v == pallas::Base::one() {
|
|
|
|
"1".into()
|
|
|
|
} else if v == -pallas::Base::one() {
|
|
|
|
"-1".into()
|
|
|
|
} else {
|
|
|
|
// Format value as hex.
|
|
|
|
let s = format!("{:?}", v);
|
|
|
|
// Remove leading zeroes.
|
|
|
|
let s = s.strip_prefix("0x").unwrap();
|
|
|
|
let s = s.trim_start_matches('0');
|
|
|
|
format!("0x{}", s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-10 18:49:23 -07:00
|
|
|
// Magnitude larger than 64 bits should fail
|
|
|
|
{
|
2021-07-16 09:44:56 -07:00
|
|
|
let circuits = [
|
|
|
|
// 2^64
|
|
|
|
MyCircuit {
|
|
|
|
magnitude: Some(pallas::Base::from_u128(1 << 64)),
|
|
|
|
sign: Some(pallas::Base::one()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: Some(pallas::Base::from(1 << 1)),
|
2021-07-16 09:44:56 -07:00
|
|
|
},
|
|
|
|
// -2^64
|
|
|
|
MyCircuit {
|
|
|
|
magnitude: Some(pallas::Base::from_u128(1 << 64)),
|
|
|
|
sign: Some(-pallas::Base::one()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: Some(pallas::Base::from(1 << 1)),
|
2021-07-16 09:44:56 -07:00
|
|
|
},
|
|
|
|
// 2^66
|
|
|
|
MyCircuit {
|
|
|
|
magnitude: Some(pallas::Base::from_u128(1 << 66)),
|
|
|
|
sign: Some(pallas::Base::one()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: Some(pallas::Base::from(1 << 3)),
|
2021-07-16 09:44:56 -07:00
|
|
|
},
|
|
|
|
// -2^66
|
|
|
|
MyCircuit {
|
|
|
|
magnitude: Some(pallas::Base::from_u128(1 << 66)),
|
|
|
|
sign: Some(-pallas::Base::one()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: Some(pallas::Base::from(1 << 3)),
|
2021-07-16 09:44:56 -07:00
|
|
|
},
|
|
|
|
// 2^254
|
|
|
|
MyCircuit {
|
|
|
|
magnitude: Some(pallas::Base::from_u128(1 << 127).square()),
|
|
|
|
sign: Some(pallas::Base::one()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: Some(
|
|
|
|
pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2),
|
|
|
|
),
|
2021-07-16 09:44:56 -07:00
|
|
|
},
|
|
|
|
// -2^254
|
|
|
|
MyCircuit {
|
|
|
|
magnitude: Some(pallas::Base::from_u128(1 << 127).square()),
|
|
|
|
sign: Some(-pallas::Base::one()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: Some(
|
|
|
|
pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2),
|
|
|
|
),
|
2021-07-16 09:44:56 -07:00
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
for circuit in circuits.iter() {
|
|
|
|
let prover = MockProver::<pallas::Base>::run(11, circuit, vec![]).unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
prover.verify(),
|
|
|
|
Err(vec![
|
2021-07-19 04:57:50 -07:00
|
|
|
VerifyFailure::ConstraintNotSatisfied {
|
2021-07-16 09:44:56 -07:00
|
|
|
constraint: (
|
2021-09-28 13:49:06 -07:00
|
|
|
(17, "Short fixed-base mul gate").into(),
|
2021-07-16 09:44:56 -07:00
|
|
|
0,
|
|
|
|
"last_window_check"
|
|
|
|
)
|
|
|
|
.into(),
|
2022-01-04 23:02:21 -08:00
|
|
|
location: FailureLocation::InRegion {
|
|
|
|
region: (3, "Short fixed-base mul (most significant word)").into(),
|
|
|
|
offset: 1,
|
|
|
|
},
|
2021-11-23 16:21:44 -08:00
|
|
|
cell_values: vec![(
|
|
|
|
((Any::Advice, 5).into(), 0).into(),
|
|
|
|
format_value(circuit.magnitude_error.unwrap()),
|
|
|
|
)],
|
2021-07-20 01:22:08 -07:00
|
|
|
},
|
|
|
|
VerifyFailure::Permutation {
|
2021-07-22 07:14:34 -07:00
|
|
|
column: (Any::Fixed, 9).into(),
|
2022-03-29 18:39:50 -07:00
|
|
|
location: FailureLocation::OutsideRegion { row: 0 },
|
2021-07-20 01:22:08 -07:00
|
|
|
},
|
|
|
|
VerifyFailure::Permutation {
|
|
|
|
column: (Any::Advice, 4).into(),
|
2022-03-29 18:39:50 -07:00
|
|
|
location: FailureLocation::InRegion {
|
|
|
|
region: (2, "Short fixed-base mul (incomplete addition)").into(),
|
|
|
|
offset: 22,
|
|
|
|
},
|
2021-07-16 09:44:56 -07:00
|
|
|
}
|
|
|
|
])
|
|
|
|
);
|
|
|
|
}
|
2021-07-10 18:49:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sign that is not +/- 1 should fail
|
|
|
|
{
|
2021-11-23 16:21:44 -08:00
|
|
|
let magnitude_u64 = rand::random::<u64>();
|
2021-07-10 18:49:23 -07:00
|
|
|
let circuit = MyCircuit {
|
2021-12-07 09:47:03 -08:00
|
|
|
magnitude: Some(pallas::Base::from(magnitude_u64)),
|
2021-07-10 18:49:23 -07:00
|
|
|
sign: Some(pallas::Base::zero()),
|
2021-11-23 16:21:44 -08:00
|
|
|
magnitude_error: None,
|
|
|
|
};
|
|
|
|
|
|
|
|
let negation_check_y = {
|
2022-01-27 13:15:41 -08:00
|
|
|
*(Short.generator() * pallas::Scalar::from(magnitude_u64))
|
2021-11-23 16:21:44 -08:00
|
|
|
.to_affine()
|
|
|
|
.coordinates()
|
|
|
|
.unwrap()
|
|
|
|
.y()
|
2021-07-10 18:49:23 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
let prover = MockProver::<pallas::Base>::run(11, &circuit, vec![]).unwrap();
|
|
|
|
assert_eq!(
|
|
|
|
prover.verify(),
|
|
|
|
Err(vec![
|
2021-07-19 04:57:50 -07:00
|
|
|
VerifyFailure::ConstraintNotSatisfied {
|
2021-09-28 13:49:06 -07:00
|
|
|
constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check")
|
2021-07-10 18:49:23 -07:00
|
|
|
.into(),
|
2022-01-04 23:02:21 -08:00
|
|
|
location: FailureLocation::InRegion {
|
|
|
|
region: (3, "Short fixed-base mul (most significant word)").into(),
|
|
|
|
offset: 1,
|
|
|
|
},
|
2021-11-23 16:21:44 -08:00
|
|
|
cell_values: vec![(((Any::Advice, 4).into(), 0).into(), "0".to_string())],
|
2021-07-10 18:49:23 -07:00
|
|
|
},
|
2021-07-19 04:57:50 -07:00
|
|
|
VerifyFailure::ConstraintNotSatisfied {
|
2021-07-10 18:49:23 -07:00
|
|
|
constraint: (
|
2021-09-28 13:49:06 -07:00
|
|
|
(17, "Short fixed-base mul gate").into(),
|
2021-07-10 18:49:23 -07:00
|
|
|
3,
|
|
|
|
"negation_check"
|
|
|
|
)
|
|
|
|
.into(),
|
2022-01-04 23:02:21 -08:00
|
|
|
location: FailureLocation::InRegion {
|
|
|
|
region: (3, "Short fixed-base mul (most significant word)").into(),
|
|
|
|
offset: 1,
|
|
|
|
},
|
2021-11-23 16:21:44 -08:00
|
|
|
cell_values: vec![
|
|
|
|
(
|
|
|
|
((Any::Advice, 1).into(), 0).into(),
|
|
|
|
format_value(negation_check_y),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
((Any::Advice, 3).into(), 0).into(),
|
|
|
|
format_value(negation_check_y),
|
|
|
|
),
|
|
|
|
(((Any::Advice, 4).into(), 0).into(), "0".to_string()),
|
|
|
|
],
|
2021-07-10 18:49:23 -07:00
|
|
|
}
|
|
|
|
])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2021-06-04 23:34:44 -07:00
|
|
|
}
|