Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,10 @@ members = [
"ecdsa",
"transcript"
]


[patch."https://github.com/privacy-scaling-explorations/halo2.git"]
halo2_proofs = { git = "https://github.com/davidnevadoc/halo2.git", branch = "test/feat-curve-endo" }

[patch."https://github.com/privacy-scaling-explorations/halo2curves.git"]
halo2curves = { git = "https://github.com/davidnevadoc/halo2curves.git", branch = "test/endo-export" }
1 change: 0 additions & 1 deletion ecc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ num-bigint = { version = "0.4", features = ["rand"] }
num-integer = "0.1"
num-traits = "0.2"
rand = "0.8"
group = "0.12"
subtle = { version = "2.3", default-features = false }

[dev-dependencies]
Expand Down
207 changes: 186 additions & 21 deletions ecc/src/base_field_ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use super::{make_mul_aux, AssignedPoint, EccConfig, MulAux, Point};
use crate::integer::chip::IntegerChip;
use crate::integer::rns::{Integer, Rns};
use crate::{halo2, maingate};
use halo2::arithmetic::CurveAffine;
use halo2::arithmetic::{CurveAffine, CurveEndo};
use halo2::circuit::Layouter;
use halo2::plonk::Error;
use integer::halo2::circuit::Value;
use integer::halo2::ff::WithSmallOrderMulGroup;
use integer::maingate::{MainGateInstructions, RegionCtx};
use integer::{IntegerInstructions, Range};
use maingate::{AssignedCondition, MainGate};
Expand All @@ -24,17 +25,54 @@ pub struct BaseFieldEccChip<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const
{
/// `IntegerChip` for the base field of the EC
integer_chip: IntegerChip<C::Base, C::Scalar, NUMBER_OF_LIMBS, BIT_LEN_LIMB>,

/// Auxiliary point for optimized multiplication algorithm
aux_generator: Option<(
AssignedPoint<C::Base, C::Scalar, NUMBER_OF_LIMBS, BIT_LEN_LIMB>,
Value<C>,
)>,
/// Auxiliary points for optimized multiplication for each (window_size,
/// n_pairs) pairs

/// Auxiliary points for optimized multiplication for each
/// (window_size, n_pairs) pairs
aux_registry:
BTreeMap<(usize, usize), AssignedPoint<C::Base, C::Scalar, NUMBER_OF_LIMBS, BIT_LEN_LIMB>>,
}

/// Elliptic Curve instructions that use the emulated curve efficient endomorphism.
#[derive(Debug, Clone)]
pub struct BaseFieldEndoEccChip<
C: CurveEndo,
const NUMBER_OF_LIMBS: usize,
const BIT_LEN_LIMB: usize,
> {
ecc_chip: BaseFieldEccChip<C::AffineExt, NUMBER_OF_LIMBS, BIT_LEN_LIMB>,
}

impl<C: CurveEndo, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>
BaseFieldEndoEccChip<C, NUMBER_OF_LIMBS, BIT_LEN_LIMB>
{
/// Return `EndoEccChip` from `EccChip`
pub fn new(ecc_chip: BaseFieldEccChip<C::AffineExt, NUMBER_OF_LIMBS, BIT_LEN_LIMB>) -> Self {
Self { ecc_chip }
}
}

impl<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>
BaseFieldEccChip<C, NUMBER_OF_LIMBS, BIT_LEN_LIMB>
{
/// Computes the endomorphism of a given point using one base field multplication.
pub fn endo(
&self,
ctx: &mut RegionCtx<'_, C::Scalar>,
point: &AssignedPoint<C::Base, C::Scalar, NUMBER_OF_LIMBS, BIT_LEN_LIMB>,
) -> Result<AssignedPoint<C::Base, C::Scalar, NUMBER_OF_LIMBS, BIT_LEN_LIMB>, Error> {
let integer_chip = self.integer_chip();
let zeta = Integer::from_fe(C::Base::ZETA, self.rns());
let x = integer_chip.mul_constant(ctx, point.x(), &zeta)?;
Ok(AssignedPoint::new(x, point.y().clone()))
}
}

impl<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>
BaseFieldEccChip<C, NUMBER_OF_LIMBS, BIT_LEN_LIMB>
{
Expand Down Expand Up @@ -101,11 +139,7 @@ impl<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>
// see https://hackmd.io/ncuKqRXzR-Cw-Au2fGzsMg?view
Ok(MulAux::new(to_add, to_sub))
}
}

impl<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>
BaseFieldEccChip<C, NUMBER_OF_LIMBS, BIT_LEN_LIMB>
{
/// Expose `AssignedPoint` as Public Input
pub fn expose_public(
&self,
Expand Down Expand Up @@ -182,10 +216,12 @@ impl<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>
ctx: &mut RegionCtx<'_, C::Scalar>,
window_size: usize,
number_of_pairs: usize,
n_bits: usize, // number of bits of the scalar
) -> Result<(), Error> {
match self.aux_generator {
Some((_, point)) => {
let aux = point.map(|point| make_mul_aux(point, window_size, number_of_pairs));
let aux =
point.map(|point| make_mul_aux(point, window_size, number_of_pairs, n_bits));
let aux = self.assign_point(ctx, aux)?;
self.aux_registry
.insert((window_size, number_of_pairs), aux);
Expand Down Expand Up @@ -340,21 +376,22 @@ impl<C: CurveAffine, const NUMBER_OF_LIMBS: usize, const BIT_LEN_LIMB: usize>

#[cfg(test)]
mod tests {
use std::marker::PhantomData;
use std::rc::Rc;

use super::BaseFieldEccChip;
use super::BaseFieldEndoEccChip;
use super::{AssignedPoint, EccConfig, Point};
use crate::curves::bn256::G1Affine as Bn256;
use crate::curves::pasta::{EpAffine as Pallas, EqAffine as Vesta};
use crate::halo2;
use crate::integer::rns::Rns;
use crate::integer::NUMBER_OF_LOOKUP_LIMBS;
use crate::maingate;
use group::{Curve as _, Group};
use halo2::arithmetic::{CurveAffine, FieldExt};
use halo2::arithmetic::CurveAffine;
use halo2::circuit::{Layouter, SimpleFloorPlanner, Value};
use halo2::plonk::{Circuit, ConstraintSystem, Error};
use integer::halo2::curves::CurveEndo;
use integer::halo2::ff::{Field, FromUniformBytes, PrimeField};
use integer::halo2::group::Curve;
use integer::halo2::group::Group;
use integer::maingate::RegionCtx;
use maingate::mock_prover_verify;
use maingate::{
Expand All @@ -363,6 +400,8 @@ mod tests {
};
use paste::paste;
use rand_core::OsRng;
use std::marker::PhantomData;
use std::rc::Rc;

const NUMBER_OF_LIMBS: usize = 4;
const BIT_LEN_LIMB: usize = 68;
Expand Down Expand Up @@ -419,7 +458,10 @@ mod tests {
}
}

fn config_range<N: FieldExt>(&self, layouter: &mut impl Layouter<N>) -> Result<(), Error> {
fn config_range<N: PrimeField>(
&self,
layouter: &mut impl Layouter<N>,
) -> Result<(), Error> {
let range_chip = RangeChip::<N>::new(self.range_config.clone());
range_chip.load_table(layouter)?;

Expand Down Expand Up @@ -505,7 +547,10 @@ mod tests {

#[test]
fn test_base_field_ecc_addition_circuit() {
fn run<C: CurveAffine>() {
fn run<C: CurveAffine>()
where
C::Scalar: FromUniformBytes<64>,
{
let circuit = TestEccAddition::<C>::default();
let instance = vec![vec![]];
mock_prover_verify(&circuit, instance);
Expand Down Expand Up @@ -580,7 +625,10 @@ mod tests {

#[test]
fn test_base_field_ecc_public_input() {
fn run<C: CurveAffine>() {
fn run<C: CurveAffine>()
where
C::Scalar: FromUniformBytes<64>,
{
let (rns, _) = setup::<C>(20);
let rns = Rc::new(rns);

Expand Down Expand Up @@ -641,7 +689,7 @@ mod tests {
let offset = 0;
let ctx = &mut RegionCtx::new(region, offset);
ecc_chip.assign_aux_generator(ctx, Value::known(self.aux_generator))?;
ecc_chip.assign_aux(ctx, self.window_size, 1)?;
ecc_chip.assign_aux(ctx, self.window_size, 1, C::Scalar::NUM_BITS as usize)?;
ecc_chip.get_mul_aux(self.window_size, 1)?;
Ok(())
},
Expand All @@ -650,7 +698,6 @@ mod tests {
layouter.assign_region(
|| "region 0",
|region| {
use group::ff::Field;
let offset = 0;
let ctx = &mut RegionCtx::new(region, offset);

Expand All @@ -677,7 +724,10 @@ mod tests {

#[test]
fn test_base_field_ecc_mul_circuit() {
fn run<C: CurveAffine>() {
fn run<C: CurveAffine>()
where
C::Scalar: FromUniformBytes<64>,
{
for window_size in 1..5 {
let aux_generator = <C as CurveAffine>::CurveExt::random(OsRng).to_affine();

Expand Down Expand Up @@ -730,7 +780,12 @@ mod tests {
let offset = 0;
let ctx = &mut RegionCtx::new(region, offset);
ecc_chip.assign_aux_generator(ctx, Value::known(self.aux_generator))?;
ecc_chip.assign_aux(ctx, self.window_size, self.number_of_pairs)?;
ecc_chip.assign_aux(
ctx,
self.window_size,
self.number_of_pairs,
C::Scalar::NUM_BITS as usize,
)?;
ecc_chip.get_mul_aux(self.window_size, self.number_of_pairs)?;
Ok(())
},
Expand All @@ -739,7 +794,6 @@ mod tests {
layouter.assign_region(
|| "region 0",
|region| {
use group::ff::Field;
let offset = 0;
let ctx = &mut RegionCtx::new(region, offset);

Expand Down Expand Up @@ -799,4 +853,115 @@ mod tests {
test_base_field_ecc_mul_batch_circuit!(Bn256);
test_base_field_ecc_mul_batch_circuit!(Pallas);
test_base_field_ecc_mul_batch_circuit!(Vesta);

#[derive(Default, Clone, Debug)]
struct TestEccEndoMul<C: CurveEndo> {
window_size: usize,
aux_generator: C::AffineExt,
}

impl<C: CurveEndo> Circuit<<C::AffineExt as CurveAffine>::ScalarExt> for TestEccEndoMul<C> {
type Config = TestCircuitConfig;
type FloorPlanner = SimpleFloorPlanner;

fn without_witnesses(&self) -> Self {
unimplemented!();
}

fn configure(
meta: &mut ConstraintSystem<<C::AffineExt as CurveAffine>::ScalarExt>,
) -> Self::Config {
TestCircuitConfig::new::<C::AffineExt>(meta)
}

fn synthesize(
&self,
config: Self::Config,
mut layouter: impl Layouter<<C::AffineExt as CurveAffine>::ScalarExt>,
) -> Result<(), Error> {
let ecc_chip_config = config.ecc_chip_config();
let mut ecc_endo_chip =
BaseFieldEndoEccChip::<C, NUMBER_OF_LIMBS, BIT_LEN_LIMB>::new(BaseFieldEccChip::<
C::AffineExt,
NUMBER_OF_LIMBS,
BIT_LEN_LIMB,
>::new(
ecc_chip_config
));

let main_gate = MainGate::<C::ScalarExt>::new(config.main_gate_config.clone());

layouter.assign_region(
|| "assign aux values",
|region| {
let offset = 0;
let ctx = &mut RegionCtx::new(region, offset);
ecc_endo_chip
.ecc_chip
.assign_aux_generator(ctx, Value::known(self.aux_generator))?;
// we set n_pairs=2 because the scalar is split into 2 128-bit scalars
ecc_endo_chip
.ecc_chip
.assign_aux(ctx, self.window_size, 2, 128)?;
ecc_endo_chip.ecc_chip.get_mul_aux(self.window_size, 2)?;
Ok(())
},
)?;

layouter.assign_region(
|| "region 0",
|region| {
let offset = 0;
let ctx = &mut RegionCtx::new(region, offset);

let base = C::random(OsRng);
let s = C::ScalarExt::random(OsRng);
let result = base * s;

let base = ecc_endo_chip
.ecc_chip
.assign_point(ctx, Value::known(base.into()))?;
let s = main_gate.assign_value(ctx, Value::known(s))?;

let result_0 = ecc_endo_chip
.ecc_chip
.assign_point(ctx, Value::known(result.into()))?;

let result_1 = ecc_endo_chip.glv_mul(ctx, &base, &s, self.window_size)?;
ecc_endo_chip
.ecc_chip
.assert_equal(ctx, &result_0, &result_1)?;

Ok(())
},
)?;

config.config_range(&mut layouter)?;

Ok(())
}
}

#[test]
fn test_base_field_ecc_endo_mul_circuit() {
fn run<C: CurveEndo>()
where
<C::AffineExt as CurveAffine>::ScalarExt: FromUniformBytes<64> + Ord,
{
for window_size in 2..4 {
let aux_generator = C::random(OsRng).to_affine();

let circuit = TestEccEndoMul::<C> {
aux_generator,
window_size,
};
let instance: Vec<Vec<<C::AffineExt as CurveAffine>::ScalarExt>> = vec![vec![]];
mock_prover_verify(&circuit, instance);
}
}

run::<crate::curves::bn256::G1>(); // G1
run::<crate::curves::pasta::Eq>(); // Vesta
run::<crate::curves::pasta::Ep>(); // Pallas
}
}
Loading