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)
             }
+
+            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()

+ 6 - 0
src/lib.rs

@@ -321,6 +321,12 @@ where
         slf.set_pubkey(pubkey);
         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.

+ 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 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
     // wallet and sends it to the client.
     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)
 
     // client actions
@@ -141,6 +150,8 @@ fn test_wallet() -> Result<(), CMZError> {
     let recvreply = wallet_spend::Reply::try_from(&replybytes[..]).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
     // and issue must agree on the params.
     let params = wallet_spend_with_fee::Params { fee: 5u128.into() };
@@ -152,7 +163,7 @@ fn test_wallet() -> Result<(), CMZError> {
 
     let (request_fee, state_fee) =
         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
     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 W_issued_fee = state_fee.finalize(recvreply_fee).unwrap();
 
+    W_issued_fee.verify_MAC(&wallet_priv).unwrap();
+
     Ok(())
 }