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

Release v0.4.1 #214

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
17d297b
Revert "chore: pin snark-verifier branch"
jonathanpwang Sep 11, 2023
26b81a3
[rename] (coprocessor, leaf) -> (component, shard) (#161)
jonathanpwang Sep 18, 2023
d3828a4
[fix] Multiple Phase Lookup (#162)
nyunyunyunyu Sep 19, 2023
215fe1c
[chore] add conversion `SafePrimitive` to `QuantumCell::Existing` (#169)
jonathanpwang Sep 26, 2023
524c818
fix: bad import on halo2-pse
jonathanpwang Sep 26, 2023
4cd0844
chore: make `{Fixed,Var}LenBytes*` constructor public
jonathanpwang Sep 26, 2023
16fa9e5
chore(keccak): `format_requests` always returns true capacity (#171)
jonathanpwang Sep 28, 2023
dff0e63
[chore] derive `Hash` for `BaseCircuitParams` (#172)
jonathanpwang Sep 29, 2023
8a5d469
[chore] impl `AsRef, AsMut` for `BaseCircuitBuilder` to self (#173)
jonathanpwang Oct 1, 2023
addfbec
[chore] impl `AsRef, AsMut` for `BaseConfig` to self (#174)
jonathanpwang Oct 1, 2023
9e6c9a1
[chore] Add getters to `KeccakComponentShardCircuit` (#178)
jonathanpwang Oct 7, 2023
fef7316
[chore] Expose Keccak Packing (#180)
nyunyunyunyu Oct 10, 2023
5411321
[chore] Expose Keccak Format (#181)
nyunyunyunyu Oct 11, 2023
bf71f0e
[feat] basic dynamic lookup table gadget (#182)
jonathanpwang Oct 11, 2023
9ff8994
[chore] expose `spec` in `PoseidonHasher` (#183)
jonathanpwang Oct 16, 2023
ff0cadf
[chore] fix halo2-pse build error (#184)
jonathanpwang Oct 18, 2023
582f671
[feat] expose keccak table loading/packing functions for external cra…
jonathanpwang Oct 20, 2023
eef553c
[chore] add getters to `PoseidonCompactChunkInput` (#196)
jonathanpwang Oct 20, 2023
ca498e5
[chore] fix deref after using CopyGetters (#197)
jonathanpwang Oct 21, 2023
2e996ae
[feat] implement `CircuitExt` for `KeccakComponentShardCircuit` (#198)
jonathanpwang Oct 22, 2023
ee822b9
Merge branch 'release-0.4.0-rc' into develop
jonathanpwang Oct 23, 2023
267123f
chore: fix `snark-verifier-sdk` version
jonathanpwang Oct 23, 2023
a30e3b1
[fix] `BasicDynLookupConfig` needs selector on advice table to preven…
jonathanpwang Nov 3, 2023
5e2706f
chore: fix halo2-pse compile
jonathanpwang Nov 12, 2023
dacb885
Merge branch 'release-0.4.0-rc' into release-0.4.1-rc
jonathanpwang Nov 13, 2023
b880af1
chore: fix RAM test to use `&str` type id
jonathanpwang Nov 13, 2023
adb9694
[chore] add crate prefix to `type_id`s (#218)
jonathanpwang Nov 14, 2023
b6a5750
chore: use halo2-axiom from crates.io
jonathanpwang Nov 16, 2023
d45800d
chore: use poseidon-primitives from crates.io
jonathanpwang Nov 16, 2023
26a4504
chore: Bump halo2-axiom to v0.4
jonathanpwang Nov 20, 2023
12e07e1
chore: add `get_mut` for keccak circuit params
jonathanpwang Nov 20, 2023
b6625fa
[fix] soundness bug in `BasicDynLookupConfig::assign_virtual_table_to…
jonathanpwang Nov 30, 2023
fe3e439
[chore] make `KeccakComponentShardCircuit` `inputs` into `RefCell` (#…
jonathanpwang Dec 10, 2023
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
6 changes: 3 additions & 3 deletions halo2-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ num-integer = "0.1"
num-traits = "0.2"
rand_chacha = "0.3"
rustc-hash = "1.1"
rayon = "1.7"
rayon = "1.8"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
log = "0.4"
getset = "0.1.2"
ark-std = { version = "0.3.0", features = ["print-trace"], optional = true }

# Use Axiom's custom halo2 monorepo for faster proving when feature = "halo2-axiom" is on
halo2_proofs_axiom = { git = "https://github.com/axiom-crypto/halo2.git", package = "halo2_proofs", optional = true }
halo2_proofs_axiom = { version = "0.4", package = "halo2-axiom", optional = true }
# Use PSE halo2 and halo2curves for compatibility when feature = "halo2-pse" is on
halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", rev = "7a21656", optional = true }

# This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile).
# We forked it to upgrade to ff v0.13 and removed the circuit module
poseidon-rs = { git = "https://github.com/axiom-crypto/poseidon-circuit.git", rev = "1aee4a1" }
poseidon-rs = { package = "poseidon-primitives", version = "=0.1.1" }
# plotting circuit layout
plotters = { version = "0.3.0", optional = true }

Expand Down
3 changes: 2 additions & 1 deletion halo2-base/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ During `synthesize()`, the advice values of all `Context`s are concatenated into

For parallel witness generation, multiple `Context`s are created for each parallel operation. After parallel witness generation, these `Context`'s are combined to form a single "virtual column" as above. Note that while the witness generation can be multi-threaded, the ordering of the contents in each `Context`, and the order of the `Context`s themselves, must be deterministic.

**Warning:** If you create your own `Context` in a new virtual region not provided by our libraries, you must ensure that the `type_id: &str` of the context is a globally unique identifier for the virtual region, distinct from the other `type_id` strings used to identify other virtual regions. In the future we will introduce a macro to check this uniqueness at compile time.
**Warning:** If you create your own `Context` in a new virtual region not provided by our libraries, you must ensure that the `type_id: &str` of the context is a globally unique identifier for the virtual region, distinct from the other `type_id` strings used to identify other virtual regions. We suggest that you either include your crate name as a prefix in the `type_id` or use [`module_path!`](https://doc.rust-lang.org/std/macro.module_path.html) to generate a prefix.
In the future we will introduce a macro to check this uniqueness at compile time.

### [**AssignedValue**](./src/lib.rs):

Expand Down
12 changes: 12 additions & 0 deletions halo2-base/src/gates/circuit/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,3 +372,15 @@ pub struct RangeStatistics {
/// Total special advice cells that need to be looked up, per phase
pub total_lookup_advice_per_phase: Vec<usize>,
}

impl<F: ScalarField> AsRef<BaseCircuitBuilder<F>> for BaseCircuitBuilder<F> {
fn as_ref(&self) -> &BaseCircuitBuilder<F> {
self
}
}

impl<F: ScalarField> AsMut<BaseCircuitBuilder<F>> for BaseCircuitBuilder<F> {
fn as_mut(&mut self) -> &mut BaseCircuitBuilder<F> {
self
}
}
14 changes: 13 additions & 1 deletion halo2-base/src/gates/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub mod builder;

/// A struct defining the configuration parameters for a halo2-base circuit
/// - this is used to configure [BaseConfig].
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
#[derive(Clone, Default, Debug, Hash, Serialize, Deserialize)]
pub struct BaseCircuitParams {
// Keeping FlexGateConfigParams expanded for backwards compatibility
/// Specifies the number of rows in the circuit to be 2<sup>k</sup>
Expand Down Expand Up @@ -215,3 +215,15 @@ impl CircuitBuilderStage {
matches!(self, CircuitBuilderStage::Prover)
}
}

impl<F: ScalarField> AsRef<BaseConfig<F>> for BaseConfig<F> {
fn as_ref(&self) -> &BaseConfig<F> {
self
}
}

impl<F: ScalarField> AsMut<BaseConfig<F>> for BaseConfig<F> {
fn as_mut(&mut self) -> &mut BaseConfig<F> {
self
}
}
2 changes: 1 addition & 1 deletion halo2-base/src/gates/flex_gate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,7 +823,7 @@ pub trait GateInstructions<F: ScalarField> {

/// Constrains and returns little-endian bit vector representation of `a`.
///
/// Assumes `range_bits <= number of bits in a`.
/// Assumes `range_bits >= bit_length(a)`.
/// * `a`: [QuantumCell] of the value to convert
/// * `range_bits`: range of bits needed to represent `a`
fn num_to_bits(
Expand Down
16 changes: 11 additions & 5 deletions halo2-base/src/gates/flex_gate/threads/single_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ impl<F: ScalarField> SinglePhaseCoreManager<F> {
/// A distinct tag for this particular type of virtual manager, which is different for each phase.
pub fn type_of(&self) -> &'static str {
match self.phase {
0 => "SinglePhaseCoreManager: FirstPhase",
1 => "SinglePhaseCoreManager: SecondPhase",
2 => "SinglePhaseCoreManager: ThirdPhase",
0 => "halo2-base:SinglePhaseCoreManager:FirstPhase",
1 => "halo2-base:SinglePhaseCoreManager:SecondPhase",
2 => "halo2-base:SinglePhaseCoreManager:ThirdPhase",
_ => panic!("Unsupported phase"),
}
}
Expand Down 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
6 changes: 6 additions & 0 deletions halo2-base/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ pub struct ContextCell {

impl ContextCell {
/// Creates a new [ContextCell] with the given `type_id`, `context_id`, and `offset`.
///
/// **Warning:** If you create your own `Context` in a new virtual region not provided by our libraries, you must ensure that the `type_id: &str` of the context is a globally unique identifier for the virtual region, distinct from the other `type_id` strings used to identify other virtual regions. We suggest that you either include your crate name as a prefix in the `type_id` or use [`module_path!`](https://doc.rust-lang.org/std/macro.module_path.html) to generate a prefix.
/// In the future we will introduce a macro to check this uniqueness at compile time.
pub fn new(type_id: &'static str, context_id: usize, offset: usize) -> Self {
Self { type_id, context_id, offset }
}
Expand Down Expand Up @@ -203,6 +206,9 @@ impl<F: ScalarField> Context<F> {
/// Creates a new [Context] with the given `context_id` and witness generation enabled/disabled by the `witness_gen_only` flag.
/// * `witness_gen_only`: flag to determine whether public key generation or only witness generation is being performed.
/// * `context_id`: identifier to reference advice cells from this [Context] later.
///
/// **Warning:** If you create your own `Context` in a new virtual region not provided by our libraries, you must ensure that the `type_id: &str` of the context is a globally unique identifier for the virtual region, distinct from the other `type_id` strings used to identify other virtual regions. We suggest that you either include your crate name as a prefix in the `type_id` or use [`module_path!`](https://doc.rust-lang.org/std/macro.module_path.html) to generate a prefix.
/// In the future we will introduce a macro to check this uniqueness at compile time.
pub fn new(
witness_gen_only: bool,
phase: usize,
Expand Down
31 changes: 19 additions & 12 deletions halo2-base/src/poseidon/hasher/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
ScalarField,
};

use getset::Getters;
use getset::{CopyGetters, Getters};
use num_bigint::BigUint;
use std::{cell::OnceCell, mem};

Expand All @@ -23,8 +23,10 @@ pub mod spec;
pub mod state;

/// Stateless Poseidon hasher.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Getters)]
pub struct PoseidonHasher<F: ScalarField, const T: usize, const RATE: usize> {
/// Spec, contains round constants and optimized matrices.
#[getset(get = "pub")]
spec: OptimizedPoseidonSpec<F, T, RATE>,
consts: OnceCell<PoseidonHasherConsts<F, T, RATE>>,
}
Expand All @@ -51,13 +53,16 @@ impl<F: ScalarField, const T: usize, const RATE: usize> PoseidonHasherConsts<F,
}

/// 1 logical row of compact input for Poseidon hasher.
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, Getters, CopyGetters)]
pub struct PoseidonCompactInput<F: ScalarField, const RATE: usize> {
// Right padded inputs. No constrains on paddings.
/// Right padded inputs. No constrains on paddings.
#[getset(get = "pub")]
inputs: [AssignedValue<F>; RATE],
// is_final = 1 triggers squeeze.
/// is_final = 1 triggers squeeze.
#[getset(get_copy = "pub")]
is_final: SafeBool<F>,
// Length of `inputs`.
/// Length of `inputs`.
#[getset(get_copy = "pub")]
len: AssignedValue<F>,
}

Expand Down Expand Up @@ -87,11 +92,13 @@ impl<F: ScalarField, const RATE: usize> PoseidonCompactInput<F, RATE> {
}

/// A compact chunk input for Poseidon hasher. The end of a logical input could only be at the boundary of a chunk.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Getters, CopyGetters)]
pub struct PoseidonCompactChunkInput<F: ScalarField, const RATE: usize> {
// Inputs of a chunk. All witnesses will be absorbed.
/// Inputs of a chunk. All witnesses will be absorbed.
#[getset(get = "pub")]
inputs: Vec<[AssignedValue<F>; RATE]>,
// is_final = 1 triggers squeeze.
/// is_final = 1 triggers squeeze.
#[getset(get_copy = "pub")]
is_final: SafeBool<F>,
}

Expand All @@ -103,13 +110,13 @@ impl<F: ScalarField, const RATE: usize> PoseidonCompactChunkInput<F, RATE> {
}

/// 1 logical row of compact output for Poseidon hasher.
#[derive(Copy, Clone, Debug, Getters)]
#[derive(Copy, Clone, Debug, CopyGetters)]
pub struct PoseidonCompactOutput<F: ScalarField> {
/// hash of 1 logical input.
#[getset(get = "pub")]
#[getset(get_copy = "pub")]
hash: AssignedValue<F>,
/// is_final = 1 ==> this is the end of a logical input.
#[getset(get = "pub")]
#[getset(get_copy = "pub")]
is_final: SafeBool<F>,
}

Expand Down
2 changes: 1 addition & 1 deletion halo2-base/src/poseidon/hasher/tests/hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ fn hasher_compact_chunk_inputs_compatiblity_verification<
for (compact_output, chunk_input) in compact_outputs.iter().zip(chunk_inputs) {
// into() doesn't work if ! is in the beginning in the bool expression...
let is_final_input = chunk_input.is_final.as_ref().value();
let is_final_output = compact_output.is_final().as_ref().value();
let is_final_output = compact_output.is_final.as_ref().value();
assert_eq!(is_final_input, is_final_output);
if is_final_output == &Fr::ONE {
assert_eq!(native_results[output_offset], *compact_output.hash().value());
Expand Down
35 changes: 35 additions & 0 deletions halo2-base/src/utils/halo2.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use std::collections::hash_map::Entry;

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

/// Raw (physical) assigned cell in Plonkish arithmetization.
#[cfg(feature = "halo2-axiom")]
Expand Down Expand Up @@ -71,3 +75,34 @@ pub fn raw_constrain_equal<F: Field>(region: &mut Region<F>, left: Cell, right:
#[cfg(not(feature = "halo2-axiom"))]
region.constrain_equal(left, right).unwrap();
}

/// 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.
///
/// ## Panics
/// If witness generation only mode is true.
pub fn constrain_virtual_equals_external<F: Field + Ord>(
region: &mut Region<F>,
virtual_cell: AssignedValue<F>,
external_cell: Cell,
copy_manager: &mut CopyConstraintManager<F>,
) {
let ctx_cell = virtual_cell.cell.unwrap();
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);
}
}
}
12 changes: 10 additions & 2 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,10 +89,15 @@ impl<F: Field + Ord> CopyConstraintManager<F> {
}

fn load_external_cell_impl(&mut self, cell: Option<Cell>) -> ContextCell {
let context_cell = ContextCell::new("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
15 changes: 8 additions & 7 deletions halo2-base/src/virtual_region/lookups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ use crate::halo2_proofs::{
circuit::{Region, Value},
plonk::{Advice, Column},
};
use crate::utils::halo2::raw_assign_advice;
use crate::utils::halo2::{constrain_virtual_equals_external, raw_assign_advice};
use crate::{AssignedValue, ContextTag};

use super::copy_constraints::SharedCopyConstraintManager;
use super::manager::VirtualRegionManager;

/// Basic dynamic lookup table gadget.
pub mod basic;

/// A manager that can be used for any lookup argument. This manager automates
/// the process of copying cells to designed advice columns with lookup enabled.
/// It also manages how many such advice columns are necessary.
Expand Down Expand Up @@ -122,6 +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 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 @@ -135,12 +140,8 @@ 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 !self.witness_gen_only {
let ctx_cell = advice.cell.unwrap();
let copy_manager = self.copy_manager.lock().unwrap();
let acell =
copy_manager.assigned_advices.get(&ctx_cell).expect("cell not assigned");
region.constrain_equal(*acell, bcell.cell());
if let Some(copy_manager) = copy_manager.as_mut() {
constrain_virtual_equals_external(region, *advice, bcell.cell(), copy_manager);
}
}

Expand Down
Loading