Переглянути джерело

Support CMZ protocols with public Points as parameters, not just public Scalars

Ian Goldberg 2 місяців тому
батько
коміт
32697bba53
2 змінених файлів з 38 додано та 9 видалено
  1. 8 6
      README.md
  2. 30 3
      cmzcred_derive/src/lib.rs

+ 8 - 6
README.md

@@ -286,9 +286,9 @@ or if as in this case, there's just one, as a single element.
 ### Parameterized Protocols
 
 A protocol can optionally be declared as having _parameters_, which are
-public Scalar constants that will be filled in at runtime.  You declare
-parameters by changing the first line of the `muCMZProtocol!` macro
-invocation from, for example:
+public Scalar or Point constants that will be filled in at runtime.  You
+declare parameters by changing the first line of the `muCMZProtocol!`
+macro invocation from, for example:
 
 ```rust
     muCMZProtocol! { proto_name,
@@ -297,12 +297,14 @@ invocation from, for example:
 to:
 
 ```rust
-    muCMZProtocol! { proto_name<param1, param2>,
+    muCMZProtocol! { proto_name<param1, param2, @param3>,
 ```
 
 then you can use `param1` and `param2` wherever you could have used a
-literal Scalar constant in the statements in the statement list.  For
-example:
+literal Scalar constant in the statements in the statement list, and
+`param3` wherever you could have used a public Point (the `@` indicates
+the parameter is a Point; the default is that the parameter is a
+Scalar).  For example:
 
 ```rust
     muCMZProtocol! { wallet_spend<fee>,

+ 30 - 3
cmzcred_derive/src/lib.rs

@@ -428,6 +428,7 @@ impl<ShowOrIssue: Parse + Copy, const VALID_OPTIONAL: bool> Parse
 struct ProtoSpec {
     proto_name: Ident,
     params: Vec<Ident>,
+    point_params: Vec<Ident>,
     show_creds: Vec<CredSpec<ShowSpec, true>>,
     issue_creds: Vec<CredSpec<IssueSpec, false>>,
     statements: Vec<Expr>,
@@ -436,6 +437,7 @@ struct ProtoSpec {
 impl Parse for ProtoSpec {
     fn parse(input: ParseStream) -> Result<Self> {
         let mut params: Vec<Ident> = Vec::new();
+        let mut point_params: Vec<Ident> = Vec::new();
         let proto_name: Ident = input.parse()?;
         // See if there are optional parameters; Rust does not provide a
         // convenient angle-bracket parser like it does parens, square
@@ -446,8 +448,16 @@ impl Parse for ProtoSpec {
                 if input.peek(Token![>]) {
                     break;
                 }
-                let param: Ident = input.parse()?;
-                params.push(param);
+                if input.peek(Token![@]) {
+                    // Param identifiers starting with @ are Points
+                    // rather than Scalars.
+                    input.parse::<Token![@]>()?;
+                    let param: Ident = input.parse()?;
+                    point_params.push(param);
+                } else {
+                    let param: Ident = input.parse()?;
+                    params.push(param);
+                }
                 if input.peek(Token![>]) {
                     break;
                 }
@@ -467,6 +477,7 @@ impl Parse for ProtoSpec {
         Ok(ProtoSpec {
             proto_name,
             params,
+            point_params,
             show_creds: showvec.0,
             issue_creds: issuevec.0,
             statements,
@@ -555,7 +566,7 @@ fn protocol_macro(
     let proto_spec: ProtoSpec = parse_macro_input!(input as ProtoSpec);
 
     let proto_name = &proto_spec.proto_name;
-    let has_params = !proto_spec.params.is_empty();
+    let has_params = !proto_spec.params.is_empty() || !proto_spec.point_params.is_empty();
     let tot_num_creds = proto_spec.show_creds.len() + proto_spec.issue_creds.len();
 
     // Use the group of the first named credential type
@@ -1540,6 +1551,20 @@ fn protocol_macro(
         cli_proof_idmap.insert(("".to_string(), paramid.to_string()), scoped_param.clone());
     }
 
+    for paramid in proto_spec.point_params.iter() {
+        let scoped_param = format_ident!("param_{}", paramid);
+        prepare_code = quote! {
+            #prepare_code
+            let #scoped_param = params.#paramid;
+        };
+        handle_code_post_fill = quote! {
+            #handle_code_post_fill
+            let #scoped_param = params.#paramid;
+        };
+        cli_proof_pub_points.push(scoped_param.clone());
+        cli_proof_idmap.insert(("".to_string(), paramid.to_string()), scoped_param.clone());
+    }
+
     // The client will create a zero-knowledge proof
     let cli_proof_ident = format_ident!("cli_proof");
     request_fields.push_bytevec(&cli_proof_ident);
@@ -1582,9 +1607,11 @@ fn protocol_macro(
     // Build the Params struct, if we have params
     let params_struct = if has_params {
         let param_list = &proto_spec.params;
+        let point_param_list = &proto_spec.point_params;
         quote! {
             pub struct Params {
                 #( pub #param_list: Scalar, )*
+                #( pub #point_param_list: Point, )*
             }
         }
     } else {