瀏覽代碼

sdk/note: ElGamal encrypt()

parazyd 3 年之前
父節點
當前提交
0b5c2393e1
共有 1 個文件被更改,包括 50 次插入1 次删除
  1. 50 1
      src/sdk/src/crypto/note.rs

+ 50 - 1
src/sdk/src/crypto/note.rs

@@ -18,9 +18,11 @@
 
 use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, KeyInit};
 use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
+use halo2_proofs::arithmetic::Field;
+use pasta_curves::{group::Group, pallas};
 use rand_core::{CryptoRng, RngCore};
 
-use super::{diffie_hellman, PublicKey, SecretKey};
+use super::{diffie_hellman, poseidon_hash, util::mod_r_p, PublicKey, SecretKey};
 use crate::error::ContractError;
 
 /// AEAD tag length in bytes
@@ -77,6 +79,42 @@ impl AeadEncryptedNote {
     }
 }
 
+/// An encrypted note using an ElGamal scheme verifiable in ZK
+pub struct ElGamalEncryptedNote<const N: usize> {
+    pub encrypted_values: [pallas::Base; N],
+}
+
+impl<const N: usize> ElGamalEncryptedNote<N> {
+    pub fn encrypt(
+        values: [pallas::Base; N],
+        public: &PublicKey,
+        rng: &mut (impl CryptoRng + RngCore),
+    ) -> Result<Self, ContractError> {
+        // Derive shared secret using DH
+        let ephem_secret = mod_r_p(pallas::Base::random(rng));
+        let (ephem_pub_x, ephem_pub_y) = PublicKey::from(public.inner() * ephem_secret).xy();
+        let shared_secret = poseidon_hash([ephem_pub_x, ephem_pub_y]);
+
+        let mut blinds = [pallas::Base::zero(); N];
+        for i in 0..N {
+            blinds[i] = poseidon_hash([shared_secret, pallas::Base::from(i as u64 + 1)]);
+        }
+
+        let mut encrypted_values = [pallas::Base::zero(); N];
+        for i in 0..N {
+            encrypted_values[i] = values[i] + blinds[i];
+        }
+
+        Ok(Self { encrypted_values })
+    }
+
+    pub fn decrypt(&self) -> Result<[pallas::Base; N], ContractError> {
+        let mut decrypted_values = [pallas::Base::zero(); N];
+
+        Ok(decrypted_values)
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -96,4 +134,15 @@ mod tests {
 
         assert_eq!(plaintext, plaintext2);
     }
+
+    #[test]
+    fn test_elgamal_note() {
+        const N_MSGS: usize = 10;
+
+        let plain_values = [pallas::Base::random(&mut OsRng); N_MSGS];
+        let keypair = Keypair::random(&mut OsRng);
+
+        let encrypted_note =
+            ElGamalEncryptedNote::encrypt(plain_values, &keypair.public, &mut OsRng).unwrap();
+    }
 }