Skip to content

Commit

Permalink
Refactor: evm-circuit util/chips to "gadgets" crate (privacy-scaling-…
Browse files Browse the repository at this point in the history
…explorations#611)

* refactor Expr trait into gadgets, add LessThan to gadgets

* chore: refactor binary number mod and helper mods to gadgets crate

* chore: document the gadgets crate, minor changes as per review

* tests: Lt chip tests under gadgets crate

Co-authored-by: Zhang Zhuo <[email protected]>
  • Loading branch information
roynalnaruto and lispc authored Jul 12, 2022
1 parent eafc0b8 commit 159a073
Show file tree
Hide file tree
Showing 14 changed files with 714 additions and 218 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions gadgets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ halo2_proofs = { version = "0.1.0-beta.1" }
sha3 = "0.7.2"
eth-types = { path = "../eth-types" }
digest = "0.7.6"
strum = "0.24"
strum_macros = "0.24"

[dev-dependencies]
rand_xorshift = "0.3"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use crate::{
evm_circuit::{
table::RwTableTag,
util::{and, not},
},
util::Expr,
};
//! The binary number chip implements functionality to represent any given value
//! in binary bits, which can be compared against a value or expression for
//! equality.
use crate::util::{and, not, Expr};
use eth_types::Field;
use halo2_proofs::{
circuit::Region,
Expand All @@ -15,27 +13,20 @@ use std::collections::BTreeSet;
use std::marker::PhantomData;
use strum::IntoEnumIterator;

/// Helper trait that implements functionality to represent a generic type as
/// array of N-bits.
pub trait AsBits<const N: usize> {
// Return the bits of self, starting from the most significant.
/// Return the bits of self, starting from the most significant.
fn as_bits(&self) -> [bool; N];
}

impl AsBits<4> for RwTableTag {
fn as_bits(&self) -> [bool; 4] {
let mut bits = [false; 4];
let mut x = *self as u8;
for i in 0..4 {
bits[3 - i] = x % 2 == 1;
x /= 2;
}
bits
}
}

impl<const N: usize> AsBits<N> for usize {
impl<T, const N: usize> AsBits<N> for T
where
T: Copy + Into<usize>,
{
fn as_bits(&self) -> [bool; N] {
let mut bits = [false; N];
let mut x = *self as u64;
let mut x: usize = (*self).into();
for i in 0..N {
bits[N - 1 - i] = x % 2 == 1;
x /= 2;
Expand All @@ -44,17 +35,19 @@ impl<const N: usize> AsBits<N> for usize {
}
}

/// Config for the binary number chip.
#[derive(Clone, Copy)]
pub struct Config<T, const N: usize> {
// Must be constrained to be binary for correctness.
pub struct BinaryNumberConfig<T, const N: usize> {
/// Must be constrained to be binary for correctness.
pub bits: [Column<Advice>; N],
_marker: PhantomData<T>,
}

impl<T, const N: usize> Config<T, N>
impl<T, const N: usize> BinaryNumberConfig<T, N>
where
T: AsBits<N>,
{
/// Returns the expression value of the bits at the given rotation.
pub fn value<F: Field>(
&self,
rotation: Rotation,
Expand All @@ -67,6 +60,9 @@ where
}
}

/// Returns a function that can evaluate to a binary expression, that
/// evaluates to 1 if value is equal to value as bits. The returned
/// expression is of degree N.
pub fn value_equals<F: Field, S: AsBits<N>>(
&self,
value: S,
Expand All @@ -76,8 +72,8 @@ where
move |meta| Self::value_equals_expr(value, bits.map(|bit| meta.query_advice(bit, rotation)))
}

// Returns a binary expression that evaluates to 1 if expressions are equal to
// value as bits. The returned expression is of degree N.
/// Returns a binary expression that evaluates to 1 if expressions are equal
/// to value as bits. The returned expression is of degree N.
pub fn value_equals_expr<F: Field, S: AsBits<N>>(
value: S,
expressions: [Expression<F>; N], // must be binary.
Expand All @@ -98,28 +94,34 @@ where
}
}

// This chip helps working with binary encoding of integers of length N bits by:
// - enforcing that the binary representation is in the valid range defined by
// T.
// - creating expressions (via the Config) that evaluate to 1 when the bits
// match a specific value and 0 otherwise.
pub struct Chip<F: Field, T, const N: usize> {
config: Config<T, N>,
/// This chip helps working with binary encoding of integers of length N bits
/// by:
/// - enforcing that the binary representation is in the valid range defined by
/// T.
/// - creating expressions (via the Config) that evaluate to 1 when the bits
/// match a specific value and 0 otherwise.
pub struct BinaryNumberChip<F: Field, T, const N: usize> {
config: BinaryNumberConfig<T, N>,
_marker: PhantomData<F>,
}

impl<F: Field, T: IntoEnumIterator, const N: usize> Chip<F, T, N>
impl<F: Field, T: IntoEnumIterator, const N: usize> BinaryNumberChip<F, T, N>
where
T: AsBits<N>,
{
pub fn construct(config: Config<T, N>) -> Self {
/// Construct the binary number chip given a config.
pub fn construct(config: BinaryNumberConfig<T, N>) -> Self {
Self {
config,
_marker: PhantomData,
}
}

pub fn configure(meta: &mut ConstraintSystem<F>, selector: Column<Fixed>) -> Config<T, N> {
/// Configure constraints for the binary number chip.
pub fn configure(
meta: &mut ConstraintSystem<F>,
selector: Column<Fixed>,
) -> BinaryNumberConfig<T, N> {
let bits = [0; N].map(|_| meta.advice_column());
bits.map(|bit| {
meta.create_gate("bit column is 0 or 1", |meta| {
Expand All @@ -129,7 +131,7 @@ where
})
});

let config = Config {
let config = BinaryNumberConfig {
bits,
_marker: PhantomData,
};
Expand All @@ -152,6 +154,8 @@ where
config
}

/// Assign a value to the binary number chip. A generic type that implements
/// the AsBits trait can be provided for assignment.
pub fn assign(
&self,
region: &mut Region<'_, F>,
Expand All @@ -170,6 +174,7 @@ where
}
}

/// Helper function to get a decimal representation given the bits.
pub fn from_bits(bits: &[bool]) -> usize {
bits.iter()
.fold(0, |result, &bit| bit as usize + 2 * result)
Expand Down
Loading

0 comments on commit 159a073

Please sign in to comment.