Browse Source

Enable shown credentials in a protocol to only optionally have their validity proven

For shown credentials only (not issued credentials): a "?" after the
credential identifier in the ProtoSpec indicates that we want to only
optionally (for example, in an "OR" clause) show that this credential is
valid.  The default (no "?") means we should always show that the
credential is valid.
Ian Goldberg 5 months ago
parent
commit
ef94f40afd
1 changed files with 36 additions and 13 deletions
  1. 36 13
      cmzcred_derive/src/lib.rs

+ 36 - 13
cmzcred_derive/src/lib.rs

@@ -190,7 +190,7 @@ pub fn cmzcred_derive(input: TokenStream) -> TokenStream {
          attr1: H,
          attr2: R,
        },
-       B: Cred2 {
+       B?: Cred2 {
          attr3: H,
          attr4: I,
        } ],
@@ -219,6 +219,11 @@ pub fn cmzcred_derive(input: TokenStream) -> TokenStream {
 
    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
@@ -320,15 +325,28 @@ impl<ShowOrIssue: Parse> Parse for AttrSpec<ShowOrIssue> {
 
 // A specification of a credential, either to be shown or issued
 #[derive(Debug)]
-struct CredSpec<ShowOrIssue: Parse> {
+struct CredSpec<ShowOrIssue: Parse, const VALID_OPTIONAL: bool> {
     id: Ident,
     cred_type: Ident,
+    // For shown credentials only (not issued credentials): set to true
+    // if we want to only optionally (for example, in an "OR" clause)
+    // show that this credential is valid.  The default state of false
+    // means we should always show that the credential is valid.
+    valid_optional: bool,
     attrs: HashMap<Ident, ShowOrIssue>,
 }
 
-impl<ShowOrIssue: Parse + Copy> Parse for CredSpec<ShowOrIssue> {
+impl<ShowOrIssue: Parse + Copy, const VALID_OPTIONAL: bool> Parse
+    for CredSpec<ShowOrIssue, VALID_OPTIONAL>
+{
     fn parse(input: ParseStream) -> Result<Self> {
         let id: Ident = input.parse()?;
+        let valid_optional = if VALID_OPTIONAL && input.peek(Token![?]) {
+            input.parse::<Token![?]>()?;
+            true
+        } else {
+            false
+        };
         input.parse::<Token![:]>()?;
         let cred_type: Ident = input.parse()?;
         let content;
@@ -342,6 +360,7 @@ impl<ShowOrIssue: Parse + Copy> Parse for CredSpec<ShowOrIssue> {
         Ok(Self {
             id,
             cred_type,
+            valid_optional,
             attrs,
         })
     }
@@ -351,21 +370,25 @@ impl<ShowOrIssue: Parse + Copy> Parse for CredSpec<ShowOrIssue> {
 // credential specification, or a bracketed list of credential
 // specifications.  We need a newtype here and not just a Vec so that we
 // can implement the Parse trait for it.
-struct CredSpecVec<ShowOrIssue: Parse>(Vec<CredSpec<ShowOrIssue>>);
+struct CredSpecVec<ShowOrIssue: Parse, const VALID_OPTIONAL: bool>(
+    Vec<CredSpec<ShowOrIssue, VALID_OPTIONAL>>,
+);
 
-impl<ShowOrIssue: Parse + Copy> Parse for CredSpecVec<ShowOrIssue> {
+impl<ShowOrIssue: Parse + Copy, const VALID_OPTIONAL: bool> Parse
+    for CredSpecVec<ShowOrIssue, VALID_OPTIONAL>
+{
     fn parse(input: ParseStream) -> Result<Self> {
-        let specvec: Vec<CredSpec<ShowOrIssue>> = if input.peek(Token![,]) {
+        let specvec: Vec<CredSpec<ShowOrIssue, VALID_OPTIONAL>> = if input.peek(Token![,]) {
             // The list is empty
             Vec::new()
         } else if input.peek(token::Bracket) {
             let content;
             bracketed!(content in input);
-            let specs: Punctuated<CredSpec<ShowOrIssue>, Token![,]> =
-                content.parse_terminated(CredSpec::<ShowOrIssue>::parse, Token![,])?;
+            let specs: Punctuated<CredSpec<ShowOrIssue, VALID_OPTIONAL>, Token![,]> = content
+                .parse_terminated(CredSpec::<ShowOrIssue, VALID_OPTIONAL>::parse, Token![,])?;
             specs.into_iter().collect()
         } else {
-            let spec: CredSpec<ShowOrIssue> = input.parse()?;
+            let spec: CredSpec<ShowOrIssue, VALID_OPTIONAL> = input.parse()?;
             vec![spec]
         };
 
@@ -378,8 +401,8 @@ impl<ShowOrIssue: Parse + Copy> Parse for CredSpecVec<ShowOrIssue> {
 struct ProtoSpec {
     proto_name: Ident,
     params: Vec<Ident>,
-    show_creds: Vec<CredSpec<ShowSpec>>,
-    issue_creds: Vec<CredSpec<IssueSpec>>,
+    show_creds: Vec<CredSpec<ShowSpec, true>>,
+    issue_creds: Vec<CredSpec<IssueSpec, false>>,
     statements: Vec<Expr>,
 }
 
@@ -406,9 +429,9 @@ impl Parse for ProtoSpec {
             input.parse::<Token![>]>()?;
         }
         input.parse::<Token![,]>()?;
-        let showvec: CredSpecVec<ShowSpec> = input.parse()?;
+        let showvec: CredSpecVec<ShowSpec, true> = input.parse()?;
         input.parse::<Token![,]>()?;
-        let issuevec: CredSpecVec<IssueSpec> = input.parse()?;
+        let issuevec: CredSpecVec<IssueSpec, false> = input.parse()?;
         input.parse::<Token![,]>()?;
         let statementpunc: Punctuated<Expr, Token![,]> =
             input.parse_terminated(Expr::parse, Token![,])?;