Browse Source

Prepare for handing range statements by finding all Pedersen assignment statements in the StatementTree

Ian Goldberg 4 months ago
parent
commit
af0748ec23

+ 3 - 0
sigma_compiler_core/src/lib.rs

@@ -39,6 +39,9 @@ pub fn sigma_compiler_core(
     // Apply any substitution transformations
     substitution::transform(&mut codegen, &mut spec.statements, &mut spec.vars).unwrap();
 
+    // Apply any range statement transformations
+    rangeproof::transform(&mut codegen, &mut spec.statements, &mut spec.vars).unwrap();
+
     /* Just some test code for now:
     let C_var = codegen.gen_point(&mut spec.vars, &quote::format_ident!("C"), false, true);
     let V_var = codegen.gen_point(&mut spec.vars, &quote::format_ident!("V"), true, true);

+ 35 - 2
sigma_compiler_core/src/pedersen.rs

@@ -330,8 +330,8 @@ pub struct Pedersen {
 
 impl Pedersen {
     /// Get the `Ident` for the committed private `Scalar` in a [`Pedersen`]
-    pub fn var(&self) -> Option<Ident> {
-        Some(self.var_term.coeff.id.clone())
+    pub fn var(&self) -> Ident {
+        self.var_term.coeff.id.clone()
     }
 
     /// Negate a [`Pedersen`]
@@ -807,6 +807,39 @@ pub fn recognize_pubscalar(
     Some((is_vec, val))
 }
 
+/// A representation of an assignment [`Expr`] assigning a [Pedersen
+/// expression](Pedersen) to a public `Point`.
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub struct PedersenAssignment {
+    /// The public `Point` being assigned to
+    pub id: Ident,
+    /// The Pedersen expression being assigned
+    pub pedersen: Pedersen,
+}
+
+/// Parse an [`Expr`] to see if we recognize it as an assignment
+/// statement assigning a [Pedersen expression](Pedersen) to an
+/// [`struct@Ident`] for a public `Point`.
+pub fn recognize_pedersen_assignment(
+    vars: &TaggedVarDict,
+    randoms: &HashSet<String>,
+    vardict: &VarDict,
+    expr: &Expr,
+) -> Option<PedersenAssignment> {
+    let Expr::Assign(syn::ExprAssign { left, right, .. }) = expr else {
+        return None;
+    };
+    let Expr::Path(syn::ExprPath { path, .. }) = left.as_ref() else {
+        return None;
+    };
+    let id = path.get_ident()?;
+    let pedersen = recognize_pedersen(vars, randoms, vardict, right)?;
+    Some(PedersenAssignment {
+        id: id.clone(),
+        pedersen,
+    })
+}
+
 #[cfg(test)]
 mod test {
     use super::*;

+ 47 - 3
sigma_compiler_core/src/rangeproof.rs

@@ -20,13 +20,17 @@
 //! private.
 
 use super::codegen::CodeGen;
-use super::pedersen::{recognize_linscalar, recognize_pubscalar, LinScalar};
+use super::pedersen::{
+    recognize_linscalar, recognize_pedersen_assignment, recognize_pubscalar, unique_random_scalars,
+    LinScalar, PedersenAssignment,
+};
 use super::sigma::combiners::*;
 use super::sigma::types::VarDict;
 use super::syntax::taggedvardict_to_vardict;
 use super::transform::paren_if_needed;
-use super::TaggedVarDict;
-use syn::{parse_quote, Expr, Result};
+use super::{TaggedIdent, TaggedPoint, TaggedVarDict};
+use std::collections::HashMap;
+use syn::{parse_quote, Expr, Ident, Result};
 
 /// A struct representing a normalized parsed range statement.
 ///
@@ -195,11 +199,51 @@ pub fn transform(
     // Make the VarDict version of the variable dictionary
     let vardict = taggedvardict_to_vardict(vars);
 
+    // A HashSet of the unique random Scalars in the macro input
+    let randoms = unique_random_scalars(vars, st);
+
     // Gather mutable references to all Exprs in the leaves of the
     // StatementTree.  Note that this ignores the combiner structure in
     // the StatementTree, but that's fine.
     let mut leaves = st.leaves_mut();
 
+    // A list of the computationally independent (non-vector) Points in
+    // the macro input.  There must be at least two of them in order to
+    // handle range statements, so that we can make Pedersen
+    // commitments.
+    let cind_points: Vec<Ident> = vars
+        .values()
+        .filter_map(|ti| {
+            if let TaggedIdent::Point(TaggedPoint {
+                is_cind: true,
+                is_vec: false,
+                id,
+                ..
+            }) = ti
+            {
+                Some(id.clone())
+            } else {
+                None
+            }
+        })
+        .collect();
+
+    // Find any statements that look like Pedersen commitments in the
+    // StatementTree, and make a HashMap mapping the committed private
+    // variable to the parsed commitment.
+    let pedersens: HashMap<Ident, PedersenAssignment> = leaves
+        .iter()
+        .filter_map(|leafexpr| {
+            if let Some(ped_assign) =
+                recognize_pedersen_assignment(vars, &randoms, &vardict, leafexpr)
+            {
+                Some((ped_assign.pedersen.var(), ped_assign))
+            } else {
+                None
+            }
+        })
+        .collect();
+
     // For each leaf expression, see if it looks like a range statement
     for leafexpr in leaves.iter_mut() {
         let is_range = parse(vars, &vardict, leafexpr);

+ 0 - 1
sigma_compiler_core/src/transform.rs

@@ -126,7 +126,6 @@ pub fn paren_if_needed(expr: Expr) -> Expr {
 
 #[cfg(test)]
 mod tests {
-    use super::super::syntax::taggedvardict_from_strs;
     use super::*;
 
     #[test]