Skip to content

Commit

Permalink
sync with v0.4.1-rc (#239)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanpwang authored Dec 21, 2023
2 parents 93f2567 + 3bdcfda commit 8cdbf54
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 92 deletions.
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ cargo test --release --no-default-features --features "halo2-axiom, mimalloc" --
- [halo2-rsa](https://github.com/zkemail/halo2-rsa/tree/feat/new_bigint)
- [halo2-fri-gadget](https://github.com/maxgillett/halo2-fri-gadget) -- FRI verifier in halo2.
- [eth-voice-recovery](https://github.com/SoraSuegami/voice_recovery_circuit)
- [zkevm signature verification circuit](https://github.com/scroll-tech/zkevm-circuits/tree/develop/zkevm-circuits/src/sig_circuit.rs)
<<<<<<< HEAD
- # [zkevm signature verification circuit](https://github.com/scroll-tech/zkevm-circuits/tree/develop/zkevm-circuits/src/sig_circuit.rs)
- [zkevm tx-circuit](https://github.com/scroll-tech/zkevm-circuits/tree/develop/zkevm-circuits/src/tx_circuit)
> > > > > > > release-0.4.1-rc
- [webauthn-halo2](https://github.com/zkwebauthn/webauthn-halo2) -- Proving and verifying WebAuthn with halo2.
- [Fixed Point Arithmetic](https://github.com/DCMMC/halo2-scaffold/tree/main/src/gadget) -- Fixed point arithmetic library in halo2.
12 changes: 6 additions & 6 deletions halo2-base/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "halo2-base"
version = "0.4.0"
version = "0.4.1"
edition = "2021"

[dependencies]
Expand Down Expand Up @@ -29,7 +29,7 @@ poseidon-rs = { package = "poseidon-primitives", version = "=0.1.1" }
plotters = { version = "0.3.0", optional = true }

# test-utils
rand={ version="0.8", optional=true }
rand = { version = "0.8", optional = true }

[dev-dependencies]
ark-std = { version = "0.3.0", features = ["print-trace"] }
Expand All @@ -46,9 +46,9 @@ pse-poseidon = { git = "https://github.com/axiom-crypto/pse-poseidon.git" }

# memory allocation
[target.'cfg(not(target_env = "msvc"))'.dependencies]
jemallocator={ version="=0.5", optional=true }
jemallocator = { version = "=0.5", optional = true }

mimalloc={ version="=0.1", default-features=false, optional=true }
mimalloc = { version = "=0.1", default-features = false, optional = true }

[features]
default = ["halo2-axiom", "display", "test-utils"]
Expand All @@ -61,8 +61,8 @@ profile = ["halo2_proofs_axiom?/profile"]
test-utils = ["dep:rand", "ark-std"]

[[bench]]
name="mul"
harness=false
name = "mul"
harness = false

[[bench]]
name = "inner_product"
Expand Down
10 changes: 8 additions & 2 deletions halo2-base/src/gates/flex_gate/threads/single_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,15 @@ pub fn assign_with_constraints<F: ScalarField, const ROTATIONS: usize>(
.assign_advice(|| "", column, row_offset, || value.map(|v| *v))
.unwrap()
.cell();
copy_manager
if let Some(old_cell) = copy_manager
.assigned_advices
.insert(ContextCell::new(ctx.type_id, ctx.context_id, i), cell);
.insert(ContextCell::new(ctx.type_id, ctx.context_id, i), cell)
{
assert!(
old_cell.row_offset == cell.row_offset && old_cell.column == cell.column,
"Trying to overwrite virtual cell with a different raw cell"
);
}

// If selector enabled and row_offset is valid add break point, account for break point overlap, and enforce equality constraint for gate outputs.
// ⚠️ This assumes overlap is of form: gate enabled at `i - delta` and `i`, where `delta = ROTATIONS - 1`. We currently do not support `delta < ROTATIONS - 1`.
Expand Down
128 changes: 99 additions & 29 deletions halo2-base/src/utils/halo2.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use std::collections::hash_map::Entry;

use crate::ff::Field;
use crate::halo2_proofs::{
circuit::{AssignedCell, Cell, Region, Value},
plonk::{Advice, Assigned, Column, Fixed},
plonk::{Advice, Assigned, Circuit, Column, Fixed},
};
use crate::virtual_region::copy_constraints::{CopyConstraintManager, SharedCopyConstraintManager};
use crate::virtual_region::copy_constraints::{CopyConstraintManager, EXTERNAL_CELL_TYPE_ID};
use crate::AssignedValue;

/// Raw (physical) assigned cell in Plonkish arithmetization.
Expand Down Expand Up @@ -74,30 +76,11 @@ pub fn raw_constrain_equal<F: Field>(region: &mut Region<F>, left: Cell, right:
region.constrain_equal(left, right).unwrap();
}

/// Assign virtual cell to raw halo2 cell in column `column` at row offset `offset` within the `region`.
/// Stores the mapping between `virtual_cell` and the raw assigned cell in `copy_manager`, if provided.
///
/// `copy_manager` **must** be provided unless you are only doing witness generation
/// without constraints.
pub fn assign_virtual_to_raw<'v, F: Field + Ord>(
region: &mut Region<F>,
column: Column<Advice>,
offset: usize,
virtual_cell: AssignedValue<F>,
copy_manager: Option<&SharedCopyConstraintManager<F>>,
) -> Halo2AssignedCell<'v, F> {
let raw = raw_assign_advice(region, column, offset, Value::known(virtual_cell.value));
if let Some(copy_manager) = copy_manager {
let mut copy_manager = copy_manager.lock().unwrap();
let cell = virtual_cell.cell.unwrap();
copy_manager.assigned_advices.insert(cell, raw.cell());
drop(copy_manager);
}
raw
}

/// Constrains that `virtual` is equal to `external`. The `virtual` cell must have
/// **already** been raw assigned, with the raw assigned cell stored in `copy_manager`.
/// Constrains that `virtual_cell` is equal to `external_cell`. The `virtual_cell` must have
/// already been raw assigned with the raw assigned cell stored in `copy_manager`
/// **unless** it is marked an external-only cell with type id [EXTERNAL_CELL_TYPE_ID].
/// * When the virtual cell has already been assigned, the assigned cell is constrained to be equal to the external cell.
/// * When the virtual cell has not been assigned **and** it is marked as an external cell, it is assigned to `external_cell` and the mapping is stored in `copy_manager`.
///
/// This should only be called when `witness_gen_only` is false, otherwise it will panic.
///
Expand All @@ -107,9 +90,96 @@ pub fn constrain_virtual_equals_external<F: Field + Ord>(
region: &mut Region<F>,
virtual_cell: AssignedValue<F>,
external_cell: Cell,
copy_manager: &CopyConstraintManager<F>,
copy_manager: &mut CopyConstraintManager<F>,
) {
let ctx_cell = virtual_cell.cell.unwrap();
let acell = copy_manager.assigned_advices.get(&ctx_cell).expect("cell not assigned");
region.constrain_equal(*acell, external_cell);
match copy_manager.assigned_advices.entry(ctx_cell) {
Entry::Occupied(acell) => {
// The virtual cell has already been assigned, so we can constrain it to equal the external cell.
region.constrain_equal(*acell.get(), external_cell);
}
Entry::Vacant(assigned) => {
// The virtual cell **must** be an external cell
assert_eq!(ctx_cell.type_id, EXTERNAL_CELL_TYPE_ID);
// We map the virtual cell to point to the raw external cell in `copy_manager`
assigned.insert(external_cell);
}
}
}

/// This trait should be implemented on the minimal circuit configuration data necessary to
/// completely determine a circuit (independent of circuit inputs).
/// This is used to generate a _dummy_ instantiation of a concrete `Circuit` type for the purposes of key generation.
/// This dummy instantiation just needs to have the correct arithmetization format, but the witnesses do not need to
/// satisfy constraints.
pub trait KeygenCircuitIntent<F: Field> {
/// Concrete circuit type
type ConcreteCircuit: Circuit<F>;
/// Additional data that "pins" down the circuit. These can always to deterministically rederived from `Self`, but
/// storing the `Pinning` saves recomputations in future proof generations.
type Pinning;

/// The intent must include the log_2 domain size of the circuit.
/// This is used to get the correct trusted setup file.
fn get_k(&self) -> u32;

/// Builds a _dummy_ instantiation of `Self::ConcreteCircuit` for the purposes of key generation.
/// This dummy instantiation just needs to have the correct arithmetization format, but the witnesses do not need to
/// satisfy constraints.
fn build_keygen_circuit(self) -> Self::ConcreteCircuit;

/// Pinning is only fully computed after `synthesize` has been run during keygen
fn get_pinning_after_keygen(
self,
kzg_params: &ParamsKZG<Bn256>,
circuit: &Self::ConcreteCircuit,
) -> Self::Pinning;
}

use halo2_proofs_axiom::halo2curves::bn256::Bn256;
use halo2_proofs_axiom::poly::kzg::commitment::ParamsKZG;
pub use keygen::ProvingKeyGenerator;

mod keygen {
use halo2_proofs_axiom::poly::commitment::Params;

use crate::halo2_proofs::{
halo2curves::bn256::{Bn256, Fr, G1Affine},
plonk::{self, ProvingKey},
poly::kzg::commitment::ParamsKZG,
};

use super::KeygenCircuitIntent;

/// Trait for creating a proving key and a pinning for a circuit from minimal circuit configuration data.
pub trait ProvingKeyGenerator {
/// Create proving key and pinning.
fn create_pk_and_pinning(
self,
kzg_params: &ParamsKZG<Bn256>,
) -> (ProvingKey<G1Affine>, serde_json::Value);
}

impl<CI> ProvingKeyGenerator for CI
where
CI: KeygenCircuitIntent<Fr> + Clone,
CI::Pinning: serde::Serialize,
{
fn create_pk_and_pinning(
self,
kzg_params: &ParamsKZG<Bn256>,
) -> (ProvingKey<G1Affine>, serde_json::Value) {
assert_eq!(kzg_params.k(), self.get_k());
let circuit = self.clone().build_keygen_circuit();
#[cfg(feature = "halo2-axiom")]
let pk = plonk::keygen_pk2(kzg_params, &circuit, false).unwrap();
#[cfg(not(feature = "halo2-axiom"))]
let pk = {
let vk = plonk::keygen_vk_custom(kzg_params, &circuit, false).unwrap();
plonk::keygen_pk(kzg_params, vk, &circuit).unwrap()
};
let pinning = self.get_pinning_after_keygen(kzg_params, &circuit);
(pk, serde_json::to_value(pinning).unwrap())
}
}
}
13 changes: 10 additions & 3 deletions halo2-base/src/virtual_region/copy_constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ use crate::{ff::Field, ContextCell};

use super::manager::VirtualRegionManager;

/// Type ID to distinguish external raw Halo2 cells. **This Type ID must be unique.**
pub const EXTERNAL_CELL_TYPE_ID: &str = "halo2-base:External Raw Halo2 Cell";

/// Thread-safe shared global manager for all copy constraints.
pub type SharedCopyConstraintManager<F> = Arc<Mutex<CopyConstraintManager<F>>>;

Expand Down Expand Up @@ -86,11 +89,15 @@ impl<F: Field + Ord> CopyConstraintManager<F> {
}

fn load_external_cell_impl(&mut self, cell: Option<Cell>) -> ContextCell {
let context_cell =
ContextCell::new("halo2-base:External Raw Halo2 Cell", 0, self.external_cell_count);
let context_cell = ContextCell::new(EXTERNAL_CELL_TYPE_ID, 0, self.external_cell_count);
self.external_cell_count += 1;
if let Some(cell) = cell {
self.assigned_advices.insert(context_cell, cell);
if let Some(old_cell) = self.assigned_advices.insert(context_cell, cell) {
assert!(
old_cell.row_offset == cell.row_offset && old_cell.column == cell.column,
"External cell already assigned"
)
}
}
context_cell
}
Expand Down
5 changes: 3 additions & 2 deletions halo2-base/src/virtual_region/lookups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ impl<F: Field + Ord, const ADVICE_COLS: usize> VirtualRegionManager<F>
type Config = Vec<[Column<Advice>; ADVICE_COLS]>;

fn assign_raw(&self, config: &Self::Config, region: &mut Region<F>) {
let copy_manager = (!self.witness_gen_only).then(|| self.copy_manager().lock().unwrap());
let mut copy_manager =
(!self.witness_gen_only).then(|| self.copy_manager().lock().unwrap());
let cells_to_lookup = self.cells_to_lookup.lock().unwrap();
// Copy the cells to the config columns, going left to right, then top to bottom.
// Will panic if out of rows
Expand All @@ -139,7 +140,7 @@ impl<F: Field + Ord, const ADVICE_COLS: usize> VirtualRegionManager<F>
for (advice, &column) in advices.iter().zip(config[lookup_col].iter()) {
let bcell =
raw_assign_advice(region, column, lookup_offset, Value::known(advice.value));
if let Some(copy_manager) = copy_manager.as_ref() {
if let Some(copy_manager) = copy_manager.as_mut() {
constrain_virtual_equals_external(region, *advice, bcell.cell(), copy_manager);
}
}
Expand Down
25 changes: 15 additions & 10 deletions halo2-base/src/virtual_region/lookups/basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@ use crate::{
poly::Rotation,
},
utils::{
halo2::{
assign_virtual_to_raw, constrain_virtual_equals_external, raw_assign_advice,
raw_assign_fixed,
},
halo2::{constrain_virtual_equals_external, raw_assign_advice, raw_assign_fixed},
ScalarField,
},
virtual_region::copy_constraints::SharedCopyConstraintManager,
Expand Down Expand Up @@ -83,7 +80,7 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
Self { table_is_enabled, table, to_lookup }
}

/// Assign managed lookups
/// Assign managed lookups. The `keys` must have already been raw assigned beforehand.
///
/// `copy_manager` **must** be provided unless you are only doing witness generation
/// without constraints.
Expand Down Expand Up @@ -114,6 +111,8 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
.unwrap();
}

/// Assign managed lookups. The `keys` must have already been raw assigned beforehand.
///
/// `copy_manager` **must** be provided unless you are only doing witness generation
/// without constraints.
pub fn assign_virtual_to_lookup_to_raw_from_offset<F: ScalarField>(
Expand All @@ -123,7 +122,7 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
mut offset: usize,
copy_manager: Option<&SharedCopyConstraintManager<F>>,
) {
let copy_manager = copy_manager.map(|c| c.lock().unwrap());
let mut copy_manager = copy_manager.map(|c| c.lock().unwrap());
// Copied from `LookupAnyManager::assign_raw` but modified to set `key_is_enabled` to 1.
// Copy the cells to the config columns, going left to right, then top to bottom.
// Will panic if out of rows
Expand All @@ -138,7 +137,7 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
raw_assign_fixed(region, key_is_enabled_col, offset, F::ONE);
for (advice, column) in zip(key, key_col) {
let bcell = raw_assign_advice(region, column, offset, Value::known(advice.value));
if let Some(copy_manager) = copy_manager.as_ref() {
if let Some(copy_manager) = copy_manager.as_mut() {
constrain_virtual_equals_external(region, advice, bcell.cell(), copy_manager);
}
}
Expand All @@ -147,7 +146,7 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
}
}

/// Assign virtual table to raw.
/// Assign virtual table to raw. The `rows` must have already been raw assigned beforehand.
///
/// `copy_manager` **must** be provided unless you are only doing witness generation
/// without constraints.
Expand Down Expand Up @@ -178,6 +177,8 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
.unwrap();
}

/// Assign virtual table to raw. The `rows` must have already been raw assigned beforehand.
///
/// `copy_manager` **must** be provided unless you are only doing witness generation
/// without constraints.
pub fn assign_virtual_table_to_raw_from_offset<F: ScalarField>(
Expand All @@ -187,11 +188,15 @@ impl<const KEY_COL: usize> BasicDynLookupConfig<KEY_COL> {
mut offset: usize,
copy_manager: Option<&SharedCopyConstraintManager<F>>,
) {
let mut copy_manager = copy_manager.map(|c| c.lock().unwrap());
for row in rows {
// Enable this row in the table
raw_assign_fixed(region, self.table_is_enabled, offset, F::ONE);
for (col, virtual_cell) in self.table.into_iter().zip(row) {
assign_virtual_to_raw(region, col, offset, virtual_cell, copy_manager);
for (advice, column) in zip(row, self.table) {
let bcell = raw_assign_advice(region, column, offset, Value::known(advice.value));
if let Some(copy_manager) = copy_manager.as_mut() {
constrain_virtual_equals_external(region, advice, bcell.cell(), copy_manager);
}
}
offset += 1;
}
Expand Down
Loading

0 comments on commit 8cdbf54

Please sign in to comment.