Browse Source

A little more on the Pedersen commitment expression recognizer

Ian Goldberg 4 months ago
parent
commit
8342b14159
1 changed files with 61 additions and 3 deletions
  1. 61 3
      sigma_compiler_core/src/pedersen.rs

+ 61 - 3
sigma_compiler_core/src/pedersen.rs

@@ -108,6 +108,43 @@ impl LinScalar {
             ..self
         })
     }
+
+    /// Add a public `Scalar` expression to a [`LinScalar`]
+    pub fn add_opt_pub_scalar_expr(self, opsexpr: Option<Expr>) -> Result<Self> {
+        if let Some(psexpr) = opsexpr {
+            Ok(Self {
+                pub_scalar_expr: if let Some(expr) = self.pub_scalar_expr {
+                    let ppsexpr = paren_if_needed(psexpr);
+                    Some(parse_quote! { #expr + #ppsexpr })
+                } else {
+                    Some(psexpr)
+                },
+                ..self
+            })
+        } else {
+            Ok(self)
+        }
+    }
+
+    /// Add a [`LinScalar`] to a [`LinScalar`].
+    ///
+    /// The private variables must match.
+    pub fn add_linscalar(self, arg: Self) -> Result<Self> {
+        if self.id != arg.id {
+            return Err(Error::new(
+                proc_macro2::Span::call_site(),
+                "private variables in added LinScalars do not match",
+            ));
+        }
+        Self {
+            coeff: self.coeff.checked_add(arg.coeff).ok_or(Error::new(
+                proc_macro2::Span::call_site(),
+                "i128 add overflow",
+            ))?,
+            ..self
+        }
+        .add_opt_pub_scalar_expr(arg.pub_scalar_expr)
+    }
 }
 
 /// A representation of `b*A` where `b` is a public `Scalar` [arithmetic
@@ -126,8 +163,9 @@ impl CIndPoint {
     /// Negate a [`CIndPoint`]
     pub fn neg(self) -> Result<Self> {
         Ok(Self {
-            coeff: Some(if let Some(expr) = &self.coeff {
-                parse_quote! { -#expr }
+            coeff: Some(if let Some(expr) = self.coeff {
+                let pexpr = paren_if_needed(expr);
+                parse_quote! { -#pexpr }
             } else {
                 parse_quote! { -1 }
             }),
@@ -289,7 +327,27 @@ impl<'a> AExprFold<PedersenExpr> for RecognizeFold<'a> {
         rarg: (AExprType, PedersenExpr),
         restype: AExprType,
     ) -> Result<PedersenExpr> {
-        Ok(larg.1)
+        match (larg.1, rarg.1) {
+            // Adding two PubScalarExprs yields a PubScalarExpr
+            (PedersenExpr::PubScalarExpr(lexpr), PedersenExpr::PubScalarExpr(rexpr)) => Ok(
+                PedersenExpr::PubScalarExpr(parse_quote! { #lexpr + #rexpr }),
+            ),
+            // Adding a PubScalarExpr and a LinScalar yields a LinScalar
+            (PedersenExpr::PubScalarExpr(psexpr), PedersenExpr::LinScalar(linscalar))
+            | (PedersenExpr::LinScalar(linscalar), PedersenExpr::PubScalarExpr(psexpr)) => Ok(
+                PedersenExpr::LinScalar(linscalar.add_opt_pub_scalar_expr(Some(psexpr))?),
+            ),
+            // Adding two LinScalars yields a LinScalar if they're for
+            // the same private variable
+            (PedersenExpr::LinScalar(llinscalar), PedersenExpr::LinScalar(rlinscalar)) => Ok(
+                PedersenExpr::LinScalar(llinscalar.add_linscalar(rlinscalar)?),
+            ),
+            // Nothing else is valid
+            _ => Err(Error::new(
+                proc_macro2::Span::call_site(),
+                "not a component of a Pedersen commitment",
+            )),
+        }
     }
 
     /// Called when adding two `Point`s