Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
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: 1 addition & 1 deletion crates/circuit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license.workspace = true
[dependencies]
blake3.workspace = true
common.workspace = true
field = { path = "../field" }
field.workspace = true
num-bigint.workspace = true
poly.workspace = true
num-traits.workspace = true
Expand Down
29 changes: 16 additions & 13 deletions crates/circuit/benches/support/p256.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
use circuit::p256::VERIFY_DIGEST_INPUT_BITS;
use num_bigint::{BigInt, BigUint, Sign};
use num_bigint::Sign;
use num_traits::{One, Zero};

pub const AUX_INPUT_BITS: usize = 6 * 256;

fn from_hex(value: &[u8]) -> BigUint {
BigUint::parse_bytes(value, 16).unwrap()
type S = num_bigint::BigUint;
type R = num_bigint::BigInt;

fn from_hex(value: &[u8]) -> S {
S::parse_bytes(value, 16).unwrap()
}

fn scalar_modulus() -> BigUint {
fn scalar_modulus() -> S {
from_hex(b"ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551")
}

fn inverse(value: &BigUint, modulus: &BigUint) -> BigUint {
let mut t = BigInt::zero();
let mut new_t = BigInt::one();
let mut r = BigInt::from(modulus.clone());
let mut new_r = BigInt::from(value.clone());
fn inverse(value: &S, modulus: &S) -> S {
let mut t = R::zero();
let mut new_t = R::one();
let mut r = R::from(modulus.clone());
let mut new_r = R::from(value.clone());
while !new_r.is_zero() {
let quotient = &r / &new_r;
(t, new_t) = (new_t.clone(), t - &quotient * new_t);
(r, new_r) = (new_r.clone(), r - quotient * new_r);
}
assert_eq!(r, BigInt::one());
let modulus = BigInt::from(modulus.clone());
assert_eq!(r, R::one());
let modulus = R::from(modulus.clone());
let mut t = t % &modulus;
if t.sign() == Sign::Minus {
t += modulus;
Expand All @@ -32,7 +35,7 @@ fn inverse(value: &BigUint, modulus: &BigUint) -> BigUint {
}

/// P-256 inputs for d = k = 1: Q = G, r = G.x, and s = z + r*d.
pub fn valid_aux_input(digest: &BigUint) -> Box<[bool; AUX_INPUT_BITS]> {
pub fn valid_aux_input(digest: &S) -> Box<[bool; AUX_INPUT_BITS]> {
let modulus = scalar_modulus();
let gx = from_hex(b"6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296");
let gy = from_hex(b"4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5");
Expand All @@ -53,7 +56,7 @@ pub fn valid_aux_input(digest: &BigUint) -> Box<[bool; AUX_INPUT_BITS]> {

/// A small valid ECDSA instance with z = 1.
pub fn valid_input() -> Box<[bool; VERIFY_DIGEST_INPUT_BITS]> {
let digest = BigUint::one();
let digest = S::one();
let aux = valid_aux_input(&digest);
let bits: Box<[bool]> = (0..VERIFY_DIGEST_INPUT_BITS)
.map(|index| {
Expand Down
16 changes: 9 additions & 7 deletions crates/circuit/src/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
//! witness, prefixed by a constant one, to the integer witness. Its first row
//! is the implicit integer constant one. `A`, `B`, and `C` then encode the
//! rank-1 constraints `(A z) * (B z) = C z` over that integer witness. Every
//! integer coefficient is an arbitrary-precision signed [`BitzRing`].
//! integer coefficient is an arbitrary-precision signed [`BitzConstraintRing`].

use crate::witgen::PackedWitness;
use crate::{BoolWitness, Circuit, HintResult, PackedBits, ScalarBits, WitnessContext};
use common::{BitzRing, BitzSemiring};
use common::{BitzConstraintRing, BitzSemiring};
use num_traits::Zero;
use rayon::prelude::*;
use std::array;
Expand Down Expand Up @@ -232,7 +232,7 @@ pub enum ConstraintMatrixShapeError {
AssignmentLengthMismatch { m_rows: usize, r1cs_columns: usize },
}

impl<R: BitzSemiring> ConstraintMatrices<R> {
impl<R: Send + Sync> ConstraintMatrices<R> {
/// Checks that A, B, and C share a shape and consume the assignment
/// produced by M.
pub fn validate_shape(&self) -> Result<(), ConstraintMatrixShapeError> {
Expand Down Expand Up @@ -284,7 +284,9 @@ impl<R: BitzSemiring> ConstraintMatrices<R> {
c: self.c.map_values_with(&map),
}
}
}

impl<R: BitzSemiring> ConstraintMatrices<R> {
/// Applies `M` to a packed Boolean witness.
///
/// The returned vector starts with the implicit constant one and is the
Expand Down Expand Up @@ -498,7 +500,7 @@ impl<R: BitzSemiring> AddAssign for LinearCombination<R> {
}
}

impl<R: BitzRing> Neg for LinearCombination<R> {
impl<R: BitzConstraintRing> Neg for LinearCombination<R> {
type Output = Self;

fn neg(mut self) -> Self::Output {
Expand All @@ -510,15 +512,15 @@ impl<R: BitzRing> Neg for LinearCombination<R> {
}
}

impl<R: BitzRing> Sub for LinearCombination<R> {
impl<R: BitzConstraintRing> Sub for LinearCombination<R> {
type Output = Self;

fn sub(self, rhs: Self) -> Self::Output {
self + -rhs
}
}

impl<R: BitzRing> SubAssign for LinearCombination<R> {
impl<R: BitzConstraintRing> SubAssign for LinearCombination<R> {
fn sub_assign(&mut self, rhs: Self) {
*self += -rhs;
}
Expand Down Expand Up @@ -715,7 +717,7 @@ fn bool_sparse_row(value: BoolLinearCombination) -> SparseBoolRow {
}
}

impl<R: BitzRing> Circuit for ConstraintGenerator<R> {
impl<R: BitzConstraintRing> Circuit for ConstraintGenerator<R> {
type Bool = BoolLinearCombination;
type Coefficient<const LIMBS: usize> = R;
type Z<const LIMBS: usize> = LinearCombination<R>;
Expand Down
27 changes: 23 additions & 4 deletions crates/circuit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,21 +538,40 @@ pub trait Circuit {
) -> Self::Z<TO_LIMBS>;
}

pub trait Bits {
pub trait BitWidth {
/// Determines the fewest bits necessary to express this value
fn bits(&self) -> u64;
fn bit_width(&self) -> u64;
}

pub trait IntoWords {
/// Convert a value into u64 words, lowest limb first
fn into_words<const LIMBS: usize>(self) -> [u64; LIMBS];
}

impl Bits for num_bigint::BigUint {
fn bits(&self) -> u64 {
impl BitWidth for u128 {
fn bit_width(&self) -> u64 {
u128::bit_width(*self) as u64
}
}

impl BitWidth for num_bigint::BigUint {
fn bit_width(&self) -> u64 {
num_bigint::BigUint::bits(self)
}
}

impl IntoWords for u128 {
fn into_words<const LIMBS: usize>(self) -> [u64; LIMBS] {
const {
assert!(LIMBS >= 2);
}
let mut result = [0; LIMBS];
result[0] = self as u64;
result[1] = (self >> 64) as u64;
result
}
}

impl IntoWords for num_bigint::BigUint {
fn into_words<const LIMBS: usize>(self) -> [u64; LIMBS] {
let mut digits = self.iter_u64_digits();
Expand Down
19 changes: 16 additions & 3 deletions crates/circuit/src/matrix_products.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@
//! and `C(Mw)` vectors during witness generation. This module subsequently
//! reduces those vectors modulo a runtime modulus. Large batches use Rayon;
//! small batches stay sequential to avoid scheduling overhead.
// TODO(alex): Should this be generalized over [`BitzClaimField`] as well?

use crate::witgen::Z as Integer;
use crate::{Bits, IntoWords};
use crate::{BitWidth, IntoWords};
use num_traits::{One, Zero};
use rayon::prelude::*;
use std::cmp::Ordering;
Expand All @@ -21,14 +22,16 @@ pub struct RuntimeModulus<const PRIME_LIMBS: usize> {

impl<const PRIME_LIMBS: usize> RuntimeModulus<PRIME_LIMBS> {
/// Validates and stores a runtime modulus.
pub fn new<S: One + PartialOrd + Bits + IntoWords>(modulus: S) -> Result<Self, &'static str> {
pub fn new<S: One + PartialOrd + BitWidth + IntoWords>(
modulus: S,
) -> Result<Self, &'static str> {
if PRIME_LIMBS == 0 {
return Err("a runtime field needs at least one limb");
}
if modulus <= S::one() {
return Err("the modulus must be greater than one");
}
if modulus.bits() > (PRIME_LIMBS as u64) * 64 {
if modulus.bit_width() > (PRIME_LIMBS as u64) * 64 {
return Err("the modulus does not fit the selected limb count");
}
Ok(Self {
Expand Down Expand Up @@ -264,6 +267,16 @@ impl<const PRIME_LIMBS: usize> ModularVector<PRIME_LIMBS> {
}
}

impl From<&ModularVector<2>> for Vec<field::FqDefault> {
fn from(values: &ModularVector<2>) -> Self {
values
.values()
.iter()
.map(|&[low, high]| field::FqDefault::from_limbs(low, high))
.collect()
}
}

/// Dense runtime-field `A(Mw)`, `B(Mw)`, and `C(Mw)` vectors.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct MatrixProducts<const PRIME_LIMBS: usize> {
Expand Down
4 changes: 2 additions & 2 deletions crates/circuit/src/matrix_sparse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use crate::constraints::{ConstraintMatrices, SparseMatrix};
use crate::matrix_products::{RuntimeModulus, StoredInteger};
use crate::matrix_wengert::{add_mod_words, montgomery_mul_2, neg_mod_words};
use common::BitzRing;
use common::BitzConstraintRing;
use crypto_bigint::modular::{FixedMontyForm, FixedMontyParams};
use crypto_bigint::{Odd, U128};
use rayon::prelude::*;
Expand Down Expand Up @@ -74,7 +74,7 @@ impl MaterializedAbc {
/// Transposes and stores the integer matrices without choosing a modulus.
pub fn from_matrices<R>(matrices: &ConstraintMatrices<R>) -> Self
where
R: BitzRing,
R: BitzConstraintRing,
StoredInteger: for<'a> From<&'a R>,
{
let row_count = matrices.a.row_count();
Expand Down
3 changes: 1 addition & 2 deletions crates/circuit/src/matrix_transpose.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,11 +514,10 @@ mod tests {
use crate::sha256::{COMPRESSION_HINT_BITS, COMPRESSION_INPUT_BITS, compression_circuit};
use crate::witgen::Witgen;
use crate::{BoolRepresentation, BoolWitness, Circuit};
use num_bigint::BigInt;

use super::*;

type R = BigInt;
type R = num_bigint::BigInt;

fn example_circuit<CS: Circuit>(circuit: &mut CS, inputs: &[CS::Bool; 3]) {
let xy = circuit.xor(inputs[0].clone(), inputs[1].clone());
Expand Down
Loading
Loading