Skip to main content

binius_circuits/bignum/
cmp.rs

1// Copyright 2026 The Binius Developers
2// Copyright 2025 Irreducible Inc.
3use std::iter;
4
5use binius_core::word::Word;
6use binius_frontend::{CircuitBuilder, Wire};
7
8use super::biguint::BigUint;
9
10/// Less-than comparison between equally-sized `BigUint`s.
11///
12/// # Arguments
13/// * `builder` - Circuit builder for constraint generation
14/// * `a` - First operand
15/// * `b` - Second operand (must have same number of limbs as `a`)
16///
17/// # Returns
18/// Boolean wire that is true when `a < b`.
19///
20/// # Panics
21/// - Panics if `a` and `b` have different number of limbs
22pub fn biguint_lt(builder: &CircuitBuilder, a: &BigUint, b: &BigUint) -> Wire {
23	assert_eq!(
24		a.limbs.len(),
25		b.limbs.len(),
26		"biguint_lt: inputs must have the same number of limbs"
27	);
28
29	let mut result = builder.add_constant(Word::ZERO);
30
31	for (&a_limb, &b_limb) in iter::zip(&a.limbs, &b.limbs) {
32		let lt_flag = builder.icmp_ult(a_limb, b_limb);
33		let eq_flag = builder.icmp_eq(a_limb, b_limb);
34		// `lt_flag` and `eq_flag` are mutually exclusive (a limb cannot be both
35		// less than and equal to another), so their MSB-bools never share a set
36		// bit and OR agrees with XOR on the only bit these flags define. XOR is
37		// linear, saving one AND constraint per limb.
38		result = builder.bxor(lt_flag, builder.band(eq_flag, result));
39	}
40
41	result
42}
43
44/// Equality check between equally-sized `BigUint`s.
45///
46/// # Arguments
47/// * `builder` - Circuit builder for constraint generation
48/// * `a` - First operand
49/// * `b` - Second operand (must have same number of limbs as `a`)
50///
51/// # Returns
52/// Boolean wire that is true when `a == b`.
53///
54/// # Panics
55/// - Panics if `a` and `b` have different number of limbs
56pub fn biguint_eq(builder: &CircuitBuilder, a: &BigUint, b: &BigUint) -> Wire {
57	assert_eq!(
58		a.limbs.len(),
59		b.limbs.len(),
60		"biguint_eq: inputs must have the same number of limbs"
61	);
62
63	let mut result = builder.add_constant(Word::ALL_ONE);
64
65	for (&a_limb, &b_limb) in iter::zip(&a.limbs, &b.limbs) {
66		result = builder.band(builder.icmp_eq(a_limb, b_limb), result);
67	}
68
69	result
70}