Skip to content

Commit

Permalink
OrchardZSA backward compatability using traits (#31)
Browse files Browse the repository at this point in the history
This commit contains the following modifications:
- Add tests for Lookup, ECC, Merkle, and Sinsemilla to verify that the verification key and the proof have not been modified by comparing them to those saved in a file.
- Introduce a `LookupRangeCheck` trait that provides common methods for a lookup range check.
- Use this new trait as a generic parameter in configs, chips and tests that are using lookup.
- Create a new Lookup chip which is optimized for 4, 5 and 10-bit range check and add tests for this new chip.
- Add `init_from_private_point` parameter in `SinsemillaConfig`. If this parameter is set to false, the `SinsemillaChip` is the same as the current `SinsemillaChip` used in vanilla circuit. Otherwise, the `SinsemillaChip` is modified to support hash from private point.

---------

Co-authored-by: YaoGalteland <[email protected]>
Co-authored-by: Dmitry Demin <[email protected]>
Co-authored-by: Constance Beguier <[email protected]>
  • Loading branch information
4 people authored Aug 8, 2024
1 parent 5f436dc commit 1195c9a
Show file tree
Hide file tree
Showing 52 changed files with 56,515 additions and 1,499 deletions.
55 changes: 28 additions & 27 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -125,33 +125,34 @@ jobs:
- name: Test halo2 book
run: mdbook test -L target/debug/deps book/

# codecov:
# name: Code coverage
# runs-on: ubuntu-latest
#
# steps:
# - uses: actions/checkout@v3
# # Use stable for this to ensure that cargo-tarpaulin can be built.
# - id: prepare
# uses: ./.github/actions/prepare
# with:
# toolchain: stable
# nightly-features: true
# - name: Install cargo-tarpaulin
# uses: actions-rs/cargo@v1
# with:
# command: install
# args: cargo-tarpaulin
# - name: Generate coverage report
# uses: actions-rs/cargo@v1
# with:
# command: tarpaulin
# args: >
# ${{ steps.prepare.outputs.feature-flags }}
# --timeout 600
# --out Xml
# - name: Upload coverage to Codecov
# uses: codecov/[email protected]
codecov:
name: Code coverage
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
# Use stable for this to ensure that cargo-tarpaulin can be built.
- id: prepare
uses: ./.github/actions/prepare
with:
toolchain: stable
nightly-features: true
- name: Install cargo-tarpaulin
uses: actions-rs/cargo@v1
with:
command: install
args: cargo-tarpaulin
- name: Generate coverage report
uses: actions-rs/cargo@v1
with:
command: tarpaulin
# Extend the timeout to 3600 to ensure the code coverage test pass
args: >
${{ steps.prepare.outputs.feature-flags }}
--timeout 3600
--out Xml
- name: Upload coverage to Codecov
uses: codecov/[email protected]

doc-links:
name: Intra-doc links
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

97 changes: 74 additions & 23 deletions halo2_gadgets/src/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,8 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
point.map(|inner| Point { chip, inner })
}

/// Constructs a new point with the given fixed value.
/// Witnesses the given constant point as a private input to the circuit.
/// This allows the point to be the identity, mapped to (0, 0) in affine coordinates.
pub fn new_from_constant(
chip: EccChip,
mut layouter: impl Layouter<C::Base>,
Expand Down Expand Up @@ -622,14 +623,7 @@ impl<C: CurveAffine, EccChip: EccInstructions<C>> FixedPointShort<C, EccChip> {
pub(crate) mod tests {
use ff::PrimeField;
use group::{prime::PrimeCurveAffine, Curve, Group};

use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
dev::MockProver,
plonk::{Circuit, ConstraintSystem, Error},
};
use lazy_static::lazy_static;
use pasta_curves::pallas;
use std::marker::PhantomData;

use super::{
chip::{
Expand All @@ -638,7 +632,19 @@ pub(crate) mod tests {
},
FixedPoints,
};
use crate::utilities::lookup_range_check::LookupRangeCheckConfig;
use crate::{
tests::test_utils::test_against_stored_circuit,
utilities::lookup_range_check::{
PallasLookupRangeCheck, PallasLookupRangeCheck4_5BConfig, PallasLookupRangeCheckConfig,
},
};
use halo2_proofs::{
circuit::{Layouter, SimpleFloorPlanner, Value},
dev::MockProver,
plonk::{Circuit, ConstraintSystem, Error},
};
use lazy_static::lazy_static;
use pasta_curves::pallas;

#[derive(Debug, Eq, PartialEq, Clone)]
pub(crate) struct TestFixedBases;
Expand Down Expand Up @@ -766,17 +772,27 @@ pub(crate) mod tests {
type Base = BaseField;
}

struct MyCircuit {
struct EccCircuit<Lookup: PallasLookupRangeCheck> {
test_errors: bool,
_lookup_marker: PhantomData<Lookup>,
}

impl<Lookup: PallasLookupRangeCheck> EccCircuit<Lookup> {
fn new(test_errors: bool) -> Self {
Self {
test_errors,
_lookup_marker: PhantomData,
}
}
}

#[allow(non_snake_case)]
impl Circuit<pallas::Base> for MyCircuit {
type Config = EccConfig<TestFixedBases>;
impl<Lookup: PallasLookupRangeCheck> Circuit<pallas::Base> for EccCircuit<Lookup> {
type Config = EccConfig<TestFixedBases, Lookup>;
type FloorPlanner = SimpleFloorPlanner;

fn without_witnesses(&self) -> Self {
MyCircuit { test_errors: false }
EccCircuit::new(false)
}

fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
Expand All @@ -793,7 +809,6 @@ pub(crate) mod tests {
meta.advice_column(),
];
let lookup_table = meta.lookup_table_column();
let table_range_check_tag = meta.lookup_table_column();
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
Expand All @@ -808,13 +823,13 @@ pub(crate) mod tests {
let constants = meta.fixed_column();
meta.enable_constant(constants);

let range_check = LookupRangeCheckConfig::configure(
let range_check = Lookup::configure(meta, advices[9], lookup_table);
EccChip::<TestFixedBases, Lookup>::configure(
meta,
advices[9],
lookup_table,
table_range_check_tag,
);
EccChip::<TestFixedBases>::configure(meta, advices, lagrange_coeffs, range_check)
advices,
lagrange_coeffs,
range_check,
)
}

fn synthesize(
Expand Down Expand Up @@ -953,11 +968,17 @@ pub(crate) mod tests {
#[test]
fn ecc_chip() {
let k = 13;
let circuit = MyCircuit { test_errors: true };
let circuit = EccCircuit::<PallasLookupRangeCheckConfig>::new(true);
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
assert_eq!(prover.verify(), Ok(()))
}

#[test]
fn test_ecc_chip_against_stored_circuit() {
let circuit = EccCircuit::<PallasLookupRangeCheckConfig>::new(false);
test_against_stored_circuit(circuit, "ecc_chip", 3872);
}

#[cfg(feature = "test-dev-graph")]
#[test]
fn print_ecc_chip() {
Expand All @@ -967,7 +988,37 @@ pub(crate) mod tests {
root.fill(&WHITE).unwrap();
let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap();

let circuit = MyCircuit { test_errors: false };
let circuit = EccCircuit::<PallasLookupRangeCheckConfig>::new(false);
halo2_proofs::dev::CircuitLayout::default()
.render(13, &circuit, &root)
.unwrap();
}

#[test]
fn ecc_chip_4_5b() {
let k = 13;
let circuit = EccCircuit::<PallasLookupRangeCheck4_5BConfig>::new(true);
let prover = MockProver::run(k, &circuit, vec![]).unwrap();

assert_eq!(prover.verify(), Ok(()))
}

#[test]
fn test_against_stored_ecc_chip_4_5b() {
let circuit = EccCircuit::<PallasLookupRangeCheck4_5BConfig>::new(false);
test_against_stored_circuit(circuit, "ecc_chip_4_5b", 3968);
}

#[cfg(feature = "test-dev-graph")]
#[test]
fn print_ecc_chip_4_5b() {
use plotters::prelude::*;

let root = BitMapBackend::new("ecc-chip-4_5b-layout.png", (1024, 7680)).into_drawing_area();
root.fill(&WHITE).unwrap();
let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap();

let circuit = EccCircuit::<PallasLookupRangeCheck4_5BConfig>::new(false);
halo2_proofs::dev::CircuitLayout::default()
.render(13, &circuit, &root)
.unwrap();
Expand Down
63 changes: 39 additions & 24 deletions halo2_gadgets/src/ecc/chip.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Chip implementations for the ECC gadgets.

use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints};
use crate::{
sinsemilla::primitives as sinsemilla,
utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
use crate::utilities::{
lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig},
UtilitiesInstructions,
};
use arrayvec::ArrayVec;

Expand Down Expand Up @@ -137,7 +137,10 @@ impl From<NonIdentityEccPoint> for EccPoint {
/// Configuration for [`EccChip`].
#[derive(Clone, Debug, Eq, PartialEq)]
#[allow(non_snake_case)]
pub struct EccConfig<FixedPoints: super::FixedPoints<pallas::Affine>> {
pub struct EccConfig<
FixedPoints: super::FixedPoints<pallas::Affine>,
Lookup: PallasLookupRangeCheck = PallasLookupRangeCheckConfig,
> {
/// Advice columns needed by instructions in the ECC chip.
pub advices: [Column<Advice>; 10],

Expand All @@ -148,20 +151,20 @@ pub struct EccConfig<FixedPoints: super::FixedPoints<pallas::Affine>> {
add: add::Config,

/// Variable-base scalar multiplication
mul: mul::Config,
mul: mul::Config<Lookup>,

/// Fixed-base full-width scalar multiplication
mul_fixed_full: mul_fixed::full_width::Config<FixedPoints>,
/// Fixed-base signed short scalar multiplication
mul_fixed_short: mul_fixed::short::Config<FixedPoints>,
/// Fixed-base mul using a base field element as a scalar
mul_fixed_base_field: mul_fixed::base_field_elem::Config<FixedPoints>,
mul_fixed_base_field: mul_fixed::base_field_elem::Config<FixedPoints, Lookup>,

/// Witness point
witness_point: witness_point::Config,

/// Lookup range check using 10-bit lookup table
pub lookup_config: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
pub lookup_config: Lookup,
}

/// A trait representing the kind of scalar used with a particular `FixedPoint`.
Expand Down Expand Up @@ -227,12 +230,17 @@ pub trait FixedPoint<C: CurveAffine>: std::fmt::Debug + Eq + Clone {

/// An [`EccInstructions`] chip that uses 10 advice columns.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EccChip<FixedPoints: super::FixedPoints<pallas::Affine>> {
config: EccConfig<FixedPoints>,
pub struct EccChip<
FixedPoints: super::FixedPoints<pallas::Affine>,
Lookup: PallasLookupRangeCheck = PallasLookupRangeCheckConfig,
> {
config: EccConfig<FixedPoints, Lookup>,
}

impl<FixedPoints: super::FixedPoints<pallas::Affine>> Chip<pallas::Base> for EccChip<FixedPoints> {
type Config = EccConfig<FixedPoints>;
impl<FixedPoints: super::FixedPoints<pallas::Affine>, Lookup: PallasLookupRangeCheck>
Chip<pallas::Base> for EccChip<FixedPoints, Lookup>
{
type Config = EccConfig<FixedPoints, Lookup>;
type Loaded = ();

fn config(&self) -> &Self::Config {
Expand All @@ -244,13 +252,15 @@ impl<FixedPoints: super::FixedPoints<pallas::Affine>> Chip<pallas::Base> for Ecc
}
}

impl<Fixed: super::FixedPoints<pallas::Affine>> UtilitiesInstructions<pallas::Base>
for EccChip<Fixed>
impl<Fixed: super::FixedPoints<pallas::Affine>, Lookup: PallasLookupRangeCheck>
UtilitiesInstructions<pallas::Base> for EccChip<Fixed, Lookup>
{
type Var = AssignedCell<pallas::Base, pallas::Base>;
}

impl<FixedPoints: super::FixedPoints<pallas::Affine>> EccChip<FixedPoints> {
impl<FixedPoints: super::FixedPoints<pallas::Affine>, Lookup: PallasLookupRangeCheck>
EccChip<FixedPoints, Lookup>
{
/// Reconstructs this chip from the given config.
pub fn construct(config: <Self as Chip<pallas::Base>>::Config) -> Self {
Self { config }
Expand All @@ -264,7 +274,7 @@ impl<FixedPoints: super::FixedPoints<pallas::Affine>> EccChip<FixedPoints> {
meta: &mut ConstraintSystem<pallas::Base>,
advices: [Column<Advice>; 10],
lagrange_coeffs: [Column<Fixed>; 8],
range_check: LookupRangeCheckConfig<pallas::Base, { sinsemilla::K }>,
range_check: Lookup,
) -> <Self as Chip<pallas::Base>>::Config {
// Create witness point gate
let witness_point = witness_point::Config::configure(meta, advices[0], advices[1]);
Expand Down Expand Up @@ -301,12 +311,13 @@ impl<FixedPoints: super::FixedPoints<pallas::Affine>> EccChip<FixedPoints> {
mul_fixed::short::Config::<FixedPoints>::configure(meta, mul_fixed.clone());

// Create gate that is only used in fixed-base mul using a base field element.
let mul_fixed_base_field = mul_fixed::base_field_elem::Config::<FixedPoints>::configure(
meta,
advices[6..9].try_into().unwrap(),
range_check,
mul_fixed,
);
let mul_fixed_base_field =
mul_fixed::base_field_elem::Config::<FixedPoints, Lookup>::configure(
meta,
advices[6..9].try_into().unwrap(),
range_check,
mul_fixed,
);

EccConfig {
advices,
Expand Down Expand Up @@ -407,7 +418,8 @@ pub enum ScalarVar {
FullWidth,
}

impl<Fixed: FixedPoints<pallas::Affine>> EccInstructions<pallas::Affine> for EccChip<Fixed>
impl<Fixed: FixedPoints<pallas::Affine>, Lookup: PallasLookupRangeCheck>
EccInstructions<pallas::Affine> for EccChip<Fixed, Lookup>
where
<Fixed as FixedPoints<pallas::Affine>>::Base:
FixedPoint<pallas::Affine, FixedScalarKind = BaseFieldElem>,
Expand Down Expand Up @@ -453,6 +465,9 @@ where
)
}

/// Witnesses the given constant point as a private input to the circuit.
/// This allows the point to be the identity, mapped to (0, 0) in
/// affine coordinates.
fn witness_point_from_constant(
&self,
layouter: &mut impl Layouter<pallas::Base>,
Expand Down Expand Up @@ -624,8 +639,8 @@ where
}
}

impl<Fixed: FixedPoints<pallas::Affine>> BaseFitsInScalarInstructions<pallas::Affine>
for EccChip<Fixed>
impl<Fixed: FixedPoints<pallas::Affine>, Lookup: PallasLookupRangeCheck>
BaseFitsInScalarInstructions<pallas::Affine> for EccChip<Fixed, Lookup>
where
<Fixed as FixedPoints<pallas::Affine>>::Base:
FixedPoint<pallas::Affine, FixedScalarKind = BaseFieldElem>,
Expand Down
Loading

0 comments on commit 1195c9a

Please sign in to comment.