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}