Skip to content

Make BitZ generic over semirings, rings and fields - #140

Open
frozenspider wants to merge 18 commits into
mainfrom
fs/field
Open

frozenspider wants to merge 18 commits into
mainfrom
fs/field

Conversation

@frozenspider

@frozenspider frozenspider commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

A follow-up to #135, another step toward #136 (hopefully second-to-last).

Summary of changes:

  • Added new blanket trait BitzClaimField.
  • Generalized concrete Fq to F: BitzClaimField.
    • Note that F128 is still hardcoded, and that's intended - we don't plan to generalize over it.
  • Did the same with u128 and BigUint -> BitzSemiring in a few places.
  • Relaxed ConstField requirement to Field.
  • Renamed BitzRing to BitzConstraintRing to avoid confusion with BitzClaimField::Integer.
  • Added a bridge between BitzConstraintRing and BitzClaimField in the form of ProjectConstraint.
  • In places where generalization was not feasible, removed direct imports of BigUint, BigInt and Fq, replacing them with type aliases (S, R, F).
  • Spartan SHA-256 test and benchmark moved to tooling crate in order to get access to ProjectBigIntToFq.

A follow-up PR will replace Fq with dynamic field.

@frozenspider frozenspider changed the title [WIP] Make project generic over semirings, rings and fields [WIP] Make BitZ generic over semirings, rings and fields Sep 29, 2026
@frozenspider frozenspider changed the title [WIP] Make BitZ generic over semirings, rings and fields Make BitZ generic over semirings, rings and fields Sep 29, 2026
@frozenspider
frozenspider marked this pull request as ready for review September 29, 2026 20:13
# Conflicts:
#	crates/tests/examples/dump_bitz.rs
#	crates/tests/tests/host.rs
#	crates/tests/tests/prove.rs
#	crates/verifier/src/verify.rs
#	tooling/cli/src/end_to_end.rs
#	tooling/cli/tests/circuits.rs
#	tooling/cli/tests/end_to_end.rs
@frozenspider
frozenspider added this pull request to stack #142 October 5, 2026 13:19
Comment thread crates/circuit/src/constraints.rs Outdated
Comment thread crates/circuit/src/lib.rs Outdated
Comment on lines +23 to +24
type S = num_bigint::BigUint;
type R = num_bigint::BigInt;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind single letter types, but here I'm missing the mnemonic for S and R.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It stands for (S)emiring and (R)ing

params: &BitZParams<Q>,
row_weights: Vec<Fq<Q>>,
column_weights: Vec<Fq<Q>>,
target: Fq<Q>,

@xrvdg xrvdg Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both Q and Fq<Q> got replaced by F. Since Q in BitZParams is a phantom data it might not matter that much. But do investigate, these things tend to break later on.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is by design, as the whole BitZParams was reworked to be generic over any field, not just Fq over some Q.

}

impl<const Q: u128> BitZParams<Q> {
impl<F: BitzClaimField> BitZParams<F> {

@xrvdg xrvdg Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continuating of previous point. u128 -> BitzClaimField, while somewhere else Fq<Q> -> BitzClaimField.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Comment on lines +88 to +92
pub fn fold_bound(&self) -> F::Integer {
let rows = u64::try_from(self.shape.rows()).expect("Too many rows");
let rows = F::Integer::from(rows);
let max_f = F::max_value().lift();
rows.checked_mul(&max_f).expect("Multiplication overflow")

@xrvdg xrvdg Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This many expects in arithmetic code feels off. Later on the similar calculation is done without expects.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just some guardrails - they should probably become Result<_, _> at some point, to avoid DoS in real systems.
How do you want to treat them now?

Comment on lines +29 to +32
pub struct VirtualStatement<'a, F, M: VirtualMap> {
params: VirtualParams<F>,
map: &'a M,
claim: &'a LinearClaim<Fq<Q>>,
claim: &'a LinearClaim<F>,

@xrvdg xrvdg Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before, Q -> F and Fq<Q> -> F

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

Box::new((0..n).map(|_| F128::from(rand::random::<u128>())).collect());
let packed: &'static _ = packed.leak();
let params: BitZParams<Q114> =
let params: BitZParams<Fq<Q114>> =

@xrvdg xrvdg Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continuation of earlier point about BitZParams. Now Fq shows up in BitZParams while it wasn't there before.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, as BitZParams is now generic over a field, Fq<Q114> is the concrete field type used here.

Comment thread crates/prover/src/fold.rs

for fold in &folds {
transcript.prover_message(&fold.to_le_bytes());
transcript.prover_message(&fold.to_le_bytes().as_ref());

@xrvdg xrvdg Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would Deref be better than AsRef in this case?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite follow, how do you want to deref it if we specifically need a reference?

To give some context, I was following the existing convention (partially enforced by spongefish) - the type bound T: Encoding<[u8]> + NargSerialize + ?Sized and argument type &T, so we need to provide a reference so something that is NargSerialize. Given that [u8] is not NargSerialize, we pass in &&[u8].

Comment on lines +100 to +102
let modulus = F::modulus();
let fold = (shape.rows() as u128) * (modulus - 1);
let params = BitZParams::<F>::new(shape, smallest_generator()).unwrap();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ties back to earlier point of too much exception handling. This piece of code performs the same calculation but doesn't need expect.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is test code, so we don't care about expects, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants