1+ use p3_field:: PrimeField64 ;
2+
13/// The basic arithmetic operations supported by the VM's `Computation` instruction.
24#[ derive( Debug , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
35pub enum Operation {
@@ -6,3 +8,102 @@ pub enum Operation {
68 /// Field multiplication in the base field.
79 Mul ,
810}
11+
12+ impl Operation {
13+ /// Computes the result of applying this arithmetic operation to two operands.
14+ ///
15+ /// # Parameters
16+ ///
17+ /// - `a`: The left-hand operand.
18+ /// - `b`: The right-hand operand.
19+ ///
20+ /// # Returns
21+ ///
22+ /// The result of `a ⊕ b`, where `⊕` is the operation represented by `self`.
23+ /// For example:
24+ /// - If `self` is `Add`, returns `a + b`.
25+ /// - If `self` is `Mul`, returns `a * b`.
26+ pub fn compute < F > ( & self , a : F , b : F ) -> F
27+ where
28+ F : PrimeField64 ,
29+ {
30+ match self {
31+ Self :: Add => a + b,
32+ Self :: Mul => a * b,
33+ }
34+ }
35+
36+ /// Computes the inverse of the operation with respect to the right-hand operand.
37+ ///
38+ /// Solves for `a` given the result `c = a ⊕ b`, by computing `a = c ⊖ b`, where `⊖`
39+ /// is the inverse of the operation represented by `self`.
40+ ///
41+ /// # Parameters
42+ ///
43+ /// - `a`: The result value (i.e., `a ⊕ b`).
44+ /// - `b`: The right-hand operand of the original operation.
45+ ///
46+ /// # Returns
47+ ///
48+ /// - `Some(a)` if the inverse exists.
49+ /// - `None` if the inverse does not exist (e.g., `b == 0` for `Mul`).
50+ pub fn inverse_compute < F > ( & self , a : F , b : F ) -> Option < F >
51+ where
52+ F : PrimeField64 ,
53+ {
54+ match self {
55+ Self :: Add => Some ( a - b) ,
56+ Self :: Mul => ( !b. is_zero ( ) ) . then ( || a / b) ,
57+ }
58+ }
59+ }
60+
61+ #[ cfg( test) ]
62+ mod tests {
63+ use p3_baby_bear:: BabyBear ;
64+ use p3_field:: PrimeCharacteristicRing ;
65+
66+ use super :: * ;
67+
68+ type F = BabyBear ;
69+
70+ #[ test]
71+ fn test_compute_add ( ) {
72+ let op = Operation :: Add ;
73+ let val1 = F :: from_u32 ( 100 ) ;
74+ let val2 = F :: from_u32 ( 50 ) ;
75+ assert_eq ! ( op. compute( val1, val2) , F :: from_u32( 150 ) ) ;
76+ }
77+
78+ #[ test]
79+ fn test_compute_mul ( ) {
80+ let op = Operation :: Mul ;
81+ let val1 = F :: from_u32 ( 10 ) ;
82+ let val2 = F :: from_u32 ( 5 ) ;
83+ assert_eq ! ( op. compute( val1, val2) , F :: from_u32( 50 ) ) ;
84+ }
85+
86+ #[ test]
87+ fn test_inverse_compute_add ( ) {
88+ let op = Operation :: Add ;
89+ let val1 = F :: from_u32 ( 150 ) ;
90+ let val2 = F :: from_u32 ( 50 ) ;
91+ assert_eq ! ( op. inverse_compute( val1, val2) , Some ( F :: from_u32( 100 ) ) ) ;
92+ }
93+
94+ #[ test]
95+ fn test_inverse_compute_mul_success ( ) {
96+ let op = Operation :: Mul ;
97+ let val1 = F :: from_u32 ( 50 ) ;
98+ let val2 = F :: from_u32 ( 5 ) ;
99+ assert_eq ! ( op. inverse_compute( val1, val2) , Some ( F :: from_u32( 10 ) ) ) ;
100+ }
101+
102+ #[ test]
103+ fn test_inverse_compute_mul_by_zero ( ) {
104+ let op = Operation :: Mul ;
105+ let val1 = F :: from_u32 ( 50 ) ;
106+ let val2 = F :: ZERO ;
107+ assert_eq ! ( op. inverse_compute( val1, val2) , None ) ;
108+ }
109+ }
0 commit comments