acvm/pwg/blackbox/
range.rs1use crate::{
2 OpcodeResolutionError,
3 pwg::{ErrorLocation, input_to_value},
4};
5use acir::{AcirField, circuit::opcodes::FunctionInput, native_types::WitnessMap};
6
7pub(crate) fn solve_range_opcode<F: AcirField>(
8 initial_witness: &WitnessMap<F>,
9 input: &FunctionInput<F>,
10 num_bits: u32,
11) -> Result<(), OpcodeResolutionError<F>> {
12 let w_value = input_to_value(initial_witness, *input)?;
13
14 if w_value.num_bits() > num_bits {
15 return Err(OpcodeResolutionError::UnsatisfiedConstrain {
16 opcode_location: ErrorLocation::Unresolved,
17 payload: None,
18 });
19 }
20 Ok(())
21}
22
23#[cfg(test)]
24mod tests {
25 use std::collections::BTreeMap;
26
27 use acir::{
28 AcirField, FieldElement,
29 circuit::opcodes::FunctionInput,
30 native_types::{Witness, WitnessMap},
31 };
32
33 use crate::pwg::blackbox::solve_range_opcode;
34
35 #[test]
36 fn rejects_too_large_inputs() {
37 let witness_map =
38 WitnessMap::from(BTreeMap::from([(Witness(0), FieldElement::from(256u32))]));
39 let input: FunctionInput<FieldElement> = FunctionInput::Witness(Witness(0));
40 assert!(solve_range_opcode(&witness_map, &input, 8).is_err());
41 }
42
43 #[test]
44 fn accepts_zero_for_zero_bits() {
45 let witness_map = WitnessMap::from(BTreeMap::from([(Witness(0), FieldElement::zero())]));
46 let input: FunctionInput<FieldElement> = FunctionInput::Witness(Witness(0));
47 assert!(solve_range_opcode(&witness_map, &input, 0).is_ok());
48 }
49
50 #[test]
51 fn accepts_valid_inputs() {
52 let values: [u32; 4] = [0, 1, 8, 255];
53
54 for value in values {
55 let witness_map =
56 WitnessMap::from(BTreeMap::from([(Witness(0), FieldElement::from(value))]));
57 let input: FunctionInput<FieldElement> = FunctionInput::Witness(Witness(0));
58 assert!(solve_range_opcode(&witness_map, &input, 8).is_ok());
59 }
60 }
61}