浏览代码

Refactor to use runtime/derive/core crate pattern

Ian Goldberg 1 月之前
父节点
当前提交
e850753df0
共有 6 个文件被更改,包括 335 次插入315 次删除
  1. 1 1
      Cargo.toml
  2. 1 4
      cmz_core/Cargo.toml
  3. 11 309
      cmz_core/src/lib.rs
  4. 14 0
      cmz_derive/Cargo.toml
  5. 307 0
      cmz_derive/src/lib.rs
  6. 1 1
      src/lib.rs

+ 1 - 1
Cargo.toml

@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-cmzcred_derive = { path = "cmzcred_derive" }
+cmz_derive = { path = "cmz_derive" }
 ff = "0.13"
 generic_static = "0.2"
 group = "0.13"

+ 1 - 4
cmzcred_derive/Cargo.toml → cmz_core/Cargo.toml

@@ -1,11 +1,8 @@
 [package]
-name = "cmzcred_derive"
+name = "cmz_core"
 version = "0.1.0"
 edition = "2021"
 
-[lib]
-proc-macro = true
-
 [dependencies]
 syn = { version = "2.0", features = ["extra-traits", "visit-mut"] }
 quote = "1.0"

+ 11 - 309
cmzcred_derive/src/lib.rs → cmz_core/src/lib.rs

@@ -1,272 +1,15 @@
-// We want the macros like CMZ14Protocol to be camel case
+// We want to allow Point variables to be uppercase
 #![allow(non_snake_case)]
 
-/*! The implementation of the CMZCred derive.
+//! The core functionality of the CMZ protocol macros
 
-This derive should not be explicitly used by a programmer using a CMZ
-credential.  Instead, a CMZ credential should be declared with the
-
-`CMZ!{ Name: attr1, attr2, attr3 }`
-
-macro.  That macro will internally expand to a struct annotated with
-this CMZCred derive.  This derive will output the implementation of
-the CMZCredential trait for the declared credential.
-
-*/
-
-use darling::FromDeriveInput;
-use proc_macro::TokenStream;
-use proc_macro2::TokenStream as TokenStream2;
+use proc_macro2::TokenStream;
 use quote::{format_ident, quote, ToTokens};
 use std::collections::HashMap;
 use syn::parse::{Parse, ParseStream, Result};
 use syn::punctuated::Punctuated;
 use syn::visit_mut::{self, VisitMut};
-use syn::{
-    braced, bracketed, parse_macro_input, parse_quote, token, Data, DataStruct, DeriveInput, Expr,
-    Fields, FieldsNamed, Ident, Member, Token, Visibility,
-};
-
-fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStream {
-    // Ensure that CMZCred is derived on a struct and not something else
-    // (like an enum)
-    let Data::Struct(DataStruct {
-        struct_token: _,
-        fields:
-            Fields::Named(FieldsNamed {
-                brace_token: _,
-                ref named,
-            }),
-        semi_token: _,
-    }) = ast.data
-    else {
-        panic!("CMZCred derived on a non-struct");
-    };
-    // attrs and idents are each vectors of the names of the attributes
-    // of the credential (not including the MAC and any non-public
-    // fields).  attrs stores the names as Strings, while idents stores
-    // them as Idents.
-    let mut attrs = Vec::<String>::new();
-    let mut idents = Vec::<&Ident>::new();
-    for n in named {
-        let Some(ref ident) = n.ident else {
-            panic!("Missing attribute name in CMZCred");
-        };
-        let id_str = ident.to_string();
-        if let Visibility::Public(_) = n.vis {
-            if id_str != *"MAC" {
-                attrs.push(id_str);
-                idents.push(ident);
-            }
-        }
-    }
-    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);
-
-    // Output the CMZCredential trait implementation
-    let gen = quote! {
-        impl CMZCredential for #name {
-            type Scalar = <#group_ident as Group>::Scalar;
-            type Point = #group_ident;
-
-            fn attrs() -> Vec<&'static str> {
-                vec![
-                    #( #attrs, )*
-                ]
-            }
-
-            fn num_attrs() -> usize {
-                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, )*
-                    _ => panic!(#errmsg),
-                }
-            }
-
-            fn attr_mut(&mut self, attrname: &str) -> &mut Option<Self::Scalar> {
-                match attrname {
-                    #( #attrs => &mut self.#idents, )*
-                    _ => panic!(#errmsg),
-                }
-            }
-
-            fn set_pubkey(&mut self, pubkey: &CMZPubkey<Self::Point>) -> &mut Self {
-                self.pubkey = pubkey.clone();
-                self
-            }
-
-            fn get_pubkey<'a> (&'a self) -> &'a CMZPubkey<Self::Point> {
-                &self.pubkey
-            }
-
-            fn set_privkey(&mut self, privkey: &CMZPrivkey<Self::Point>) -> &mut Self {
-                self.pubkey = cmz_privkey_to_pubkey(&privkey);
-                self.privkey = privkey.clone();
-                self
-            }
-
-            fn get_privkey<'a> (&'a self) -> &'a CMZPrivkey<Self::Point> {
-                &self.privkey
-            }
-
-            fn privkey_x(&self, name: &str) -> Self::Scalar {
-                self.privkey.x[Self::attr_num(name)]
-            }
-
-            fn pubkey_X(&self, name: &str) -> Self::Point {
-                self.pubkey.X[Self::attr_num(name)]
-            }
-
-            fn gen_keys(rng: &mut impl RngCore, muCMZ: bool) ->
-                    (CMZPrivkey<Self::Point>, CMZPubkey<Self::Point>) {
-                // Generate (num_attrs + 2) random scalars as the
-                // private key
-                let x0 = <Self::Scalar as ff::Field>::random(&mut *rng);
-                let xr = <Self::Scalar as ff::Field>::random(&mut *rng);
-                let x: Vec<Self::Scalar> = (0..Self::num_attrs())
-                    .map(|_| <Self::Scalar as ff::Field>::random(&mut *rng))
-                    .collect();
-                let privkey = CMZPrivkey { muCMZ, x0, xr, x };
-
-                // Convert the private key to a public key
-                let pubkey = cmz_privkey_to_pubkey(&privkey);
-
-                (privkey, pubkey)
-            }
-
-            fn compute_MAC_coeff(&self, privkey: &CMZPrivkey<Self::Point>) -> Result<Self::Scalar, ()> {
-                if privkey.x.len() != Self::num_attrs() {
-                    return Err(());
-                }
-                let mut coeff = privkey.x0;
-                if privkey.muCMZ {
-                    coeff += privkey.xr;
-                }
-                for field in Self::attrs().iter() {
-                    let attr_val = self.attr(field).ok_or(())?;
-                    coeff += attr_val * privkey.x[Self::attr_num(field)];
-                }
-                Ok(coeff)
-            }
-
-            fn create_MAC(&mut self, rng: &mut impl RngCore, privkey: &CMZPrivkey<Self::Point>) -> Result<(),()> {
-                let coeff = self.compute_MAC_coeff(privkey)?;
-                self.MAC.P = <Self::Point as group::Group>::random(&mut *rng);
-                self.MAC.Q = coeff * self.MAC.P;
-                Ok(())
-            }
-
-            fn verify_MAC(&self, privkey: &CMZPrivkey<Self::Point>) ->
-                    Result<(),()> {
-                let coeff = self.compute_MAC_coeff(privkey)?;
-                if !bool::from(self.MAC.P.is_identity()) && coeff * self.MAC.P == self.MAC.Q {
-                    Ok(())
-                } else {
-                    Err(())
-                }
-            }
-
-            fn fake_MAC(&mut self, rng: &mut impl RngCore) {
-                self.MAC.P = <Self::Point as group::Group>::random(&mut *rng);
-                self.MAC.Q = <Self::Point as group::Group>::random(&mut *rng);
-            }
-
-        }
-    };
-    gen.into()
-}
-
-#[derive(FromDeriveInput)]
-#[darling(attributes(cmzcred_group))]
-struct GroupIdent {
-    group: Ident,
-}
-
-#[proc_macro_derive(CMZCred, attributes(cmzcred_group))]
-pub fn cmzcred_derive(input: TokenStream) -> TokenStream {
-    // Construct a representation of Rust code as a syntax tree
-    // that we can manipulate
-    let ast: DeriveInput = syn::parse(input).unwrap();
-
-    // Get the cmzcred_group(group = G) attribute
-    let group_ident = GroupIdent::from_derive_input(&ast)
-        .expect("missing group parameter to cmzcred_group attribute");
-
-    // Build the trait implementation
-    impl_cmzcred_derive(&ast, &group_ident.group)
-}
-
-/** The CMZ Protocol creation macros.
-
-   The format is:
-
-   let proto = muCMZProtocol! { proto_name<param1,param2>,
-     [ A: Cred {
-         attr1: H,
-         attr2: R,
-       },
-       B?: Cred2 {
-         attr3: H,
-         attr4: I,
-       } ],
-     C: Cred3 {
-       attr5: J,
-       attr6: R,
-       attr7: H,
-       attr8: I,
-       attr9: S,
-     },
-     A.attr1 == B.attr3 + param1,
-     A.attr1 == C.attr7,
-   };
-
-   The parameters are:
-   - an identifier for the protocol
-   - an optional angle-bracketed list of parameters (identifiers)
-   - a list of zero or more specifications for credentials that will be shown
-   - a list of zero or more specifications for credentials that will be issued
-   - zero or more statements relating the attributes in the credentials
-
-   Each credential specification list can be:
-   - empty
-   - a single credential specification
-   - a square-bracketed list of credential specifications
-
-   Each credential specification is:
-   - an identifier for the credential
-   - for a shown (not issued) credential, an optional "?".  If present,
-     the validity of this credential will _not_ be proved by default,
-     and must be explicit (perhaps in only some branches of an "OR"
-     statement) in the statements; if absent (the default), the validity
-     of the shown credential will always be proven
-   - a type for the credential, previously defined with the CMZ! macro
-   - a braced list of the attributes of the credential (as defined in
-     the CMZ! macro), annotated with the attribute specification
-
-   An attribute specification for a credential to be shown is one of:
-   - H (hide)
-   - R (reveal)
-   - I (implicit)
-
-   An attribute specification for a credential to be issued is one of:
-   - H (hide)
-   - R (reveal)
-   - I (implicit)
-   - S (set by issuer)
-   - J (joint creation)
-*/
+use syn::{braced, bracketed, parse_quote, token, Expr, Ident, Member, Token};
 
 // The possible attribute specifications for a credential to be shown
 #[derive(Copy, Clone, Debug, PartialEq)]
@@ -425,7 +168,7 @@ impl<ShowOrIssue: Parse + Copy, const VALID_OPTIONAL: bool> Parse
 
 // A protocol specification, following the syntax described above.
 #[derive(Debug)]
-struct ProtoSpec {
+pub struct ProtoSpec {
     proto_name: Ident,
     params: Vec<Ident>,
     point_params: Vec<Ident>,
@@ -557,14 +300,12 @@ impl StructFieldList {
 // This is where the main work is done.  The six macros in the
 // CMZProtocol macro family (below) all call this function, with
 // different values for the bools.
-fn protocol_macro(
-    input: TokenStream,
+pub fn cmz_core(
+    proto_spec: &ProtoSpec,
     use_muCMZ: bool,
     emit_client: bool,
     emit_issuer: bool,
 ) -> TokenStream {
-    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() || !proto_spec.point_params.is_empty();
     let tot_num_creds = proto_spec.show_creds.len() + proto_spec.issue_creds.len();
@@ -593,7 +334,7 @@ fn protocol_macro(
     let mut cli_proof_cind_points = Vec::<Ident>::default();
     let mut cli_proof_pub_points = Vec::<Ident>::default();
     let mut cli_proof_const_points = Vec::<Ident>::default();
-    let mut cli_proof_statements = Vec::<TokenStream2>::default();
+    let mut cli_proof_statements = Vec::<TokenStream>::default();
     // A map from the credential name and attribute name (as Strings) to
     // the scoped attribute identifier.  This map is used to translate
     // expressions like `L.id` in the user-provided statements into the
@@ -607,7 +348,7 @@ fn protocol_macro(
     // The issuer has no cind_points
     let mut iss_proof_pub_points = Vec::<Ident>::default();
     let mut iss_proof_const_points = Vec::<Ident>::default();
-    let mut iss_proof_statements = Vec::<TokenStream2>::default();
+    let mut iss_proof_statements = Vec::<TokenStream>::default();
 
     /* Credential issuing
 
@@ -1318,7 +1059,7 @@ fn protocol_macro(
     }
 
     // Validity proofs for shown credentials with valid_optional go here
-    let mut validity_proofs: HashMap<String, TokenStream2> = HashMap::new();
+    let mut validity_proofs: HashMap<String, TokenStream> = HashMap::new();
 
     for show_cred in proto_spec.show_creds.iter() {
         // The credential being shown
@@ -1725,7 +1466,7 @@ fn protocol_macro(
 
     struct StatementScoper<'a> {
         idmap: &'a HashMap<(String, String), Ident>,
-        validity_proofs: &'a HashMap<String, TokenStream2>,
+        validity_proofs: &'a HashMap<String, TokenStream>,
     }
 
     impl<'a> VisitMut for StatementScoper<'a> {
@@ -2115,43 +1856,4 @@ fn protocol_macro(
             #issuer_side
         }
     }
-    .into()
-}
-
-/** There are six variants of the `CMZProtocol` macro.  The ones starting
-  with "CMZ14" create protocol implementations using the original CMZ14
-  issuing protocol.  The ones starting with "muCMZ" using the more
-  efficient µCMZ protocol.  The ones with "Cli" only create the code
-  for the client side of the protocol.  The ones with "Iss" only create
-  the code for the issuer side of the protocol.  (The ones without
-  either create the code for both sides of the protocol.)
-*/
-#[proc_macro]
-pub fn CMZ14Protocol(input: TokenStream) -> TokenStream {
-    protocol_macro(input, false, true, true)
-}
-
-#[proc_macro]
-pub fn CMZ14CliProtocol(input: TokenStream) -> TokenStream {
-    protocol_macro(input, false, true, false)
-}
-
-#[proc_macro]
-pub fn CMZ14IssProtocol(input: TokenStream) -> TokenStream {
-    protocol_macro(input, false, false, true)
-}
-
-#[proc_macro]
-pub fn muCMZProtocol(input: TokenStream) -> TokenStream {
-    protocol_macro(input, true, true, true)
-}
-
-#[proc_macro]
-pub fn muCMZCliProtocol(input: TokenStream) -> TokenStream {
-    protocol_macro(input, true, true, false)
-}
-
-#[proc_macro]
-pub fn muCMZIssProtocol(input: TokenStream) -> TokenStream {
-    protocol_macro(input, true, false, true)
 }

+ 14 - 0
cmz_derive/Cargo.toml

@@ -0,0 +1,14 @@
+[package]
+name = "cmz_derive"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+cmz_core = { path = "../cmz_core" }
+syn = { version = "2.0", features = ["extra-traits", "visit-mut"] }
+quote = "1.0"
+darling = "0.20"
+proc-macro2 = "1.0"

+ 307 - 0
cmz_derive/src/lib.rs

@@ -0,0 +1,307 @@
+// We want the macros like CMZ14Protocol to be camel case
+#![allow(non_snake_case)]
+
+/*! The implementation of the CMZCred derive and CMZ protocol macros.
+
+This derive should not be explicitly used by a programmer using a CMZ
+credential.  Instead, a CMZ credential should be declared with the
+
+`CMZ!{ Name: attr1, attr2, attr3 }`
+
+macro.  That macro will internally expand to a struct annotated with
+this CMZCred derive.  This derive will output the implementation of
+the CMZCredential trait for the declared credential.
+
+*/
+
+use cmz_core::{cmz_core, ProtoSpec};
+use darling::FromDeriveInput;
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{
+    parse_macro_input, Data, DataStruct, DeriveInput, Fields, FieldsNamed, Ident, Visibility,
+};
+
+fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStream {
+    // Ensure that CMZCred is derived on a struct and not something else
+    // (like an enum)
+    let Data::Struct(DataStruct {
+        struct_token: _,
+        fields:
+            Fields::Named(FieldsNamed {
+                brace_token: _,
+                ref named,
+            }),
+        semi_token: _,
+    }) = ast.data
+    else {
+        panic!("CMZCred derived on a non-struct");
+    };
+    // attrs and idents are each vectors of the names of the attributes
+    // of the credential (not including the MAC and any non-public
+    // fields).  attrs stores the names as Strings, while idents stores
+    // them as Idents.
+    let mut attrs = Vec::<String>::new();
+    let mut idents = Vec::<&Ident>::new();
+    for n in named {
+        let Some(ref ident) = n.ident else {
+            panic!("Missing attribute name in CMZCred");
+        };
+        let id_str = ident.to_string();
+        if let Visibility::Public(_) = n.vis {
+            if id_str != *"MAC" {
+                attrs.push(id_str);
+                idents.push(ident);
+            }
+        }
+    }
+    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);
+
+    // Output the CMZCredential trait implementation
+    let gen = quote! {
+        impl CMZCredential for #name {
+            type Scalar = <#group_ident as Group>::Scalar;
+            type Point = #group_ident;
+
+            fn attrs() -> Vec<&'static str> {
+                vec![
+                    #( #attrs, )*
+                ]
+            }
+
+            fn num_attrs() -> usize {
+                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, )*
+                    _ => panic!(#errmsg),
+                }
+            }
+
+            fn attr_mut(&mut self, attrname: &str) -> &mut Option<Self::Scalar> {
+                match attrname {
+                    #( #attrs => &mut self.#idents, )*
+                    _ => panic!(#errmsg),
+                }
+            }
+
+            fn set_pubkey(&mut self, pubkey: &CMZPubkey<Self::Point>) -> &mut Self {
+                self.pubkey = pubkey.clone();
+                self
+            }
+
+            fn get_pubkey<'a> (&'a self) -> &'a CMZPubkey<Self::Point> {
+                &self.pubkey
+            }
+
+            fn set_privkey(&mut self, privkey: &CMZPrivkey<Self::Point>) -> &mut Self {
+                self.pubkey = cmz_privkey_to_pubkey(&privkey);
+                self.privkey = privkey.clone();
+                self
+            }
+
+            fn get_privkey<'a> (&'a self) -> &'a CMZPrivkey<Self::Point> {
+                &self.privkey
+            }
+
+            fn privkey_x(&self, name: &str) -> Self::Scalar {
+                self.privkey.x[Self::attr_num(name)]
+            }
+
+            fn pubkey_X(&self, name: &str) -> Self::Point {
+                self.pubkey.X[Self::attr_num(name)]
+            }
+
+            fn gen_keys(rng: &mut impl RngCore, muCMZ: bool) ->
+                    (CMZPrivkey<Self::Point>, CMZPubkey<Self::Point>) {
+                // Generate (num_attrs + 2) random scalars as the
+                // private key
+                let x0 = <Self::Scalar as ff::Field>::random(&mut *rng);
+                let xr = <Self::Scalar as ff::Field>::random(&mut *rng);
+                let x: Vec<Self::Scalar> = (0..Self::num_attrs())
+                    .map(|_| <Self::Scalar as ff::Field>::random(&mut *rng))
+                    .collect();
+                let privkey = CMZPrivkey { muCMZ, x0, xr, x };
+
+                // Convert the private key to a public key
+                let pubkey = cmz_privkey_to_pubkey(&privkey);
+
+                (privkey, pubkey)
+            }
+
+            fn compute_MAC_coeff(&self, privkey: &CMZPrivkey<Self::Point>) -> Result<Self::Scalar, ()> {
+                if privkey.x.len() != Self::num_attrs() {
+                    return Err(());
+                }
+                let mut coeff = privkey.x0;
+                if privkey.muCMZ {
+                    coeff += privkey.xr;
+                }
+                for field in Self::attrs().iter() {
+                    let attr_val = self.attr(field).ok_or(())?;
+                    coeff += attr_val * privkey.x[Self::attr_num(field)];
+                }
+                Ok(coeff)
+            }
+
+            fn create_MAC(&mut self, rng: &mut impl RngCore, privkey: &CMZPrivkey<Self::Point>) -> Result<(),()> {
+                let coeff = self.compute_MAC_coeff(privkey)?;
+                self.MAC.P = <Self::Point as group::Group>::random(&mut *rng);
+                self.MAC.Q = coeff * self.MAC.P;
+                Ok(())
+            }
+
+            fn verify_MAC(&self, privkey: &CMZPrivkey<Self::Point>) ->
+                    Result<(),()> {
+                let coeff = self.compute_MAC_coeff(privkey)?;
+                if !bool::from(self.MAC.P.is_identity()) && coeff * self.MAC.P == self.MAC.Q {
+                    Ok(())
+                } else {
+                    Err(())
+                }
+            }
+
+            fn fake_MAC(&mut self, rng: &mut impl RngCore) {
+                self.MAC.P = <Self::Point as group::Group>::random(&mut *rng);
+                self.MAC.Q = <Self::Point as group::Group>::random(&mut *rng);
+            }
+
+        }
+    };
+    gen.into()
+}
+
+#[derive(FromDeriveInput)]
+#[darling(attributes(cmzcred_group))]
+struct GroupIdent {
+    group: Ident,
+}
+
+#[proc_macro_derive(CMZCred, attributes(cmzcred_group))]
+pub fn cmzcred_derive(input: TokenStream) -> TokenStream {
+    // Construct a representation of Rust code as a syntax tree
+    // that we can manipulate
+    let ast: DeriveInput = syn::parse(input).unwrap();
+
+    // Get the cmzcred_group(group = G) attribute
+    let group_ident = GroupIdent::from_derive_input(&ast)
+        .expect("missing group parameter to cmzcred_group attribute");
+
+    // Build the trait implementation
+    impl_cmzcred_derive(&ast, &group_ident.group)
+}
+
+/** The CMZ Protocol creation macros.
+
+   The format is:
+
+   let proto = muCMZProtocol! { proto_name<param1,param2>,
+     [ A: Cred {
+         attr1: H,
+         attr2: R,
+       },
+       B?: Cred2 {
+         attr3: H,
+         attr4: I,
+       } ],
+     C: Cred3 {
+       attr5: J,
+       attr6: R,
+       attr7: H,
+       attr8: I,
+       attr9: S,
+     },
+     A.attr1 == B.attr3 + param1,
+     A.attr1 == C.attr7,
+   };
+
+   The parameters are:
+   - an identifier for the protocol
+   - an optional angle-bracketed list of parameters (identifiers)
+   - a list of zero or more specifications for credentials that will be shown
+   - a list of zero or more specifications for credentials that will be issued
+   - zero or more statements relating the attributes in the credentials
+
+   Each credential specification list can be:
+   - empty
+   - a single credential specification
+   - a square-bracketed list of credential specifications
+
+   Each credential specification is:
+   - an identifier for the credential
+   - for a shown (not issued) credential, an optional "?".  If present,
+     the validity of this credential will _not_ be proved by default,
+     and must be explicit (perhaps in only some branches of an "OR"
+     statement) in the statements; if absent (the default), the validity
+     of the shown credential will always be proven
+   - a type for the credential, previously defined with the CMZ! macro
+   - a braced list of the attributes of the credential (as defined in
+     the CMZ! macro), annotated with the attribute specification
+
+   An attribute specification for a credential to be shown is one of:
+   - H (hide)
+   - R (reveal)
+   - I (implicit)
+
+   An attribute specification for a credential to be issued is one of:
+   - H (hide)
+   - R (reveal)
+   - I (implicit)
+   - S (set by issuer)
+   - J (joint creation)
+
+  There are six variants of the `CMZProtocol` macro.  The ones starting
+  with "CMZ14" create protocol implementations using the original CMZ14
+  issuing protocol.  The ones starting with "muCMZ" using the more
+  efficient µCMZ protocol.  The ones with "Cli" only create the code
+  for the client side of the protocol.  The ones with "Iss" only create
+  the code for the issuer side of the protocol.  (The ones without
+  either create the code for both sides of the protocol.)
+*/
+#[proc_macro]
+pub fn CMZ14Protocol(input: TokenStream) -> TokenStream {
+    let proto_spec = parse_macro_input!(input as ProtoSpec);
+    cmz_core(&proto_spec, false, true, true).into()
+}
+
+#[proc_macro]
+pub fn CMZ14CliProtocol(input: TokenStream) -> TokenStream {
+    let proto_spec = parse_macro_input!(input as ProtoSpec);
+    cmz_core(&proto_spec, false, true, false).into()
+}
+
+#[proc_macro]
+pub fn CMZ14IssProtocol(input: TokenStream) -> TokenStream {
+    let proto_spec = parse_macro_input!(input as ProtoSpec);
+    cmz_core(&proto_spec, false, false, true).into()
+}
+
+#[proc_macro]
+pub fn muCMZProtocol(input: TokenStream) -> TokenStream {
+    let proto_spec = parse_macro_input!(input as ProtoSpec);
+    cmz_core(&proto_spec, true, true, true).into()
+}
+
+#[proc_macro]
+pub fn muCMZCliProtocol(input: TokenStream) -> TokenStream {
+    let proto_spec = parse_macro_input!(input as ProtoSpec);
+    cmz_core(&proto_spec, true, true, false).into()
+}
+
+#[proc_macro]
+pub fn muCMZIssProtocol(input: TokenStream) -> TokenStream {
+    let proto_spec = parse_macro_input!(input as ProtoSpec);
+    cmz_core(&proto_spec, true, false, true).into()
+}

+ 1 - 1
src/lib.rs

@@ -2,7 +2,7 @@
 // lowercase letters
 #![allow(non_snake_case)]
 
-pub use cmzcred_derive::*;
+pub use cmz_derive::*;
 use core::any::Any;
 use ff::{Field, PrimeField};
 use generic_static::StaticTypeMap;