arnaucube
arnaucube/plonky2-crypto-gadgetsPublic Self-hosted repository
plonky2-crypto-gadgets/ecgfp5/src/elgamal.rs
ecgfp5/src/elgamal.rsRaw
 1//! For LICENSE check out https://github.com/0xPARC/plonky2-crypto-gadgets/blob/main/LICENSE
 2
 3use num::bigint::BigUint;
 4use pod2::backends::plonky2::primitives::ec::curve::{GROUP_ORDER, Point};
 5
 6use crate::ECGFP5SecretKey;
 7
 8pub mod circuit;
 9
10/// ElGamal encryption on EcGFp5
11pub fn elgamal_encrypt(pk: Point, nonce: &BigUint, msg: Point) -> (Point, Point) {
12    assert!(nonce < &GROUP_ORDER);
13    let nonce_times_gen = nonce * Point::generator();
14    let nonce_times_pk = nonce * pk;
15    (nonce_times_gen, msg + nonce_times_pk)
16}
17
18/// ElGamal decryption on EcGFp5
19pub fn elgamal_decrypt(sk: ECGFP5SecretKey, ct: (Point, Point)) -> Point {
20    let nonce_times_pk = &sk.0 * ct.0;
21    ct.1 + nonce_times_pk.inverse()
22}
23
24#[cfg(test)]
25mod tests {
26    use num_bigint::RandBigInt;
27    use pod2::backends::plonky2::primitives::ec::curve::{GROUP_ORDER, Point};
28    use rand::rngs::OsRng;
29
30    use crate::elgamal::{ECGFP5SecretKey, elgamal_decrypt, elgamal_encrypt};
31
32    #[test]
33    fn round_trip_encryption() {
34        (0..100).for_each(|_| {
35            let sk = ECGFP5SecretKey::rand();
36            let pk = sk.public_key();
37
38            let msg = Point::new_rand_from_subgroup();
39            let nonce = OsRng.gen_biguint_below(&GROUP_ORDER);
40
41            let encrypted_msg = elgamal_encrypt(pk, &nonce, msg);
42            let decrypted_msg = elgamal_decrypt(sk, encrypted_msg);
43
44            assert_eq!(msg, decrypted_msg);
45        })
46    }
47}