Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimized ECC chip #73

Closed
wants to merge 49 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c9331b1
Add ECC chip
therealyingtong Apr 26, 2021
b752b92
Load ECC chip
therealyingtong May 18, 2021
46af16b
Add chip::util mod with assign_and_constrain() helper
therealyingtong Apr 26, 2021
ae288a2
Witness point
therealyingtong Apr 26, 2021
d6116d6
Point doubling
therealyingtong Apr 27, 2021
b67d1f7
Incomplete point addition
therealyingtong Apr 26, 2021
94d0cd3
Witness scalar for fixed-base mul
therealyingtong Apr 26, 2021
d8f02af
Fixed-base scalar mul
therealyingtong Apr 26, 2021
13d9024
Witness short signed scalar for fixed-base mul
therealyingtong Apr 26, 2021
5c4e307
Signed short fixed-base scalar mul
therealyingtong Apr 26, 2021
23bebc6
Complete addition
therealyingtong Apr 26, 2021
f751555
Witness scalar var
therealyingtong May 4, 2021
7182130
Variable-base scalar mul
therealyingtong Apr 26, 2021
05eb13c
Add ECC test
therealyingtong May 5, 2021
b58a8f5
Map point at infinity to (0,0) in complete addition
therealyingtong May 22, 2021
d9a95e9
Fix bug in complete addition gates
therealyingtong May 22, 2021
8f630d8
Comprehensive tests for complete and incomplete addition
therealyingtong May 22, 2021
eb5d829
Handle point at infinity in point doubling
therealyingtong May 22, 2021
62f3b3f
Comprehensive tests for fixed- and variable-base scalar mul
therealyingtong May 22, 2021
71c3f99
Check limit values for short fixed-base scalar mul
therealyingtong May 22, 2021
4909a93
Define separate configs for each operation
therealyingtong May 23, 2021
a236f63
Use complete addition for last addition in fixed-base scalar mul
therealyingtong May 24, 2021
6102e45
Document or remove unwrap()s
therealyingtong May 24, 2021
70d6a56
Refactor mul.rs into complete and incomplete submodules
therealyingtong May 25, 2021
46ac3f2
Fix bugs in complete addition formulae.
therealyingtong May 25, 2021
f911b70
Clean up load.rs
therealyingtong May 25, 2021
9a46d1f
Move double API to #[cfg(test]
therealyingtong May 25, 2021
a399085
Documentation and clippy fixes
therealyingtong May 25, 2021
acfc1be
Move all assignments out of Option.map() scopes
therealyingtong May 26, 2021
5497e15
Derive Eq for EccChip
therealyingtong May 28, 2021
4948479
Remove point doubling API.
therealyingtong May 28, 2021
b0d04f7
Define inv0() in add.rs
therealyingtong May 28, 2021
e539720
mul.rs: Replace Mul trait with free-floating functions
therealyingtong May 28, 2021
9beaf68
Remove misleading column names at top-level config.
therealyingtong May 28, 2021
13ebe78
Add check for a corner case of fixed-base scalar multiplication that …
daira May 28, 2021
381584f
Add check for a corner case of *short* fixed-base scalar multiplicati…
daira May 28, 2021
dbb6120
Reduce test boilerplate
therealyingtong May 29, 2021
ffa3d6e
Check endo_p_neg, endo_p_2_neg in complete addition tests
therealyingtong May 29, 2021
db95b5b
Test all fixed bases
therealyingtong May 29, 2021
a90b7f0
Remove EccLoaded struct and FixedPoint, FixedPointShort associated ty…
therealyingtong May 31, 2021
9a8a81b
mul_fixed: Remove MulFixed trait
therealyingtong May 31, 2021
a4f7128
chip: Directly use ValueCommitV as FixedPointsShort associated type
therealyingtong May 31, 2021
218efa2
mul_fixed: Use const generics to differentiate full-width vs short Co…
therealyingtong May 31, 2021
9303f8b
witness_scalar_fixed: Use const generics to differentiate full-width …
therealyingtong May 31, 2021
aeee55a
Documentation + variable naming cleanups
therealyingtong May 31, 2021
65ac816
Update to use multi-polynomial create_gate() API
therealyingtong Jun 2, 2021
9c30463
Rebase on Utilities chip
therealyingtong Jun 4, 2021
6d1059b
Remove unwrap() in tests
therealyingtong Jun 5, 2021
63751fa
Address review comments
therealyingtong Jun 5, 2021
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
240 changes: 187 additions & 53 deletions src/circuit/gadget/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use halo2::{
plonk::Error,
};

pub mod chip;

/// The set of circuit instructions required to use the ECC gadgets.
pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
/// Variable representing an element of the elliptic curve's base field, that
Expand Down Expand Up @@ -36,16 +38,10 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
/// Variable representing the affine short Weierstrass x-coordinate of an
/// elliptic curve point.
type X: Clone + Debug;
/// Variable representing the set of fixed bases in the circuit.
/// Enumeration of the set of fixed bases to be used in full-width scalar mul.
type FixedPoints: Clone + Debug;
/// Variable representing the set of fixed bases to be used in scalar
/// multiplication with a short signed exponent.
/// Enumeration of the set of fixed bases to be used in short signed scalar mul.
type FixedPointsShort: Clone + Debug;
/// Variable representing a fixed elliptic curve point (constant in the circuit).
type FixedPoint: Clone + Debug;
/// Variable representing a fixed elliptic curve point (constant in the circuit)
/// to be used in scalar multiplication with a short signed exponent.
type FixedPointShort: Clone + Debug;

/// Witnesses the given base field element as a private input to the circuit
/// for variable-base scalar mul.
Expand Down Expand Up @@ -81,18 +77,6 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
/// Extracts the x-coordinate of a point.
fn extract_p(point: &Self::Point) -> &Self::X;

/// Returns a fixed point that had been previously loaded into the circuit.
/// The pre-loaded cells are used to set up equality constraints in other
/// parts of the circuit where the fixed base is used.
fn get_fixed(&self, fixed_points: Self::FixedPoints) -> Result<Self::FixedPoint, Error>;

/// Returns a fixed point to be used in scalar multiplication with a signed
/// short exponent.
fn get_fixed_short(
&self,
fixed_points: Self::FixedPointsShort,
) -> Result<Self::FixedPointShort, Error>;

/// Performs incomplete point addition, returning `a + b`.
///
/// This returns an error in exceptional cases.
Expand All @@ -111,14 +95,8 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
b: &Self::Point,
) -> Result<Self::Point, Error>;

/// Performs point doubling, returning `[2] a`.
fn double(
&self,
layouter: &mut impl Layouter<C::Base>,
a: &Self::Point,
) -> Result<Self::Point, Error>;

/// Performs variable-base scalar multiplication, returning `[scalar] base`.
/// Multiplication of the identity `[scalar] 𝒪 ` returns an error.
fn mul(
&self,
layouter: &mut impl Layouter<C::Base>,
Expand All @@ -131,15 +109,15 @@ pub trait EccInstructions<C: CurveAffine>: Chip<C::Base> {
&self,
layouter: &mut impl Layouter<C::Base>,
scalar: &Self::ScalarFixed,
base: &Self::FixedPoint,
base: &Self::FixedPoints,
) -> Result<Self::Point, Error>;

/// Performs fixed-base scalar multiplication using a short signed scalar, returning `[scalar] base`.
fn mul_fixed_short(
&self,
layouter: &mut impl Layouter<C::Base>,
scalar: &Self::ScalarFixedShort,
base: &Self::FixedPointShort,
base: &Self::FixedPointsShort,
) -> Result<Self::Point, Error>;
}

Expand Down Expand Up @@ -174,12 +152,18 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> ScalarVar

/// A full-width element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul.
#[derive(Debug)]
pub struct ScalarFixed<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
pub struct ScalarFixed<C: CurveAffine, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
chip: EccChip,
inner: EccChip::ScalarFixed,
}

impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> ScalarFixed<C, EccChip> {
impl<C: CurveAffine, EccChip> ScalarFixed<C, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
/// Constructs a new ScalarFixed with the given value.
pub fn new(
chip: EccChip,
Expand All @@ -193,13 +177,17 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> ScalarFix

/// A signed short element of the given elliptic curve's scalar field, to be used for fixed-base scalar mul.
#[derive(Debug)]
pub struct ScalarFixedShort<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
pub struct ScalarFixedShort<C: CurveAffine, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
chip: EccChip,
inner: EccChip::ScalarFixedShort,
}

impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq>
ScalarFixedShort<C, EccChip>
impl<C: CurveAffine, EccChip> ScalarFixedShort<C, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
/// Constructs a new ScalarFixedShort with the given value.
///
Expand Down Expand Up @@ -231,7 +219,7 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq>
}

/// An elliptic curve point over the given curve.
#[derive(Debug)]
#[derive(Copy, Clone, Debug)]
pub struct Point<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
chip: EccChip,
inner: EccChip::Point,
Expand Down Expand Up @@ -318,18 +306,18 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> X<C, EccC
/// A constant elliptic curve point over the given curve, for which window tables have
/// been provided to make scalar multiplication more efficient.
#[derive(Clone, Debug)]
pub struct FixedPoint<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
pub struct FixedPoint<C: CurveAffine, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
chip: EccChip,
inner: EccChip::FixedPoint,
inner: EccChip::FixedPoints,
}

impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> FixedPoint<C, EccChip> {
/// Gets a reference to the specified fixed point in the circuit.
pub fn get(chip: EccChip, point: EccChip::FixedPoints) -> Result<Self, Error> {
chip.get_fixed(point)
.map(|inner| FixedPoint { chip, inner })
}

impl<C: CurveAffine, EccChip> FixedPoint<C, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
/// Returns `[by] self`.
pub fn mul(
&self,
Expand All @@ -344,23 +332,28 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> FixedPoin
inner,
})
}

/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPoints) -> Self {
FixedPoint { chip, inner }
}
}

/// A constant elliptic curve point over the given curve, used in scalar multiplication
/// with a short signed exponent
#[derive(Clone, Debug)]
pub struct FixedPointShort<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> {
pub struct FixedPointShort<C: CurveAffine, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
chip: EccChip,
inner: EccChip::FixedPointShort,
inner: EccChip::FixedPointsShort,
}

impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> FixedPointShort<C, EccChip> {
/// Gets a reference to the specified fixed point in the circuit.
pub fn get(chip: EccChip, point: EccChip::FixedPointsShort) -> Result<Self, Error> {
chip.get_fixed_short(point)
.map(|inner| FixedPointShort { chip, inner })
}

impl<C: CurveAffine, EccChip> FixedPointShort<C, EccChip>
where
EccChip: EccInstructions<C> + Clone + Debug + Eq,
{
/// Returns `[by] self`.
pub fn mul(
&self,
Expand All @@ -375,4 +368,145 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> FixedPoin
inner,
})
}

/// Wraps the given fixed base (obtained directly from an instruction) in a gadget.
pub fn from_inner(chip: EccChip, inner: EccChip::FixedPointsShort) -> Self {
FixedPointShort { chip, inner }
}
}

#[cfg(test)]
mod tests {
use group::{Curve, Group};
use halo2::{
arithmetic::CurveAffine,
circuit::{layouter::SingleChipLayouter, Layouter},
dev::MockProver,
pasta::pallas,
plonk::{Assignment, Circuit, ConstraintSystem, Error},
};

use super::chip::{EccChip, EccConfig};

struct MyCircuit<C: CurveAffine> {
_marker: std::marker::PhantomData<C>,
}

#[allow(non_snake_case)]
impl<C: CurveAffine> Circuit<C::Base> for MyCircuit<C> {
type Config = EccConfig;

fn configure(meta: &mut ConstraintSystem<C::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(),
];
daira marked this conversation as resolved.
Show resolved Hide resolved

let perm = meta.permutation(
&advices
.iter()
.map(|advice| (*advice).into())
.collect::<Vec<_>>(),
);

EccChip::<C>::configure(meta, advices, perm)
}

fn synthesize(
&self,
cs: &mut impl Assignment<C::Base>,
config: Self::Config,
) -> Result<(), Error> {
let mut layouter = SingleChipLayouter::new(cs)?;
let chip = EccChip::construct(config);

// Generate a random point P
let p_val = C::CurveExt::random(rand::rngs::OsRng).to_affine(); // P
let p = super::Point::new(chip.clone(), layouter.namespace(|| "point"), Some(p_val))?;
let p_neg = -p_val;
let p_neg =
super::Point::new(chip.clone(), layouter.namespace(|| "point"), Some(p_neg))?;

// Generate a random point Q
let q_val = C::CurveExt::random(rand::rngs::OsRng).to_affine(); // P
let q = super::Point::new(chip.clone(), layouter.namespace(|| "point"), Some(q_val))?;

// Make sure P and Q are not the same point.
assert_ne!(p_val, q_val);

// Generate a (0,0) point to be used in other tests.
let zero = p.add(layouter.namespace(|| "P + (-P)"), &p_neg)?;

// Test complete addition
{
super::chip::add::tests::test_add(
chip.clone(),
layouter.namespace(|| "complete addition"),
&zero,
p_val,
&p,
q_val,
&q,
&p_neg,
)?;
}
therealyingtong marked this conversation as resolved.
Show resolved Hide resolved

// Test incomplete addition
{
super::chip::add_incomplete::tests::test_add_incomplete(
layouter.namespace(|| "incomplete addition"),
&zero,
&p,
&q,
&p_neg,
)?;
}
therealyingtong marked this conversation as resolved.
Show resolved Hide resolved

// Test variable-base scalar multiplication
{
super::chip::mul::tests::test_mul(
chip.clone(),
layouter.namespace(|| "variable-base scalar mul"),
&zero,
&p,
)?;
}
therealyingtong marked this conversation as resolved.
Show resolved Hide resolved

// Test full-width fixed-base scalar multiplication
{
super::chip::mul_fixed::full_width::tests::test_mul_fixed(
chip.clone(),
layouter.namespace(|| "full-width fixed-base scalar mul"),
)?;
}
therealyingtong marked this conversation as resolved.
Show resolved Hide resolved

// Test signed short fixed-base scalar multiplication
{
super::chip::mul_fixed::short::tests::test_mul_fixed_short(
chip,
layouter.namespace(|| "signed short fixed-base scalar mul"),
)?;
}
therealyingtong marked this conversation as resolved.
Show resolved Hide resolved

Ok(())
}
}

#[test]
fn ecc() {
let k = 12;
let circuit = MyCircuit::<pallas::Affine> {
_marker: std::marker::PhantomData,
};
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
assert_eq!(prover.verify(), Ok(()))
}
}
Loading