Skip to content

Commit

Permalink
Merge pull request #38 from cryspen/jonas/sampling-context
Browse files Browse the repository at this point in the history
Introduce domain separation & panic on insufficient randomness for scalar sampling
  • Loading branch information
jschneider-bensch authored Oct 25, 2023
2 parents 71299ad + d934bc8 commit c6bf698
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 9 deletions.
15 changes: 11 additions & 4 deletions hacspec-scrambledb/elgamal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ use p256::{p256_point_mul, p256_point_mul_base, point_add, random_scalar, P256Po

use std::ops::Neg;

/// Domain separator for scalar sampling during key generation.
const DST_KEYGEN: &[u8] = b"ElGamal-KeyGeneration";
/// Domain separator for scalar sampling during encryption.
const DST_ENCRYPT: &[u8] = b"ElGamal-Encryption";
/// Domain separator for scalar sampling during ciphertext rerandomization.
const DST_RERANDOMIZE: &[u8] = b"ElGamal-Rerandomize";

/// An Elgamal encryption of a message `M` under public key `PK` is a pair of group elements `(c0, c1)` where
/// * `c0` is the group generator multiplied by a randomizer `r`
/// * `c1` is the result of multiplying the target public encryption key the same randomizer `r` and adding the result to the message `M` that is to be encrypted.
Expand Down Expand Up @@ -41,7 +48,7 @@ pub type EncryptionKey = P256Point;
/// To generate a pair of encryption and decryption keys, first the decryption key is drawn uniformly at random from the set of scalars.
/// Then the corresponding encryption key is generated by scalar multiplication of the group generator with the decryption key.
pub fn generate_keys(randomness: &mut Randomness) -> Result<(DecryptionKey, EncryptionKey), Error> {
let dec_key = random_scalar(randomness)?;
let dec_key = random_scalar(randomness, DST_KEYGEN)?;
let enc_key = p256_point_mul_base(dec_key)?;

Ok((dec_key, enc_key))
Expand All @@ -56,7 +63,7 @@ pub fn encrypt(
message: Plaintext,
randomness: &mut Randomness,
) -> Result<Ciphertext, Error> {
let randomizer = random_scalar(randomness)?;
let randomizer = random_scalar(randomness, DST_ENCRYPT)?;

let blinded_message = p256::point_add(message, p256::p256_point_mul(randomizer, enc_key)?)?;
let auxillary = p256::p256_point_mul_base(randomizer)?;
Expand All @@ -79,7 +86,7 @@ pub fn rerandomize(
ctx: Ciphertext,
randomness: &mut Randomness,
) -> Result<Ciphertext, Error> {
let randomizer = random_scalar(randomness)?;
let randomizer = random_scalar(randomness, DST_RERANDOMIZE)?;
let updated_blinding = p256_point_mul(randomizer, enc_key)?;
let updated_blinded_message = point_add(updated_blinding, ctx.1)?;

Expand Down Expand Up @@ -146,7 +153,7 @@ mod test {
}

fn random_element() -> Result<P256Point, Error> {
let rand = random_scalar(&mut Randomness::new(vec![0xab; 32])).unwrap();
let rand = random_scalar(&mut Randomness::new(vec![0xab; 32]), b"ElGamal-Test").unwrap();
let res = p256_point_mul_base(rand)?;

Ok(res)
Expand Down
6 changes: 5 additions & 1 deletion hacspec-scrambledb/oprf/src/coprf/coprf_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ use crate::{
Error,
};

/// Domain separator for scalar sampling during CoPRF key generation.
const DST_KEYGEN: &[u8] = b"CoPRF-KeyGeneration";

/// As blinding is performed by Elgamal encryption, the blinding public
/// key is an Elgamal encryption key.
pub type BlindingPublicKey = elgamal::EncryptionKey;
Expand Down Expand Up @@ -124,5 +127,6 @@ pub fn derive_key(context: &CoPRFEvaluatorContext, key_id: &[u8]) -> Result<CoPR

let random_bytes = sha256::hash(&key_material);

p256::random_scalar(&mut Randomness::new(random_bytes.to_vec())).map_err(|e| e.into())
p256::random_scalar(&mut Randomness::new(random_bytes.to_vec()), DST_KEYGEN)
.map_err(|e| e.into())
}
2 changes: 1 addition & 1 deletion hacspec-scrambledb/oprf/src/p256_sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn hash_to_group(bytes: &[u8], context_string: &[u8]) -> Result<P256Point, E
fn serialize_deserialize() {
use hacspec_lib::Randomness;
let p: P256Point = p256::p256_point_mul_base(
p256::random_scalar(&mut Randomness::new(vec![0xab; 32])).unwrap(),
p256::random_scalar(&mut Randomness::new(vec![0xab; 32]), b"OPRF-Test").unwrap(),
)
.unwrap();

Expand Down
19 changes: 16 additions & 3 deletions hacspec-scrambledb/p256/src/p256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,22 @@ pub struct P256FieldElement {}
#[nat_mod("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 32)]
pub struct P256Scalar {}

pub fn random_scalar(randomness: &mut Randomness) -> Result<P256Scalar, Error> {
// XXX: salt?
let dkp_prk = hkdf_extract(b"salt", randomness.bytes(32)?);
/// Generate a random P256 scalar using rejection sampling.
///
/// Inputs:
/// - `randomness`: Random bytes
/// - `dst`: Domain separation tag
///
/// Outputs:
/// - A random P256 scalar
///
/// Raises:
/// - `SamplingError`: If no valid scalar can be found within 256 sampling attempts
///
/// Panics:
/// - If the provided random bytes are insufficient
pub fn random_scalar(randomness: &mut Randomness, dst: &[u8]) -> Result<P256Scalar, Error> {
let dkp_prk = hkdf_extract(dst, randomness.bytes(32).unwrap());

let mut sk = P256Scalar::zero();

Expand Down

0 comments on commit c6bf698

Please sign in to comment.