Browse Source

sdk/crypto: Add "_unsafe" suffix to ElGamalEncryptedNote functions

The reasoning is explained in the rustdoc for those functions.
parazyd 2 years ago
parent
commit
23f2bbeac9

+ 1 - 1
bin/drk/src/dao.rs

@@ -799,7 +799,7 @@ impl Drk {
             for vote in new_dao_votes {
                 for dao in &daos {
                     // TODO: we shouldn't decrypt with all DAOs here
-                    let note = vote.0.note.decrypt(&dao.secret_key);
+                    let note = vote.0.note.decrypt_unsafe(&dao.secret_key);
                     eprintln!("Managed to decrypt DAO proposal vote note");
                     let daos_proposals = self.get_dao_proposals(dao.id).await?;
                     let mut proposal_id = None;

+ 2 - 2
src/contract/dao/src/client/auth_xfer.rs

@@ -72,7 +72,7 @@ impl DaoAuthMoneyTransferCall {
                 coin_attrs.blind.inner(),
             ];
             let enc_note =
-                ElGamalEncryptedNote::encrypt(note, &ephem_secret, &coin_attrs.public_key);
+                ElGamalEncryptedNote::encrypt_unsafe(note, &ephem_secret, &coin_attrs.public_key);
 
             let prover_witnesses = vec![
                 Witness::EcNiPoint(Value::known(coin_attrs.public_key.inner())),
@@ -118,7 +118,7 @@ impl DaoAuthMoneyTransferCall {
             self.dao_coin_attrs.blind.inner(),
         ];
         let dao_change_attrs =
-            ElGamalEncryptedNote::encrypt(note, &ephem_secret, &self.dao.public_key);
+            ElGamalEncryptedNote::encrypt_unsafe(note, &ephem_secret, &self.dao.public_key);
 
         let params = DaoAuthMoneyTransferParams { enc_attrs, dao_change_attrs };
 

+ 2 - 1
src/contract/dao/src/client/vote.rs

@@ -249,7 +249,8 @@ impl DaoVoteCall {
         let proposal_bulla = self.proposal.to_bulla();
 
         let note = [vote_option, yes_vote_blind.inner(), all_vote_value_fp, all_vote_blind.inner()];
-        let enc_note = ElGamalEncryptedNote::encrypt(note, &ephem_secret, &self.dao_keypair.public);
+        let enc_note =
+            ElGamalEncryptedNote::encrypt_unsafe(note, &ephem_secret, &self.dao_keypair.public);
 
         let public_inputs = vec![
             token_commit,

+ 3 - 3
src/contract/dao/tests/integration.rs

@@ -392,9 +392,9 @@ fn integration_test() -> Result<()> {
         }
 
         // Gather and decrypt all vote notes
-        let vote_note_1 = alice_vote_params.note.decrypt(&dao_keypair.secret);
-        let vote_note_2 = bob_vote_params.note.decrypt(&dao_keypair.secret);
-        let vote_note_3 = charlie_vote_params.note.decrypt(&dao_keypair.secret);
+        let vote_note_1 = alice_vote_params.note.decrypt_unsafe(&dao_keypair.secret);
+        let vote_note_2 = bob_vote_params.note.decrypt_unsafe(&dao_keypair.secret);
+        let vote_note_3 = charlie_vote_params.note.decrypt_unsafe(&dao_keypair.secret);
 
         // Count the votes
         let mut total_yes_vote_value = 0;

+ 24 - 5
src/sdk/src/crypto/note.rs

@@ -81,15 +81,26 @@ impl AeadEncryptedNote {
     }
 }
 
-/// An encrypted note using an ElGamal scheme verifiable in ZK
+/// An encrypted note using an ElGamal scheme verifiable in ZK.
+///
+/// **WARNING:**
+/// Without ZK, there is no authentication of the ciphertexts so these should
+/// not be used without a corresponding ZK proof.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
 pub struct ElGamalEncryptedNote<const N: usize> {
+    /// The values encrypted with the derived shared secret using Diffie-Hellman
     pub encrypted_values: [pallas::Base; N],
+    /// The ephemeral public key used for Diffie-Hellman key derivation
     pub ephem_public: PublicKey,
 }
 
 impl<const N: usize> ElGamalEncryptedNote<N> {
-    pub fn encrypt(
+    /// Encrypt given values to the given `PublicKey` using a `SecretKey` for Diffie-Hellman
+    ///
+    /// Note that this does not do any message authentication.
+    /// This means that alterations of the ciphertexts lead to the same alterations
+    /// on the plaintexts.
+    pub fn encrypt_unsafe(
         values: [pallas::Base; N],
         ephem_secret: &SecretKey,
         public: &PublicKey,
@@ -99,11 +110,13 @@ impl<const N: usize> ElGamalEncryptedNote<N> {
         let (ss_x, ss_y) = PublicKey::from(public.inner() * fp_mod_fv(ephem_secret.inner())).xy();
         let shared_secret = poseidon_hash([ss_x, ss_y]);
 
+        // Derive the blinds using the shared secret and incremental nonces
         let mut blinds = [pallas::Base::ZERO; N];
         for (i, item) in blinds.iter_mut().enumerate().take(N) {
             *item = poseidon_hash([shared_secret, pallas::Base::from(i as u64 + 1)]);
         }
 
+        // Encrypt the values
         let mut encrypted_values = [pallas::Base::ZERO; N];
         for i in 0..N {
             encrypted_values[i] = values[i] + blinds[i];
@@ -112,7 +125,13 @@ impl<const N: usize> ElGamalEncryptedNote<N> {
         Self { encrypted_values, ephem_public }
     }
 
-    pub fn decrypt(&self, secret: &SecretKey) -> [pallas::Base; N] {
+    /// Decrypt the `ElGamalEncryptedNote` using a `SecretKey` for shared secret derivation
+    /// using Diffie-Hellman
+    ///
+    /// Note that this does not do any message authentication.
+    /// This means that alterations of the ciphertexts lead to the same alterations
+    /// on the plaintexts.
+    pub fn decrypt_unsafe(&self, secret: &SecretKey) -> [pallas::Base; N] {
         // Derive shared secret using DH
         let (ss_x, ss_y) =
             PublicKey::from(self.ephem_public.inner() * fp_mod_fv(secret.inner())).xy();
@@ -162,9 +181,9 @@ mod tests {
         let ephem_secret = SecretKey::random(&mut OsRng);
 
         let encrypted_note =
-            ElGamalEncryptedNote::encrypt(plain_values, &ephem_secret, &keypair.public);
+            ElGamalEncryptedNote::encrypt_unsafe(plain_values, &ephem_secret, &keypair.public);
 
-        let decrypted_values = encrypted_note.decrypt(&keypair.secret);
+        let decrypted_values = encrypted_note.decrypt_unsafe(&keypair.secret);
 
         assert_eq!(plain_values, decrypted_values);
     }