瀏覽代碼

CMZ (not muCMZ) issuing progressing

No ZKPs yet
Ian Goldberg 5 月之前
父節點
當前提交
f6a599b9d6
共有 2 個文件被更改,包括 174 次插入43 次删除
  1. 169 43
      cmzcred_derive/src/lib.rs
  2. 5 0
      src/lib.rs

+ 169 - 43
cmzcred_derive/src/lib.rs

@@ -59,6 +59,7 @@ fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStre
         }
     }
     let num_attrs = attrs.len();
+    let attr_index = 0..num_attrs;
     let name = &ast.ident;
     let errmsg = format!("Invalid attribute name for {} CMZ credential", name);
 
@@ -78,6 +79,13 @@ fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStre
                 return #num_attrs;
             }
 
+            fn attr_num(attrname: &str) -> usize {
+                match attrname {
+                    #( #attrs => #attr_index, )*
+                    _ => panic!(#errmsg),
+                }
+            }
+
             fn attr(&self, attrname: &str) -> &Option<Self::Scalar> {
                 match attrname {
                     #( #attrs => &self.#idents, )*
@@ -406,6 +414,7 @@ enum StructField {
     Scalar(Ident),
     Point(Ident),
     EncPoint(Ident),
+    Pubkey(Ident),
 }
 
 // Convenience functions to create StructField items
@@ -419,6 +428,9 @@ impl StructField {
     pub fn encpoint(s: &str) -> Self {
         Self::EncPoint(Ident::new(s, Span::call_site().into()))
     }
+    pub fn pubkey(s: &str) -> Self {
+        Self::Pubkey(Ident::new(s, Span::call_site().into()))
+    }
 }
 
 // A list of StructField items
@@ -437,12 +449,16 @@ impl StructFieldList {
     pub fn push_encpoint(&mut self, s: &str) {
         self.fields.push(StructField::encpoint(s));
     }
+    pub fn push_pubkey(&mut self, s: &str) {
+        self.fields.push(StructField::pubkey(s));
+    }
     /// Output an iterator consisting of the field names
     pub fn field_iter<'a>(&'a self) -> impl Iterator<Item = &'a Ident> {
         self.fields.iter().map(|f| match f {
             StructField::Scalar(id) => id,
             StructField::Point(id) => id,
             StructField::EncPoint(id) => id,
+            StructField::Pubkey(id) => id,
         })
     }
     /// Output a ToTokens of the fields as they would appear in a struct
@@ -461,6 +477,9 @@ impl StructFieldList {
                 #[serde_as(as = "(SerdePoint, SerdePoint)")]
                 pub #id: (Point, Point),
             },
+            StructField::Pubkey(id) => quote! {
+                pub #id: CMZPubkey<Point>,
+            },
         });
         quote! { #(#decls)* }
     }
@@ -533,15 +552,46 @@ fn protocol_macro(
     // Are there any Hide or Joint attributes in _any_ credential to be
     // issued?
     let mut any_hide_joint = false;
+
     for iss_cred in proto_spec.issue_creds.iter() {
         // Are there any Hide or Joint attributes in this particular
         // credential to be issued?
         let mut cred_hide_joint = false;
-        let iss_cred_id = format_ident!("cred_{}", iss_cred.id);
+
+        let iss_cred_id = format_ident!("iss_cred_{}", iss_cred.id);
+        let pubkey_cred = format_ident!("pubkey_iss_cred_{}", iss_cred.id);
+        let b_cred = format_ident!("b_iss_cred_{}", iss_cred.id);
+        let P_cred = format_ident!("P_iss_cred_{}", iss_cred.id);
+        let Q_cred = format_ident!("Q_iss_cred_{}", iss_cred.id);
+        // EQ_cred is only used for CMZ, not muCMZ
+        let EQ_cred = format_ident!("EQ_iss_cred_{}", iss_cred.id);
+        let iss_cred_type = &iss_cred.cred_type;
+        let cred_str = iss_cred.id.to_string();
+
+        // Check that fill_creds filled in the private key for this
+        // credential
+        handle_code_post_fill = quote! {
+            #handle_code_post_fill
+            if #iss_cred_id.privkey.x.len() != #iss_cred_type::num_attrs() {
+                return Err(CMZError::PrivkeyMissing(#cred_str));
+            }
+        };
+
+        // Stash the public key in prepare and use it to fill in the
+        // public key of the completed credential in finalize
+        clientstate_fields.push_pubkey(&pubkey_cred.to_string());
+        prepare_code = quote! {
+            #prepare_code
+            let #pubkey_cred = #iss_cred_id.pubkey;
+        };
+        finalize_code = quote! {
+            #finalize_code
+            #iss_cred_id.pubkey = self.#pubkey_cred;
+        };
+
         for (attr, &spec) in iss_cred.attrs.iter() {
             // String versions of the credential name and the attribute
             // name
-            let cred_str = iss_cred.id.to_string();
             let attr_str = attr.to_string();
 
             // The scoped attribute name
@@ -592,7 +642,9 @@ fn protocol_macro(
                    exponential El Gamal encryption (of the attribute) E_attr =
                    (r_attr*B, attr*B + r_attr*D) for random r_attr.  Include E_attr
                    in the Request, attr in the ClientState, and attr,
-                   r_attr, and E_attr in the CliProof.
+                   r_attr, and E_attr in the CliProof.  Add
+                   b*x_attr*E_attr to E_Q in handle, for the b chosen on
+                   a per-issued-credential basis below.
                 */
                 let enc_attr = format_ident!("E_{}", scoped_attr);
                 let r_attr = format_ident!("r_{}", scoped_attr);
@@ -604,36 +656,18 @@ fn protocol_macro(
                         bp.mulB(&#scoped_attr) +
                         #r_attr * D);
                 };
-            }
-
-            /* For all Hide and Joint attributes of a single credential to be
-               isued (for CMZ): the issuer chooses a random b, computes
-               P = b*B, E_Q = b*x_0*B + \sum_{hide,joint} b*x_attr*E_attr
-               + (0,\sum_{implicit,reveal,set,joint} b*x_attr*attr*B)
-               (note that E_Q and each E_attr are all pairs of Points; the
-               scalar multiplication is componentwise).  Include P, E_Q in
-               Reply. For each such attribute, include t_attr = b*x_attr and
-               T_attr = b*X_attr = t_attr*A in Reply and IssProof.  The client
-               will compute Q = E_Q[1] - d*E_Q[0].
-            */
+                let bx_attr = format_ident!("bx_{}", scoped_attr);
+                handle_code_post_auth = quote! {
+                    #handle_code_post_auth
 
-            /* For all Hide and Joint attributes of a single credential to be
-               issued (for µCMZ): The client chooses a random s, computes C =
-               (\sum_{hide,joint} attr*X_attr) + s*A, where X_attr is the
-               public key for that attribute.  Include s in the ClientState, C
-               in the Request, and the attributes, s, and C in the CliProof.
-               Hide attributes will be passed into prepare on the client side;
-               Joint attributes (client contribution) will be generated randomly
-               by prepare on the client side.  On the issuer side, handle will
-               pick a random b, compute P = b*A, R = b*(x_0*A + C) +
-               \sum_{implicit,reveal,set,joint} x_attr*attr*P.  Include P
-               and R in Reply, and x_0, b, P, R, C in IssProof.  For each
-               implicit,reveal,set,joint attribute, include x_attr and P_attr =
-               attr*P in IssProof.  The client will compute Q = R - s*P.
-            */
+                    let #bx_attr = #b_cred * #iss_cred_id.privkey.x[#iss_cred_type::attr_num(#attr_str)];
+                    #EQ_cred.0 += #bx_attr * request.#enc_attr.0;
+                    #EQ_cred.1 += #bx_attr * request.#enc_attr.1;
+                }
+            }
 
             /* For each Reveal attribute: include attr in Request (client will
-               pass the value into prepare)
+               pass the value into prepare).
             */
             if spec == IssueSpec::Reveal {
                 request_fields.push_scalar(&scoped_attr.to_string());
@@ -646,7 +680,7 @@ fn protocol_macro(
                 handle_code_pre_fill = quote! {
                     #handle_code_pre_fill
                     let #scoped_attr = request.#scoped_attr;
-                }
+                };
             }
 
             /* For each Implicit attribute: does not appear (will be filled in
@@ -685,7 +719,98 @@ fn protocol_macro(
                     #iss_cred_id.#attr = Some(#scoped_attr);
                 }
             }
+
+            /* For each Reveal, Implicit, Set, or Joint attribute, add
+               attr*x_attr*P to Q in handle.
+            */
+            if spec == IssueSpec::Reveal
+                || spec == IssueSpec::Implicit
+                || spec == IssueSpec::Set
+                || spec == IssueSpec::Joint
+            {
+                handle_code_post_auth = quote! {
+                    #handle_code_post_auth
+                    #Q_cred += (#scoped_attr *
+                        #iss_cred_id.privkey.x[#iss_cred_type::attr_num(#attr_str)])
+                        * #P_cred;
+                };
+            }
         }
+
+        if !use_muCMZ {
+            /* For all Hide and Joint attributes of a single credential to be
+               issued (for CMZ): the issuer chooses a random b, computes
+               P = b*B, E_Q = (0,b*x_0*B) + \sum_{hide,joint} b*x_attr*E_attr
+               + (0,\sum_{implicit,reveal,set,joint} b*x_attr*attr*B)
+               (note that E_Q and each E_attr are all pairs of Points; the
+               scalar multiplication is componentwise).  Include P, E_Q in
+               Reply. For each such attribute, include t_attr = b*x_attr and
+               T_attr = b*X_attr = t_attr*A in Reply and IssProof.  The client
+               will compute Q = E_Q[1] - d*E_Q[0].
+            */
+            reply_fields.push_point(&P_cred.to_string());
+            if cred_hide_joint {
+                reply_fields.push_encpoint(&EQ_cred.to_string());
+            } else {
+                reply_fields.push_point(&Q_cred.to_string());
+            }
+            let EQ_cred_code_pre = if cred_hide_joint {
+                quote! {
+                    let mut #EQ_cred = (Point::identity(), Point::identity());
+                }
+            } else {
+                quote! {}
+            };
+            let EQ_cred_code_post = if cred_hide_joint {
+                quote! {
+                    #EQ_cred.1 += #Q_cred;
+                }
+            } else {
+                quote! {}
+            };
+            handle_code_post_auth = quote! {
+                let #b_cred = <Scalar as ff::Field>::random(&mut *rng);
+                let #P_cred = bp.mulB(&#b_cred);
+                let mut #Q_cred = bp.mulB(&(#b_cred * #iss_cred_id.privkey.x0));
+                #EQ_cred_code_pre
+
+                #handle_code_post_auth
+
+                #EQ_cred_code_post
+            };
+            let finalize_Q_code = if cred_hide_joint {
+                quote! {
+                    #iss_cred_id.MAC.Q = reply.#EQ_cred.1 - self.d * reply.#EQ_cred.0;
+                }
+            } else {
+                quote! {
+                    #iss_cred_id.MAC.Q = reply.#Q_cred;
+                }
+            };
+            finalize_code = quote! {
+                #finalize_code
+                #iss_cred_id.MAC.P = reply.#P_cred;
+                #finalize_Q_code
+            };
+        }
+
+        if use_muCMZ {
+            /* For all Hide and Joint attributes of a single credential to be
+               issued (for µCMZ): The client chooses a random s, computes C =
+               (\sum_{hide,joint} attr*X_attr) + s*A, where X_attr is the
+               public key for that attribute.  Include s in the ClientState, C
+               in the Request, and the attributes, s, and C in the CliProof.
+               Hide attributes will be passed into prepare on the client side;
+               Joint attributes (client contribution) will be generated randomly
+               by prepare on the client side.  On the issuer side, handle will
+               pick a random b, compute P = b*A, R = b*(x_0*A + C) +
+               \sum_{implicit,reveal,set,joint} x_attr*attr*P.  Include P
+               and R in Reply, and x_0, b, P, R, C in IssProof.  For each
+               implicit,reveal,set,joint attribute, include x_attr and P_attr =
+               attr*P in IssProof.  The client will compute Q = R - s*P.
+            */
+        }
+
         any_hide_joint |= cred_hide_joint;
     }
 
@@ -809,13 +934,13 @@ fn protocol_macro(
     // immutable reference for each credential to be shown, and an owned
     // value for each credential to be issued.
     let client_show_args = proto_spec.show_creds.iter().map(|c| {
-        let id = format_ident!("cred_{}", c.id);
+        let id = format_ident!("show_cred_{}", c.id);
         let cred_type = &c.cred_type;
         quote! { #id: &#cred_type, }
     });
 
     let client_issue_args = proto_spec.issue_creds.iter().map(|c| {
-        let id = format_ident!("cred_{}", c.id);
+        let id = format_ident!("iss_cred_{}", c.id);
         let cred_type = &c.cred_type;
         quote! { #id: #cred_type, }
     });
@@ -848,12 +973,12 @@ fn protocol_macro(
             .show_creds
             .iter()
             .map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("show_cred_{}", c.id);
                 let cred_type = &c.cred_type;
                 quote! { let mut #id = #cred_type::default(); }
             })
             .chain(proto_spec.issue_creds.iter().map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("iss_cred_{}", c.id);
                 let cred_type = &c.cred_type;
                 quote! { let mut #id = #cred_type::default(); }
             }));
@@ -885,11 +1010,11 @@ fn protocol_macro(
             .show_creds
             .iter()
             .map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("show_cred_{}", c.id);
                 quote! { #id }
             })
             .chain(proto_spec.issue_creds.iter().map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("iss_cred_{}", c.id);
                 quote! { #id }
             }));
 
@@ -911,11 +1036,11 @@ fn protocol_macro(
             .show_creds
             .iter()
             .map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("show_cred_{}", c.id);
                 quote! { &mut #id, }
             })
             .chain(proto_spec.issue_creds.iter().map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("iss_cred_{}", c.id);
                 quote! { &mut #id, }
             }));
 
@@ -944,11 +1069,11 @@ fn protocol_macro(
             .show_creds
             .iter()
             .map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("show_cred_{}", c.id);
                 quote! { &#id, }
             })
             .chain(proto_spec.issue_creds.iter().map(|c| {
-                let id = format_ident!("cred_{}", c.id);
+                let id = format_ident!("iss_cred_{}", c.id);
                 quote! { &#id, }
             }));
 
@@ -971,6 +1096,7 @@ fn protocol_macro(
                 A: FnOnce(#(#authorize_args)*) ->
                     Result<(),CMZError>
             {
+                let bp = cmz_basepoints::<Point>();
                 #(#cred_decls)*
                 #handle_code_pre_fill
                 fill_creds(#(#fill_creds_params)*)?;
@@ -986,7 +1112,7 @@ fn protocol_macro(
     let clientstate_finalize_func = {
         // The credential declarations for the client's finalize function
         let cred_decls = proto_spec.issue_creds.iter().map(|c| {
-            let id = format_ident!("cred_{}", c.id);
+            let id = format_ident!("iss_cred_{}", c.id);
             let cred_type = &c.cred_type;
             quote! { let mut #id = #cred_type::default(); }
         });
@@ -1007,7 +1133,7 @@ fn protocol_macro(
 
         // Return value for ClientState's finalize function
         let cred_retvals = proto_spec.issue_creds.iter().map(|c| {
-            let id = format_ident!("cred_{}", c.id);
+            let id = format_ident!("iss_cred_{}", c.id);
             quote! { #id }
         });
 

+ 5 - 0
src/lib.rs

@@ -261,6 +261,9 @@ where
     /// The number of attributes in this credential
     fn num_attrs() -> usize;
 
+    /// The attribute number for a given name as a string
+    fn attr_num(name: &str) -> usize;
+
     /// Get a reference to one of the attributes, specified by name as a
     /// string.
     fn attr(&self, name: &str) -> &Option<Self::Scalar>;
@@ -392,6 +395,8 @@ pub enum CMZError {
     ImplicitAttrIssMissing(&'static str, &'static str),
     #[error("Set attribute {1} of credential {0} was not set by fill_creds")]
     SetAttrMissing(&'static str, &'static str),
+    #[error("private key for credential {0} was not set by fill_creds")]
+    PrivkeyMissing(&'static str),
     #[error("unknown CMZ proof error")]
     Unknown,
 }