noah_crypto/basic/
elgamal.rs1use noah_algebra::ristretto::RistrettoPoint;
2use noah_algebra::{
3 hash::{Hash, Hasher},
4 prelude::*,
5};
6
7#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct ElGamalEncKey<G>(pub G);
10
11#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
12pub struct ElGamalDecKey<S>(pub(crate) S);
14
15#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct ElGamalCiphertext<G> {
18 pub e1: G,
20 pub e2: G,
22}
23
24impl Hash for ElGamalEncKey<RistrettoPoint> {
25 fn hash<H: Hasher>(&self, state: &mut H) {
26 self.0.to_compressed_bytes().as_slice().hash(state);
27 }
28}
29
30impl NoahFromToBytes for ElGamalCiphertext<RistrettoPoint> {
31 fn noah_to_bytes(&self) -> Vec<u8> {
32 let mut v = vec![];
33 v.extend_from_slice(self.e1.to_compressed_bytes().as_slice());
34 v.extend_from_slice(self.e2.to_compressed_bytes().as_slice());
35 v
36 }
37 fn noah_from_bytes(bytes: &[u8]) -> Result<Self> {
38 let e1 = RistrettoPoint::from_compressed_bytes(&bytes[0..RistrettoPoint::COMPRESSED_LEN])
39 .c(d!(NoahError::DeserializationError))?;
40 let e2 = RistrettoPoint::from_compressed_bytes(&bytes[RistrettoPoint::COMPRESSED_LEN..])
41 .c(d!(NoahError::DeserializationError))?;
42 Ok(ElGamalCiphertext { e1, e2 })
43 }
44}
45
46pub fn elgamal_key_gen<R: CryptoRng + RngCore, G: Group>(
48 prng: &mut R,
49) -> (ElGamalDecKey<G::ScalarType>, ElGamalEncKey<G>) {
50 let base = G::get_base();
51 let secret_key = ElGamalDecKey(G::ScalarType::random(prng));
52 let public_key = ElGamalEncKey(base.mul(&secret_key.0));
53 (secret_key, public_key)
54}
55
56pub fn elgamal_encrypt<G: Group>(
58 m: &G::ScalarType,
59 r: &G::ScalarType,
60 pub_key: &ElGamalEncKey<G>,
61) -> ElGamalCiphertext<G> {
62 let base = G::get_base();
63 let e1 = base.mul(r);
64 let e2 = base.mul(m).add(&(pub_key.0).mul(r));
65
66 ElGamalCiphertext::<G> { e1, e2 }
67}
68
69pub fn elgamal_verify<G: Group>(
71 m: &G::ScalarType,
72 ctext: &ElGamalCiphertext<G>,
73 sec_key: &ElGamalDecKey<G::ScalarType>,
74) -> Result<()> {
75 let base = G::get_base();
76 if base.mul(m).add(&ctext.e1.mul(&sec_key.0)) == ctext.e2 {
77 Ok(())
78 } else {
79 Err(eg!(NoahError::ElGamalVerificationError))
80 }
81}
82
83pub fn elgamal_partial_decrypt<G: Group>(
85 ctext: &ElGamalCiphertext<G>,
86 sec_key: &ElGamalDecKey<G::ScalarType>,
87) -> G {
88 ctext.e2.sub(&ctext.e1.mul(&sec_key.0))
89}
90
91#[cfg(test)]
92mod elgamal_test {
93 use noah_algebra::bls12_381::BLSGt;
94 use noah_algebra::bls12_381::BLSG1;
95 use noah_algebra::bls12_381::BLSG2;
96 use noah_algebra::prelude::*;
97 use noah_algebra::ristretto::RistrettoPoint;
98
99 fn verification<G: Group>() {
100 let mut prng = test_rng();
101
102 let (secret_key, public_key) = super::elgamal_key_gen::<_, G>(&mut prng);
103
104 let m = G::ScalarType::from(100u32);
105 let r = G::ScalarType::random(&mut prng);
106 let ctext = super::elgamal_encrypt::<G>(&m, &r, &public_key);
107 pnk!(super::elgamal_verify::<G>(&m, &ctext, &secret_key));
108
109 let wrong_m = G::ScalarType::from(99u32);
110 let err = super::elgamal_verify(&wrong_m, &ctext, &secret_key)
111 .err()
112 .unwrap();
113 msg_eq!(NoahError::ElGamalVerificationError, err);
114 }
115
116 fn decryption<G: Group>() {
117 let mut prng = test_rng();
118 let (secret_key, public_key) = super::elgamal_key_gen::<_, G>(&mut prng);
119
120 let mu32 = 100u32;
121 let m = G::ScalarType::from(mu32);
122 let r = G::ScalarType::random(&mut prng);
123 let ctext = super::elgamal_encrypt(&m, &r, &public_key);
124 pnk!(super::elgamal_verify(&m, &ctext, &secret_key));
125
126 let m = G::ScalarType::from(u64::MAX);
127 let ctext = super::elgamal_encrypt(&m, &r, &public_key);
128 pnk!(super::elgamal_verify(&m, &ctext, &secret_key));
129 }
130
131 #[test]
132 fn verify() {
133 verification::<RistrettoPoint>();
134 verification::<BLSG1>();
135 verification::<BLSG2>();
136 verification::<BLSGt>();
137 }
138
139 #[test]
140 fn decrypt() {
141 decryption::<RistrettoPoint>();
142 decryption::<BLSG1>();
143 decryption::<BLSG2>();
144 decryption::<BLSGt>();
145 }
146}