arkworks_small_values_ops/
ops.rs1use std::ops::Mul;
2
3use ark_ff::PrimeField;
4use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar};
5use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
6
7use crate::{
8 common::{enforce_zero, get_slack},
9 enforce_in_binary_bound,
10};
11
12pub fn min<F: PrimeField, const BITS: usize>(
18 cs: ConstraintSystemRef<F>,
19 a: &FpVar<F>,
20 b: &FpVar<F>,
21) -> Result<FpVar<F>, SynthesisError> {
22 assert!(BITS < (F::MODULUS_BIT_SIZE - 1) as usize);
23 let (_undr, over) = get_under_and_over_checked::<F, BITS>(cs, a, b)?;
24 Ok(a - over)
25}
26
27pub fn max<F: PrimeField, const BITS: usize>(
33 cs: ConstraintSystemRef<F>,
34 a: &FpVar<F>,
35 b: &FpVar<F>,
36) -> Result<FpVar<F>, SynthesisError> {
37 assert!(BITS < (F::MODULUS_BIT_SIZE - 1) as usize);
38 let (undr, _over) = get_under_and_over_checked::<F, BITS>(cs, a, b)?;
39 Ok(a + undr)
40}
41
42pub fn abs_diff<F: PrimeField, const BITS: usize>(
48 cs: ConstraintSystemRef<F>,
49 a: &FpVar<F>,
50 b: &FpVar<F>,
51) -> Result<FpVar<F>, SynthesisError> {
52 assert!(BITS < (F::MODULUS_BIT_SIZE - 1) as usize);
53 let (undr, over) = get_under_and_over_checked::<F, BITS>(cs, a, b)?;
54 Ok(undr + over)
55}
56
57fn get_under_and_over_checked<F: PrimeField, const BITS: usize>(
58 cs: ConstraintSystemRef<F>,
59 a: &FpVar<F>,
60 b: &FpVar<F>,
61) -> Result<(FpVar<F>, FpVar<F>), SynthesisError> {
62 let over = get_slack(cs.clone(), b, a)?;
63 let undr = get_slack(cs.clone(), a, b)?;
64
65 enforce_in_binary_bound::<_, BITS>(&over)?;
67 enforce_in_binary_bound::<_, BITS>(&undr)?;
68
69 enforce_zero(&over.clone().mul(&undr))?;
71
72 (a + &undr).enforce_equal(&(b + &over))?;
74
75 Ok((undr, over))
76}
77
78#[cfg(test)]
79mod tests {
80 use ark_bn254::Fr;
81 use ark_r1cs_std::{R1CSVar, alloc::AllocVar, fields::fp::FpVar};
82 use ark_relations::r1cs::ConstraintSystem;
83
84 use super::*;
85
86 fn run<const BITS: usize>(a: u64, b: u64) -> Result<(), SynthesisError> {
87 let cs = ConstraintSystem::<Fr>::new_ref();
88 let a_var = FpVar::new_witness(cs.clone(), || Ok(Fr::from(a)))?;
89 let b_var = FpVar::new_witness(cs.clone(), || Ok(Fr::from(b)))?;
90
91 let min_result = min::<_, BITS>(cs.clone(), &a_var, &b_var)?;
92 assert_eq!(min_result.value()?, Fr::from(a.min(b)));
93
94 let max_result = max::<_, BITS>(cs.clone(), &a_var, &b_var)?;
95 assert_eq!(max_result.value()?, Fr::from(a.max(b)));
96
97 let abs_diff_result = abs_diff::<_, BITS>(cs.clone(), &a_var, &b_var)?;
98 assert_eq!(abs_diff_result.value()?, Fr::from(a.abs_diff(b)));
99
100 Ok(())
101 }
102
103 #[test]
104 fn test() -> Result<(), SynthesisError> {
105 run::<3>(3, 5)?;
107 run::<3>(5, 3)?;
108
109 run::<3>(5, 5)?;
111
112 run::<3>(0, 5)?;
114 run::<3>(5, 0)?;
115 run::<3>(0, 0)?;
116
117 run::<64>(123456789, 234567890)?;
119
120 Ok(())
121 }
122}