From 59ea57ef9a8aba514f8d76f2dc73e2ed6a88f219 Mon Sep 17 00:00:00 2001 From: Joey Yandle Date: Mon, 9 Dec 2024 12:54:23 -0500 Subject: [PATCH] add elgamal encryption to utils; add pvss module; check that the secp256k1 group order is prime, and also (order - 1)/2 which is sadly not --- Cargo.toml | 2 ++ src/lib.rs | 2 ++ src/pvss.rs | 38 ++++++++++++++++++++++++++++++++++++++ src/util.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 src/pvss.rs diff --git a/Cargo.toml b/Cargo.toml index af374bc5..a231ed8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,8 @@ aes-gcm = "0.10" bs58 = "0.5" hashbrown = { version = "0.14", features = ["serde"] } hex = "0.4.3" +is_prime = { git = "https://github.com/xoloki/is_prime.git" } +num-bigint = "0.4" num-traits = "0.2" polynomial = { version = "0.2.5", features = ["serde"] } primitive-types = "0.12" diff --git a/src/lib.rs b/src/lib.rs index 12f846d8..3d622e42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ #![deny(missing_docs)] #![doc = include_str!("../README.md")] +/// PVSS +pub mod PVSS; /// Types which are common to both v1 and v2 #[allow(clippy::op_ref)] pub mod common; diff --git a/src/pvss.rs b/src/pvss.rs new file mode 100644 index 00000000..1e93cf28 --- /dev/null +++ b/src/pvss.rs @@ -0,0 +1,38 @@ +use is_prime; +use rand_core::{CryptoRng, RngCore}; + +use crate::curve::scalar::Scalar; + +/// A publicly verifiable secret share algorithm +pub struct PVSS { + R: Vec, + c: Scalar, +} + +impl PVSS { + /// Construct a random polynomial of the passed degree `n` + pub fn new(rng: &mut RNG) -> PVSS { + let R = Vec::new(); + let c = Scalar::random(rng); + PVSS { R, c } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::curve::{point::Point, scalar::Scalar}; + + use num_bigint::BigUint; + + #[test] + fn is_p_minus_1_over_2_prime() { + let p = BigUint::from_bytes_be(crate::curve::point::N.as_slice()); + + assert!(is_prime::is_biguint_prime(p.clone())); + + let p12 = (p - 1u32) / 2u32; + + assert!(is_prime::is_biguint_prime(p12.clone())); + } +} diff --git a/src/util.rs b/src/util.rs index 402e2e7b..974cffd4 100644 --- a/src/util.rs +++ b/src/util.rs @@ -82,6 +82,34 @@ pub fn decrypt(key: &[u8; 32], data: &[u8]) -> Result, AesGcmError> { cipher.decrypt(nonce, cipher_vec.as_ref()) } +/// An El-Gamal encryption packet +struct ElGamal { + c1: Scalar, + c2: Scalar, +} + +/// encrypt using a scalar based El-Gamal +pub fn encrypt_elgamal( + generator: Scalar, + message: Scalar, + public_key: Scalar, + rng: &mut RNG, +) -> Result { + // ephemeral key + let k = Scalar::random(rng); + + let c1 = generator ^ k; + let c2 = (message.invert()) * (public_key ^ k); + + Ok(ElGamal { c1, c2 }) +} + +/// encrypt using a scalar based El-Gamal +pub fn decrypt_elgamal(elgamal: &ElGamal, private_key: Scalar) -> Result { + let message = (elgamal.c1 ^ private_key) * (elgamal.c2.invert()); + Ok(message) +} + /// Creates a new random number generator. pub fn create_rng() -> impl RngCore + CryptoRng { OsRng @@ -94,7 +122,7 @@ mod test { #[test] #[allow(non_snake_case)] - fn test_shared_secret() { + fn shared_secret() { let mut rng = create_rng(); let x = Scalar::random(&mut rng); @@ -111,7 +139,7 @@ mod test { #[test] #[allow(non_snake_case)] - fn test_encrypt_decrypt() { + fn encrypt_decrypt() { let mut rng = create_rng(); let msg = "It was many and many a year ago, in a kingdom by the sea..."; @@ -129,4 +157,21 @@ mod test { assert_eq!(msg.as_bytes(), &plain); } + + #[test] + fn elgamal() { + let mut rng = create_rng(); + let generator = Scalar::random(&mut rng); + let private_key = Scalar::random(&mut rng); + let public_key = generator ^ private_key; + let message = Scalar::random(&mut rng); + + let elgamal = encrypt_elgamal(generator, message, public_key, &mut rng).unwrap(); + let decrypted_message = decrypt_elgamal(&elgamal, private_key).unwrap(); + + assert_eq!(message, decrypted_message); + } + + #[test] + fn pvss() {} }