Procházet zdrojové kódy

Broaden the places where rand Scalars can appear

Before, a rand Scalar could only appear one time in total over
all of the statements in the ZKP.  If one appeared more than once,
it would not be considered "rand" for the purposes of recognizing
Pedersen commitments.

This was overly conservative, and the rule was indeed violated with
CMZ credentials, where the statements have the rand values appearing
(typically) twice each.

Now, rand Scalars can appear multiple times in linear combination
statements, but cannot appear at all (with a compile-time error) in
range or not-equals statements (where it never made sense for them to
appear anyway).
Ian Goldberg před 1 měsícem
rodič
revize
226adac8a7

+ 2 - 2
README.md

@@ -39,8 +39,8 @@ The pieces are as follows:
       value other than what is implied by the truth of the
       statements.
     - `rand` means that the `Scalar` is a uniform random `Scalar`.
-      A `rand` `Scalar` must be used only once in the statements.
-      These are typically used as randomizers in Pedersen
+      A `rand` `Scalar` may not be used in range or not-equals
+      statements.  These are typically used as randomizers in Pedersen
       commitments.
     - `vec` means that the variable represents a vector of
       `Scalar`s, as opposed to a single `Scalar`.  The number of

+ 18 - 4
sigma-compiler-core/src/notequals.rs

@@ -11,8 +11,8 @@
 
 use super::codegen::CodeGen;
 use super::pedersen::{
-    convert_commitment, convert_randomness, recognize_linscalar, recognize_pedersen_assignment,
-    recognize_pubscalar, unique_random_scalars, LinScalar, PedersenAssignment,
+    convert_commitment, convert_randomness, random_scalars, recognize_linscalar,
+    recognize_pedersen_assignment, recognize_pubscalar, LinScalar, PedersenAssignment,
 };
 use super::sigma::combiners::*;
 use super::sigma::types::{expr_type_tokens, VarDict};
@@ -21,6 +21,7 @@ use super::transform::paren_if_needed;
 use super::TaggedVarDict;
 use quote::{format_ident, quote};
 use std::collections::HashMap;
+use syn::spanned::Spanned;
 use syn::{parse_quote, Error, Expr, Ident, Result};
 
 /// Subtract the Expr `subexpr` (with constant value `subval`, if
@@ -81,8 +82,8 @@ pub fn transform(
     // Make the VarDict version of the variable dictionary
     let mut vardict = taggedvardict_to_vardict(vars);
 
-    // A HashSet of the unique random Scalars in the macro input
-    let mut randoms = unique_random_scalars(vars, st);
+    // A HashSet of the random Scalars in the macro input
+    let mut randoms = random_scalars(vars, st);
 
     // Gather mutable references to all of the leaves of the
     // StatementTree.  Note that this ignores the combiner structure in
@@ -130,6 +131,19 @@ pub fn transform(
         };
         neq_stmt_index += 1;
 
+        // The variable in the not-equals statement must not be tagged "rand"
+        if let Some(super::TaggedIdent::Scalar(super::TaggedScalar {
+            is_pub: false,
+            is_rand: true,
+            ..
+        })) = vars.get(&neq_linscalar.id.to_string())
+        {
+            return Err(Error::new(
+                leafexpr.span(),
+                "target of not-equals expression cannot be rand",
+            ));
+        }
+
         // We will transform the not-equals statement into a list of
         // basic linear combination statements that will be ANDed
         // together to replace the not-equals statement in the

+ 15 - 30
sigma-compiler-core/src/pedersen.rs

@@ -18,15 +18,14 @@ use super::syntax::*;
 use super::transform::paren_if_needed;
 use proc_macro2::TokenStream;
 use quote::quote;
-use std::collections::{HashMap, HashSet};
+use std::collections::HashSet;
 use syn::parse::Result;
 use syn::visit::Visit;
 use syn::{parse_quote, Error, Expr, Ident};
 
 /// Find all random private `Scalar`s (according to the
-/// [`TaggedVarDict`]) that appear exactly once in the
-/// [`StatementTree`].
-pub fn unique_random_scalars(vars: &TaggedVarDict, st: &StatementTree) -> HashSet<String> {
+/// [`TaggedVarDict`]) that appear in the [`StatementTree`].
+pub fn random_scalars(vars: &TaggedVarDict, st: &StatementTree) -> HashSet<String> {
     // Filter the TaggedVarDict so that it only contains the private
     // _random_ Scalars
     let random_private_scalars: VarDict = vars
@@ -44,22 +43,17 @@ pub fn unique_random_scalars(vars: &TaggedVarDict, st: &StatementTree) -> HashSe
         .map(|(k, v)| (k.clone(), AExprType::from(v)))
         .collect();
 
-    let mut seen_randoms: HashMap<String, usize> = HashMap::new();
+    let mut seen_randoms: HashSet<String> = HashSet::new();
 
     // Create a PrivScalarMap that will call the given closure for each
     // private Scalar (listed in the VarDict) in a supplied expression
     let mut var_map = PrivScalarMap {
         vars: &random_private_scalars,
-        // The closure counts how many times each private random Scalar
-        // in the VarDict appears in total
+        // The closure records each private random Scalar in the VarDict
+        // we encounter
         closure: &mut |ident| {
             let id_str = ident.to_string();
-            let val = seen_randoms.get(&id_str);
-            let newval = match val {
-                Some(n) => n + 1,
-                None => 1,
-            };
-            seen_randoms.insert(id_str, newval);
+            seen_randoms.insert(id_str);
             Ok(())
         },
         result: Ok(()),
@@ -69,11 +63,8 @@ pub fn unique_random_scalars(vars: &TaggedVarDict, st: &StatementTree) -> HashSe
     for e in st.leaves() {
         var_map.visit_expr(e);
     }
-    // Return a HashSet of the ones that we saw exactly once
+    // Return a HashSet of the ones that we saw
     seen_randoms
-        .into_iter()
-        .filter_map(|(k, v)| if v == 1 { Some(k) } else { None })
-        .collect()
 }
 
 /// A representation of `a*x + b` where `a` is a constant `Scalar`, `b`
@@ -371,9 +362,6 @@ impl Pedersen {
                 ..self
             })
         } else if self.rand_term.id == arg.id {
-            // This branch actually can't happen, since the private
-            // random Scalar variable can only appear once in the
-            // StatementTree.
             Ok(Self {
                 rand_term: self.rand_term.add_cind(arg)?,
                 ..self
@@ -394,9 +382,6 @@ impl Pedersen {
                 ..self
             })
         } else if self.rand_term.id == arg.id {
-            // This branch actually can't happen, since the private
-            // random Scalar variable can only appear once in the
-            // StatementTree.
             Ok(Self {
                 rand_term: self.rand_term.add_term(arg)?,
                 ..self
@@ -1029,22 +1014,22 @@ mod test {
     use quote::format_ident;
     use syn::{parse_quote, Expr};
 
-    fn unique_random_scalars_tester(vars: (&[&str], &[&str]), e: Expr, expected: &[&str]) {
+    fn random_scalars_tester(vars: (&[&str], &[&str]), e: Expr, expected: &[&str]) {
         let taggedvardict = taggedvardict_from_strs(vars);
         let st = StatementTree::parse(&e).unwrap();
         let expected_out = expected.iter().map(|s| s.to_string()).collect();
-        let output = unique_random_scalars(&taggedvardict, &st);
+        let output = random_scalars(&taggedvardict, &st);
         assert_eq!(output, expected_out);
     }
 
     #[test]
-    fn unique_random_scalars_test() {
+    fn random_scalars_test() {
         let vars = (
             ["x", "y", "z", "rand r", "rand s", "rand t"].as_slice(),
             ["C", "cind A", "cind B"].as_slice(),
         );
 
-        unique_random_scalars_tester(
+        random_scalars_tester(
             vars,
             parse_quote! {
                 C = x*A + r*B
@@ -1052,7 +1037,7 @@ mod test {
             ["r"].as_slice(),
         );
 
-        unique_random_scalars_tester(
+        random_scalars_tester(
             vars,
             parse_quote! {
                 AND (
@@ -1063,7 +1048,7 @@ mod test {
             ["r", "s"].as_slice(),
         );
 
-        unique_random_scalars_tester(
+        random_scalars_tester(
             vars,
             parse_quote! {
                 AND (
@@ -1075,7 +1060,7 @@ mod test {
                     E = z*A + r*B,
                 )
             },
-            ["s", "t"].as_slice(),
+            ["r", "s", "t"].as_slice(),
         );
     }
 

+ 18 - 4
sigma-compiler-core/src/rangeproof.rs

@@ -21,8 +21,8 @@
 
 use super::codegen::CodeGen;
 use super::pedersen::{
-    convert_commitment, convert_randomness, recognize_linscalar, recognize_pedersen_assignment,
-    recognize_pubscalar, unique_random_scalars, LinScalar, PedersenAssignment,
+    convert_commitment, convert_randomness, random_scalars, recognize_linscalar,
+    recognize_pedersen_assignment, recognize_pubscalar, LinScalar, PedersenAssignment,
 };
 use super::sigma::combiners::*;
 use super::sigma::types::{expr_type_tokens, VarDict};
@@ -31,6 +31,7 @@ use super::transform::paren_if_needed;
 use super::TaggedVarDict;
 use quote::{format_ident, quote};
 use std::collections::HashMap;
+use syn::spanned::Spanned;
 use syn::{parse_quote, Error, Expr, Ident, Result};
 
 /// A struct representing a normalized parsed range statement.
@@ -198,8 +199,8 @@ pub fn transform(
     // Make the VarDict version of the variable dictionary
     let mut vardict = taggedvardict_to_vardict(vars);
 
-    // A HashSet of the unique random Scalars in the macro input
-    let mut randoms = unique_random_scalars(vars, st);
+    // A HashSet of the random Scalars in the macro input
+    let mut randoms = random_scalars(vars, st);
 
     // Gather mutable references to all of the leaves of the
     // StatementTree.  Note that this ignores the combiner structure in
@@ -247,6 +248,19 @@ pub fn transform(
         };
         range_stmt_index += 1;
 
+        // The variable in the range statement must not be tagged "rand"
+        if let Some(super::TaggedIdent::Scalar(super::TaggedScalar {
+            is_pub: false,
+            is_rand: true,
+            ..
+        })) = vars.get(&range_stmt.linscalar.id.to_string())
+        {
+            return Err(Error::new(
+                leafexpr.span(),
+                "target of range expression cannot be rand",
+            ));
+        }
+
         // We will transform the range statement into a list of basic
         // linear combination statements that will be ANDed together to
         // replace the range statement in the StatementTree.  This

+ 3 - 3
sigma-compiler-core/src/transform.rs

@@ -5,7 +5,7 @@
 
 use super::codegen::CodeGen;
 use super::pedersen::{
-    convert_commitment, convert_randomness, recognize_pedersen_assignment, unique_random_scalars,
+    convert_commitment, convert_randomness, random_scalars, recognize_pedersen_assignment,
     LinScalar, PedersenAssignment,
 };
 use super::sigma::combiners::*;
@@ -132,8 +132,8 @@ pub fn enforce_disjunction_invariant(
     // Make the VarDict version of the variable dictionary
     let mut vardict = taggedvardict_to_vardict(vars);
 
-    // A HashSet of the unique random Scalars in the macro input
-    let mut randoms = unique_random_scalars(vars, st);
+    // A HashSet of the random Scalars in the macro input
+    let mut randoms = random_scalars(vars, st);
 
     // A list of the computationally independent (non-vector) Points in
     // the macro input.  If we need to do any transformations, there