Browse Source

Add a verify_MAC function to credentials

This is mainly useful for debugging, since the client will not have the
private key and the issuer will typically not have the complete
credential.

Instrument tests/wallet.rs to check the MAC on each issued credential to
ensure they pass.
Ian Goldberg 5 months ago
parent
commit
96aa50de5e
3 changed files with 37 additions and 1 deletions
  1. 17 0
      cmzcred_derive/src/lib.rs
  2. 6 0
      src/lib.rs
  3. 14 1
      tests/wallet.rs

+ 17 - 0
cmzcred_derive/src/lib.rs

@@ -141,6 +141,23 @@ fn impl_cmzcred_derive(ast: &syn::DeriveInput, group_ident: &Ident) -> TokenStre
 
 
                 (privkey, pubkey)
                 (privkey, pubkey)
             }
             }
+
+            fn verify_MAC(&self, privkey: &CMZPrivkey<Self::Point>) ->
+                    Result<(),()> {
+                if privkey.x.len() != Self::num_attrs() {
+                    return Err(());
+                }
+                let mut coeff = privkey.x0;
+                for field in Self::attrs().iter() {
+                    let attr_val = self.attr(field).ok_or(())?;
+                    coeff += attr_val * privkey.x[Self::attr_num(field)];
+                }
+                if coeff * self.MAC.P == self.MAC.Q {
+                    Ok(())
+                } else {
+                    Err(())
+                }
+            }
         }
         }
     };
     };
     gen.into()
     gen.into()

+ 6 - 0
src/lib.rs

@@ -321,6 +321,12 @@ where
         slf.set_pubkey(pubkey);
         slf.set_pubkey(pubkey);
         slf
         slf
     }
     }
+
+    /// Verify the MAC in this credential, given the private key.  This
+    /// is mainly useful for debugging, since the client will not have
+    /// the private key and the issuer will typically not have the
+    /// complete credential.
+    fn verify_MAC(&self, privkey: &CMZPrivkey<Self::Point>) -> Result<(), ()>;
 }
 }
 
 
 /** The CMZ macro for declaring CMZ credentials.
 /** The CMZ macro for declaring CMZ credentials.

+ 14 - 1
tests/wallet.rs

@@ -108,10 +108,19 @@ fn test_wallet() -> Result<(), CMZError> {
     let ebook_item = issue_item(&mut rng, 100, 2995, &item_priv, &item_pub)?;
     let ebook_item = issue_item(&mut rng, 100, 2995, &item_priv, &item_pub)?;
     let album_item = issue_item(&mut rng, 200, 995, &item_priv, &item_pub)?;
     let album_item = issue_item(&mut rng, 200, 995, &item_priv, &item_pub)?;
 
 
+    // The verify_MAC function is only usable for debugging, since the
+    // client will not have the private key and the issuer will
+    // typically not have the complete credential.  But we'll use it
+    // here to check that the credentials we get back are correct.
+    ebook_item.verify_MAC(&item_priv).unwrap();
+    album_item.verify_MAC(&item_priv).unwrap();
+
     // In exchange for out of band funds, the issuer generates a loaded
     // In exchange for out of band funds, the issuer generates a loaded
     // wallet and sends it to the client.
     // wallet and sends it to the client.
     let initial_wallet = issue_wallet(&mut rng, 10000, &wallet_priv, &wallet_pub)?;
     let initial_wallet = issue_wallet(&mut rng, 10000, &wallet_priv, &wallet_pub)?;
 
 
+    initial_wallet.verify_MAC(&wallet_priv).unwrap();
+
     // Buy an item (no fee version)
     // Buy an item (no fee version)
 
 
     // client actions
     // client actions
@@ -141,6 +150,8 @@ fn test_wallet() -> Result<(), CMZError> {
     let recvreply = wallet_spend::Reply::try_from(&replybytes[..]).unwrap();
     let recvreply = wallet_spend::Reply::try_from(&replybytes[..]).unwrap();
     let W_issued = state.finalize(recvreply).unwrap();
     let W_issued = state.finalize(recvreply).unwrap();
 
 
+    W_issued.verify_MAC(&wallet_priv).unwrap();
+
     // The version of the protocol parameterized by a fee.  The client
     // The version of the protocol parameterized by a fee.  The client
     // and issue must agree on the params.
     // and issue must agree on the params.
     let params = wallet_spend_with_fee::Params { fee: 5u128.into() };
     let params = wallet_spend_with_fee::Params { fee: 5u128.into() };
@@ -152,7 +163,7 @@ fn test_wallet() -> Result<(), CMZError> {
 
 
     let (request_fee, state_fee) =
     let (request_fee, state_fee) =
         wallet_spend_with_fee::prepare(&mut rng, &W_issued, &album_item, N_fee, &params)?;
         wallet_spend_with_fee::prepare(&mut rng, &W_issued, &album_item, N_fee, &params)?;
-    let reqbytes_fee = request.as_bytes();
+    let reqbytes_fee = request_fee.as_bytes();
 
 
     // issuer actions
     // issuer actions
     let recvreq_fee = wallet_spend_with_fee::Request::try_from(&reqbytes_fee[..]).unwrap();
     let recvreq_fee = wallet_spend_with_fee::Request::try_from(&reqbytes_fee[..]).unwrap();
@@ -175,5 +186,7 @@ fn test_wallet() -> Result<(), CMZError> {
     let recvreply_fee = wallet_spend_with_fee::Reply::try_from(&replybytes_fee[..]).unwrap();
     let recvreply_fee = wallet_spend_with_fee::Reply::try_from(&replybytes_fee[..]).unwrap();
     let W_issued_fee = state_fee.finalize(recvreply_fee).unwrap();
     let W_issued_fee = state_fee.finalize(recvreply_fee).unwrap();
 
 
+    W_issued_fee.verify_MAC(&wallet_priv).unwrap();
+
     Ok(())
     Ok(())
 }
 }