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