use gridiron::fp_256::Fp256;
use internal::curve::CurvePoints;
use internal::ed25519::{Ed25519Signing, PrivateSigningKey, PublicSigningKey, Signature};
use internal::field::ExtensionField;
use internal::field::Field;
use internal::fp12elem::Fp12Elem;
use internal::fp2elem::Fp2Elem;
use internal::hashable::{Hashable, Hashable32};
use internal::homogeneouspoint::{HomogeneousPoint, PointErr};
use internal::non_adjacent_form::NonAdjacentForm;
use internal::pairing::Pairing;
use internal::pairing::PairingConfig;
use internal::sha256::Sha256Hashing;
use nonemptyvec::NonEmptyVec;
use num_traits::{One, Zero};
use std::ops::{Add, Mul, Neg};
#[macro_use]
pub mod macros;
pub mod bytedecoder;
pub mod curve;
pub mod ed25519;
pub mod field;
pub mod fp12elem;
pub mod fp2elem;
pub mod fp6elem;
pub mod hashable;
pub mod homogeneouspoint;
pub mod non_adjacent_form;
pub mod pairing;
pub mod rand_bytes;
pub mod sha256;
use api;
pub type ByteVector = Vec<u8>;
pub type ErrorOr<T> = Result<T, InternalError>;
#[derive(Debug)]
pub enum InternalError {
AuthHashMatchFailed,
SignatureFailed,
PrivateKeyFailed,
PointInvalid(PointErr),
BytesDecodeFailed(bytedecoder::DecodeErr),
CorruptReencryptionKey,
}
impl From<PointErr> for InternalError {
fn from(p: PointErr) -> InternalError {
InternalError::PointInvalid(p)
}
}
impl From<bytedecoder::DecodeErr> for InternalError {
fn from(decode_err: bytedecoder::DecodeErr) -> Self {
InternalError::BytesDecodeFailed(decode_err)
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct PublicKey<T: Field> {
pub value: HomogeneousPoint<T>,
}
impl<T: Field + Hashable32> PublicKey<T> {
pub fn to_byte_vectors_32(&self) -> Option<([u8; 32], [u8; 32])> {
self.value
.normalize()
.map(|(x, y)| (x.to_bytes_32(), y.to_bytes_32()))
}
pub fn new(point: HomogeneousPoint<T>) -> PublicKey<T> {
PublicKey { value: point }
}
}
impl PublicKey<Fp256> {
pub fn from_x_y_fp256(x: Fp256, y: Fp256) -> Result<PublicKey<Fp256>, InternalError> {
let result = HomogeneousPoint::from_x_y((x, y)).map(|value| PublicKey { value })?;
Ok(result)
}
}
impl<T: Field + Hashable> Hashable for PublicKey<T> {
fn to_bytes(&self) -> ByteVector {
self.value.to_bytes()
}
}
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct PrivateKey<T: Copy> {
pub value: T,
}
impl From<api::PrivateKey> for PrivateKey<Fp256> {
fn from(api_pk: api::PrivateKey) -> Self {
PrivateKey {
value: Fp256::from(api_pk.to_bytes_32()),
}
}
}
impl PrivateKey<Fp256> {
pub fn from_fp256(fp256: Fp256) -> PrivateKey<Fp256> {
PrivateKey { value: fp256 }
}
}
impl<T> NonAdjacentForm for PrivateKey<T>
where
T: NonAdjacentForm + Copy,
{
fn to_naf(&self) -> Vec<i8> {
self.value.to_naf()
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct SignedValue<T> {
pub public_signing_key: PublicSigningKey,
pub signature: Signature,
pub payload: T,
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct AuthHash {
pub bytes: [u8; 32],
}
impl Hashable for AuthHash {
fn to_bytes(&self) -> ByteVector {
self.bytes.to_vec()
}
}
impl AuthHash {
pub fn create<A: Hashable, F: Sha256Hashing>(hash_func: &F, a: &A) -> AuthHash {
AuthHash {
bytes: hash_func.hash(a),
}
}
}
#[derive(Eq, PartialEq, Clone, Debug)]
pub enum EncryptedValue<T: Field + Hashable> {
EncryptedOnce(EncryptedOnceValue<T>),
Reencrypted(ReencryptedValue<T>),
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ReencryptedValue<T: Field> {
pub ephemeral_public_key: PublicKey<T>,
pub encrypted_message: Fp12Elem<T>,
pub auth_hash: AuthHash,
pub encryption_blocks: NonEmptyVec<ReencryptionBlock<T>>,
}
impl<FP: Field + Hashable> ReencryptedValue<FP> {
fn from_encrypted_once(
encrypted_value: &EncryptedOnceValue<FP>,
re_blocks: NonEmptyVec<ReencryptionBlock<FP>>,
) -> ReencryptedValue<FP> {
ReencryptedValue {
ephemeral_public_key: encrypted_value.ephemeral_public_key,
encrypted_message: encrypted_value.encrypted_message,
auth_hash: encrypted_value.auth_hash,
encryption_blocks: re_blocks,
}
}
fn with_new_re_blocks(
&self,
new_blocks: NonEmptyVec<ReencryptionBlock<FP>>,
) -> ReencryptedValue<FP> {
ReencryptedValue {
ephemeral_public_key: self.ephemeral_public_key,
encrypted_message: self.encrypted_message,
auth_hash: self.auth_hash,
encryption_blocks: new_blocks,
}
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ReencryptionBlock<T: Field> {
pub public_key: PublicKey<T>,
pub encrypted_temp_key: Fp12Elem<T>,
pub rand_re_public_key: PublicKey<T>,
pub encrypted_rand_re_temp_key: Fp12Elem<T>,
}
impl<FP: Field + Hashable> ReencryptionBlock<FP> {
fn with_temp_key(
&self,
encrypted_temp_key: Fp12Elem<FP>,
encrypted_rand_re_temp_key: Fp12Elem<FP>,
) -> ReencryptionBlock<FP> {
ReencryptionBlock {
public_key: self.public_key,
encrypted_temp_key,
rand_re_public_key: self.rand_re_public_key,
encrypted_rand_re_temp_key,
}
}
}
impl<FP: Field + Hashable> Hashable for ReencryptionBlock<FP> {
fn to_bytes(&self) -> Vec<u8> {
[
&self.public_key.to_bytes()[..],
&self.encrypted_temp_key.to_bytes()[..],
&self.rand_re_public_key.to_bytes()[..],
&self.encrypted_rand_re_temp_key.to_bytes()[..],
]
.concat()
}
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct EncryptedOnceValue<T: Field> {
pub ephemeral_public_key: PublicKey<T>,
pub encrypted_message: Fp12Elem<T>,
pub auth_hash: AuthHash,
}
impl<T: Field + Hashable> Hashable for EncryptedValue<T> {
fn to_bytes(&self) -> ByteVector {
match self {
EncryptedValue::EncryptedOnce(EncryptedOnceValue {
ephemeral_public_key,
encrypted_message,
auth_hash,
}) => vec![
ephemeral_public_key.to_bytes(),
encrypted_message.to_bytes(),
auth_hash.to_bytes(),
].to_bytes(),
EncryptedValue::Reencrypted(ReencryptedValue {
ephemeral_public_key,
encrypted_message,
auth_hash,
encryption_blocks,
}) => vec![
ephemeral_public_key.to_bytes(),
encrypted_message.to_bytes(),
auth_hash.to_bytes(),
encryption_blocks.to_bytes(),
].to_bytes(),
}
}
}
pub trait Square {
fn square(&self) -> Self;
}
impl Square for Fp256 {
fn square(&self) -> Self {
self.square()
}
}
fn sum_n<T: Add<Output = T> + Copy + Zero + PartialEq>(t: T, n: u64) -> T {
if n == 0 {
Zero::zero()
} else {
sum_n_loop(t, n - 1, t)
}
}
fn sum_n_loop<T: Add<Output = T> + Copy>(t: T, k: u64, extra: T) -> T {
if k == 1 {
t + extra
} else {
let x = if (k & 1) == 1 { t + extra } else { extra };
sum_n_loop(t + t, k >> 1, x)
}
}
fn pow_for_square<T: One + Mul<T, Output = T> + Copy + Square>(t: T, exp: u64) -> T {
if exp == 0 {
T::one()
} else {
let mut mut_exp = exp;
let mut y = T::one();
let mut x = t;
while mut_exp > 1 {
if mut_exp & 1 == 1 {
y = x * y;
x = x.square();
} else {
x = x.square();
}
mut_exp >>= 1;
}
y * x
}
}
fn array_concat_32<T: Copy + Zero>(one: [T; 32], two: [T; 32]) -> [T; 64] {
let mut result: [T; 64] = [T::zero(); 64];
let x = [one, two].concat();
result.copy_from_slice(x.as_slice());
result
}
pub fn gen_rth_root<T>(pairing: &Pairing<T>, fp12_elem: Fp12Elem<T>) -> Fp12Elem<T>
where
T: Field + ExtensionField + Square + PairingConfig,
{
pairing.final_exp(fp12_elem)
}
pub fn public_keygen<T>(private_key: PrivateKey<T>, generator: HomogeneousPoint<T>) -> PublicKey<T>
where
T: Field + NonAdjacentForm,
{
PublicKey {
value: generator * private_key.value,
}
}
fn sign_value<T, F: Ed25519Signing>(
payload: T,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
ed25519: &F,
) -> SignedValue<T>
where
T: Hashable + Clone,
{
let signature = ed25519.sign(&(public_signing_key, payload.clone()), &private_signing_key);
SignedValue {
public_signing_key,
signature,
payload,
}
}
pub fn encrypt<T: Clone, F: Sha256Hashing, G: Ed25519Signing>(
to_public_key: PublicKey<T>,
plaintext: Fp12Elem<T>, encrypting_key: PrivateKey<T>,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
pairing: &Pairing<T>,
curve_points: &CurvePoints<T>,
hash: &F,
sign: &G,
) -> SignedValue<EncryptedValue<T>>
where
T: Field + ExtensionField + PairingConfig + NonAdjacentForm + Hashable,
{
let ephem_pub_key = PublicKey {
value: curve_points.generator * encrypting_key,
};
let encrypted_message =
pairing.pair(to_public_key.value.times(&encrypting_key), curve_points.g1) * plaintext;
let auth_hash = AuthHash::create(hash, &(ephem_pub_key, plaintext));
sign_value(
EncryptedValue::EncryptedOnce(EncryptedOnceValue {
ephemeral_public_key: ephem_pub_key,
encrypted_message,
auth_hash,
}),
public_signing_key,
private_signing_key,
sign,
)
}
pub fn decrypt<T, H: Sha256Hashing, G: Ed25519Signing>(
private_key: PrivateKey<T>,
signed_encrypted_value: SignedValue<EncryptedValue<T>>,
pairing: &Pairing<T>,
curve_points: &CurvePoints<T>,
hash: &H,
signing: &G,
) -> ErrorOr<Fp12Elem<T>>
where
T: Field + ExtensionField + PairingConfig + NonAdjacentForm + Hashable + From<[u8; 64]>,
{
verify_signed_value(signed_encrypted_value, signing).map_or(
Result::Err(InternalError::SignatureFailed),
|good_encrypted_value| match good_encrypted_value {
EncryptedValue::EncryptedOnce(encrypted_once_value) => {
let unverified_plaintext = decrypt_encrypted_once(
private_key,
&encrypted_once_value,
&pairing,
curve_points,
);
compute_and_compare_auth_hash(
encrypted_once_value.auth_hash,
encrypted_once_value.ephemeral_public_key,
unverified_plaintext,
hash,
)
}
EncryptedValue::Reencrypted(re_value) => {
let unverified_plaintext =
decrypt_reencrypted_value(private_key, &re_value, curve_points, pairing, hash);
compute_and_compare_auth_hash(
re_value.auth_hash,
re_value.ephemeral_public_key,
unverified_plaintext,
hash,
)
}
},
)
}
fn compute_and_compare_auth_hash<FP, H: Sha256Hashing>(
candidate_auth_hash: AuthHash,
public_key: PublicKey<FP>,
unverified_plaintext: Fp12Elem<FP>,
hash: &H,
) -> ErrorOr<Fp12Elem<FP>>
where
FP: Field + ExtensionField + PairingConfig + NonAdjacentForm + Hashable,
{
let computed_auth_hash = AuthHash::create(hash, &(public_key, unverified_plaintext));
if candidate_auth_hash != computed_auth_hash {
Result::Err(InternalError::AuthHashMatchFailed)
} else {
Result::Ok(unverified_plaintext)
}
}
fn decrypt_encrypted_once<T>(
private_key: PrivateKey<T>,
encrypted_value: &EncryptedOnceValue<T>,
pairing: &Pairing<T>,
curve_points: &CurvePoints<T>,
) -> Fp12Elem<T>
where
T: Field + ExtensionField + PairingConfig + NonAdjacentForm,
{
let g1 = curve_points.g1;
let EncryptedOnceValue {
ephemeral_public_key,
encrypted_message,
..
} = encrypted_value;
*encrypted_message * pairing.pair(-(ephemeral_public_key.value * private_key.value), g1)
}
fn decrypt_reencrypted_value<FP, H>(
private_key: PrivateKey<FP>,
reencrypted_value: &ReencryptedValue<FP>,
curve_points: &CurvePoints<FP>,
pairing: &Pairing<FP>,
sha256: &H,
) -> Fp12Elem<FP>
where
FP: Field + Hashable + ExtensionField + PairingConfig + NonAdjacentForm + From<[u8; 64]>,
H: Sha256Hashing,
{
let re_blocks = &reencrypted_value.encryption_blocks;
let re_blocks_last = re_blocks.last();
let ReencryptionBlock {
public_key: re_pub_key_last,
encrypted_temp_key: encrypted_k_last,
rand_re_public_key: rand_re_pub_key_last,
encrypted_rand_re_temp_key: enc_rand_re_k_last,
} = re_blocks_last;
let sec_to_last_k = *encrypted_k_last
* pairing.pair(-re_pub_key_last.value * private_key.value, curve_points.g1);
let sec_to_last_rand_re_k = *enc_rand_re_k_last * pairing.pair(
-rand_re_pub_key_last.value * private_key.value,
curve_points.g1,
);
let (first_k, first_rand_re_k) = re_blocks.to_vec().iter().rev().skip(1).fold(
(sec_to_last_k, sec_to_last_rand_re_k),
|(curr_k, curr_rand_re_k), curr_re_block| {
let ReencryptionBlock {
public_key: next_re_pub_key,
encrypted_temp_key: next_enc_k,
rand_re_public_key: next_rand_re_pub_key,
encrypted_rand_re_temp_key: next_enc_rand_re_k,
} = curr_re_block;
let curr_k_hash = hash2(curr_k, curve_points, sha256);
let new_enc_k = *next_enc_k * pairing.pair(-next_re_pub_key.value, curr_k_hash);
let new_enc_rand_re_k = *next_enc_rand_re_k * pairing.pair(
-next_rand_re_pub_key.value,
hash2(curr_rand_re_k, curve_points, sha256) + curr_k_hash,
);
(new_enc_k, new_enc_rand_re_k)
},
);
reencrypted_value.encrypted_message * pairing.pair(
reencrypted_value.ephemeral_public_key.value.neg(),
hash2(first_k, curve_points, sha256) + hash2(first_rand_re_k, curve_points, sha256),
)
}
fn verify_signed_value<T: Hashable + Clone, G: Ed25519Signing>(
signed_value: SignedValue<T>,
sign: &G,
) -> Option<T> {
if sign.verify(
&(
signed_value.public_signing_key,
signed_value.payload.clone(),
),
&signed_value.signature,
&signed_value.public_signing_key,
) {
Some(signed_value.payload)
} else {
None
}
}
pub fn generate_reencryption_key<FP, H, S>(
from_private_key: PrivateKey<FP>,
to_public_key: PublicKey<FP>,
reencryption_private_key: PrivateKey<FP>,
new_k: Fp12Elem<FP>,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
curve_points: &CurvePoints<FP>,
pairing: &Pairing<FP>,
sha256: &H,
ed25519: &S,
) -> SignedValue<ReencryptionKey<FP>>
where
FP: Field + ExtensionField + PairingConfig + NonAdjacentForm + Hashable + From<[u8; 64]>,
H: Sha256Hashing,
S: Ed25519Signing,
{
let g1 = curve_points.g1;
let re_public_key = public_keygen(reencryption_private_key, curve_points.generator);
let p = to_public_key.value * reencryption_private_key.value;
let encrypted_k = pairing.pair(p, g1) * new_k;
let hashed_k = hash2(new_k, &curve_points, sha256) + (g1.neg() * from_private_key);
let reencryption_key = ReencryptionKey {
re_public_key,
to_public_key,
encrypted_k,
hashed_k,
};
sign_value(
reencryption_key,
public_signing_key,
private_signing_key,
ed25519,
)
}
fn hash2<FP, H>(
fp12: Fp12Elem<FP>,
curve_points: &CurvePoints<FP>,
sha256: &H,
) -> HomogeneousPoint<Fp2Elem<FP>>
where
FP: Field + Hashable + From<[u8; 64]> + NonAdjacentForm,
H: Sha256Hashing,
{
let hash_element = curve_points.hash_element;
let bytes = array_concat_32(sha256.hash(&(0u8, fp12)), sha256.hash(&(1u8, fp12)));
let fp = FP::from(bytes);
hash_element * fp
}
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ReencryptionKey<FP: Field> {
pub re_public_key: PublicKey<FP>,
pub to_public_key: PublicKey<FP>,
pub encrypted_k: Fp12Elem<FP>,
pub hashed_k: HomogeneousPoint<Fp2Elem<FP>>,
}
impl<FP: Field + Hashable> Hashable for ReencryptionKey<FP> {
fn to_bytes(&self) -> ByteVector {
let clone = self;
(clone.re_public_key, clone.to_public_key, clone.encrypted_k).to_bytes()
}
}
impl<FP: Field + NonAdjacentForm> ReencryptionKey<FP> {
pub fn augment(
&self,
priv_key: &PrivateKey<FP>,
g1: &HomogeneousPoint<Fp2Elem<FP>>,
) -> ReencryptionKey<FP> {
let new_hashed_k = -(*g1 * priv_key.value) + self.hashed_k;
ReencryptionKey {
hashed_k: new_hashed_k,
..*self
}
}
}
pub fn reencrypt<FP, S, H>(
signed_reencryption_key: SignedValue<ReencryptionKey<FP>>,
signed_encrypted_value: SignedValue<EncryptedValue<FP>>,
rand_re_priv_key: PrivateKey<FP>,
rand_re_k: Fp12Elem<FP>,
public_signing_key: PublicSigningKey,
private_signing_key: PrivateSigningKey,
ed25519: &S,
sha256: &H,
curve_points: &CurvePoints<FP>,
pairing: &Pairing<FP>,
) -> Result<SignedValue<EncryptedValue<FP>>, InternalError>
where
FP: Field + Hashable + ExtensionField + PairingConfig + NonAdjacentForm + From<[u8; 64]>,
H: Sha256Hashing,
S: Ed25519Signing,
{
match (
verify_signed_value(signed_encrypted_value, ed25519),
verify_signed_value(signed_reencryption_key, ed25519),
) {
(Some(EncryptedValue::EncryptedOnce(encrypted_val)), Some(re_key)) => Ok(sign_value(
EncryptedValue::Reencrypted(reencrypt_encrypted_once(
re_key,
encrypted_val,
rand_re_priv_key,
rand_re_k,
curve_points,
pairing,
sha256,
)),
public_signing_key,
private_signing_key,
ed25519,
)),
(Some(EncryptedValue::Reencrypted(encrypted_val)), Some(re_key)) => Ok(sign_value(
EncryptedValue::Reencrypted(reencrypt_reencrypted_value(
re_key,
&encrypted_val,
rand_re_priv_key,
rand_re_k,
curve_points,
pairing,
sha256,
)),
public_signing_key,
private_signing_key,
ed25519,
)),
(None, _) => Err(InternalError::SignatureFailed),
(_, None) => Err(InternalError::CorruptReencryptionKey),
}
}
fn reencrypt_encrypted_once<FP, H>(
ReencryptionKey {
re_public_key,
to_public_key,
encrypted_k,
hashed_k,
}: ReencryptionKey<FP>,
EncryptedOnceValue {
ephemeral_public_key,
encrypted_message,
auth_hash,
}: EncryptedOnceValue<FP>,
rand_re_priv_key: PrivateKey<FP>,
rand_re_temp_key: Fp12Elem<FP>,
curve_points: &CurvePoints<FP>,
pairing: &Pairing<FP>,
sha256: &H,
) -> ReencryptedValue<FP>
where
FP: Field + Hashable + ExtensionField + PairingConfig + NonAdjacentForm + From<[u8; 64]>,
H: Sha256Hashing,
{
let rand_re_public_key = public_keygen(rand_re_priv_key, curve_points.generator);
let encrypted_rand_re_temp_key =
pairing.pair(to_public_key.value * rand_re_priv_key, curve_points.g1) * rand_re_temp_key;
let encrypted_msg_prime = pairing.pair(
ephemeral_public_key.value,
hashed_k + hash2(rand_re_temp_key, curve_points, sha256),
) * encrypted_message;
let new_encypted_data = EncryptedOnceValue {
ephemeral_public_key,
encrypted_message: encrypted_msg_prime,
auth_hash,
};
let reencryption_block = ReencryptionBlock {
public_key: re_public_key,
encrypted_temp_key: encrypted_k,
rand_re_public_key,
encrypted_rand_re_temp_key,
};
ReencryptedValue::from_encrypted_once(
&new_encypted_data,
NonEmptyVec::new_first(reencryption_block),
)
}
fn reencrypt_reencrypted_value<FP, H>(
ReencryptionKey {
re_public_key,
to_public_key,
encrypted_k,
hashed_k,
}: ReencryptionKey<FP>,
reencrypted_value: &ReencryptedValue<FP>,
rand_re_priv_key: PrivateKey<FP>,
rand_re_temp_key: Fp12Elem<FP>,
curve_points: &CurvePoints<FP>,
pairing: &Pairing<FP>,
sha256: &H,
) -> ReencryptedValue<FP>
where
FP: Field + Hashable + ExtensionField + PairingConfig + NonAdjacentForm + From<[u8; 64]>,
H: Sha256Hashing,
{
let re_blocks = reencrypted_value.encryption_blocks.clone();
let re_blocks_last = re_blocks.last();
let ReencryptionBlock {
public_key: re_pub_key_last,
encrypted_temp_key: encrypted_k_last,
rand_re_public_key: rand_re_pub_key_last,
encrypted_rand_re_temp_key: enc_rand_re_k_last,
} = re_blocks_last;
let encrypted_k_prime_last = *encrypted_k_last * pairing.pair(re_pub_key_last.value, hashed_k); let rand_re_pub_key = public_keygen(rand_re_priv_key, curve_points.generator);
let enc_rand_re_temp_key =
pairing.pair(to_public_key.value * rand_re_priv_key, curve_points.g1) * rand_re_temp_key;
let rand_re_k_last_prime = *enc_rand_re_k_last * pairing.pair(
rand_re_pub_key_last.value,
hash2(rand_re_temp_key, curve_points, sha256) + hashed_k,
);
let re_block_last_prime =
re_blocks_last.with_temp_key(encrypted_k_prime_last, rand_re_k_last_prime);
let new_re_block = ReencryptionBlock {
public_key: re_public_key,
encrypted_temp_key: encrypted_k,
rand_re_public_key: rand_re_pub_key,
encrypted_rand_re_temp_key: enc_rand_re_temp_key,
};
let new_len = re_blocks.len() - 1;
let new_blocks_vec = NonEmptyVec::new_last(
&re_blocks.to_vec()[..new_len],
NonEmptyVec::new(re_block_last_prime, vec![new_re_block]),
);
reencrypted_value.with_new_re_blocks(new_blocks_vec)
}
#[cfg(test)]
mod test {
use super::*;
use api::test::DummyRandomBytes;
use internal::ed25519::Ed25519;
use internal::fp12elem::test::arb_fp12;
use internal::homogeneouspoint::test::arb_homogeneous;
use internal::sha256::Sha256;
use internal::sum_n;
use num_traits::Pow;
use proptest::arbitrary::any;
use proptest::prelude::*;
prop_compose! {
[pub] fn arb_fp256()(seed in any::<u64>()) -> Fp256 {
if seed == 0 {
Fp256::zero()
} else if seed == 1 {
Fp256::one()
} else {
Fp256::from(seed).pow(seed)
}
}
}
struct Mocks;
impl Ed25519Signing for Mocks {
fn sign<T: Hashable>(&self, _t: &T, _private_key: &PrivateSigningKey) -> Signature {
Signature::new([0; 64])
}
fn verify<T: Hashable>(
&self,
_t: &T,
_signature: &Signature,
_public_key: &PublicSigningKey,
) -> bool {
true
}
}
impl Sha256Hashing for Mocks {
fn hash<T: Hashable>(&self, _t: &T) -> [u8; 32] {
[0; 32]
}
}
struct AlwaysFailVerifyEd25519Signing;
impl Ed25519Signing for AlwaysFailVerifyEd25519Signing {
fn sign<T: Hashable>(&self, _t: &T, _private_key: &PrivateSigningKey) -> Signature {
Signature::new([0; 64])
}
fn verify<T: Hashable>(
&self,
_t: &T,
_signature: &Signature,
_public_key: &PublicSigningKey,
) -> bool {
false
}
}
fn gen_random_fp12<R: rand_bytes::RandomBytesGen>(random_bytes: &mut R) -> Fp12Elem<Fp256> {
gen_rth_root(
&pairing::Pairing::new(),
Fp12Elem::create_from_t(
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
Fp256::from(random_bytes.random_bytes_32()),
),
)
}
#[test]
fn pow_for_square_works() {
let v = Fp256::from(10);
let result = pow_for_square(v, 2);
assert_eq!(result, v.pow(2));
let result2 = pow_for_square(v, 5);
assert_eq!(result2, v.pow(5));
}
#[test]
#[cfg_attr(rustfmt, rustfmt_skip)]
fn create_transform_key_known_value() {
let pairing = pairing::Pairing::new();
let ref curve_points = *curve::FP_256_CURVE_POINTS;
let ref sha256 = sha256::Sha256;
let ref ed25519 = api::test::DummyEd25519;
let pbsk = PublicSigningKey::new([0;32]);
let pvsk = PrivateSigningKey::new([0;64]);
let parsed_priv_key = Fp256::new(
[17189375727870516368,
18224873185075715024,
7861335034745733951,
6018377467983639816]);
let private_key = PrivateKey {
value: parsed_priv_key
};
let re_private_parsed = Fp256::new(
[4788877933930756291,
4788243223430685001,
12830453561780987202,
3505141733675108717]
);
let re_private_key = PrivateKey {
value: re_private_parsed
};
let parsed_pub_key_x = Fp256::new(
[1788354481340266741,
6941240287463798938,
4130173504620995341,
8981446317750070851]
);
let parsed_pub_key_y = Fp256::new([3047215073141965834,
7252896082344953161,
7531499505638418112,
7430769205681594307]
);
let public_key = PublicKey::from_x_y_fp256(parsed_pub_key_x, parsed_pub_key_y).unwrap();
let salt = Fp12Elem::create_from_t(
Fp256::new([18092919563963868629,
7535312703102788932,
186825010492696858,
3285197310773262209]
),
Fp256::new([17874798795115358516, 10509553017551504414, 17012896929314934145, 5476233968112089136]),
Fp256::new([2796847722043686783, 16414031163437355558, 14261424020660524668, 487727783503465407]),
Fp256::new([416187413262903592, 14122611974139580613, 17310812515621325570, 5808784911876835769]),
Fp256::new([7642361093456649217, 5130777198153281356, 11536797972669047883, 9799443444165379604]),
Fp256::new([8431854297172108127, 7450944574332271141, 2874140390769630277, 1019688058138881344]),
Fp256::new([3519691940394553995, 11232323575149724221, 14985771333848137161, 8563058112685733978]),
Fp256::new([5738022665900723689, 11696368252523858187, 9012076498597896774, 3837278967586940365]),
Fp256::new([6727065639392985210, 4848553194461313843, 11191929622260275755, 9781019263441166863]),
Fp256::new([17260445456023464461, 3557834823344504179, 3352261581837594978, 2534511165315774091]),
Fp256::new([5004153509371452589, 16294162787904550875, 220950411748700060, 9655544337531903215]),
Fp256::new([716814800932300689, 17116457880960511458, 14343763253984106508, 2777291258235104886])
);
let re_key = generate_reencryption_key(private_key, public_key, re_private_key, salt, pbsk, pvsk, curve_points, &pairing, sha256, ed25519).payload;
let good_encrypted_k = Fp12Elem::create_from_t(
Fp256::new([7407619104651529218, 11463625481515793061, 5779432075019267186, 1986317841005960384]),
Fp256::new([5296659303137686873, 4280257893045319426, 13321863481405346776, 339146066007335840]),
Fp256::new([11955219787330847568, 17307907405273938070, 6050002638559171205, 3416413821703424493]),
Fp256::new([11028330629390207567, 16277126227596076559, 4506129636556298670, 8927393321320788585]),
Fp256::new([14929701004962957076, 11618023364955498545, 11149460125633770324, 4287724988614884330]),
Fp256::new([16663177338467743103, 9761509637791858731, 6430727702093942934, 7644115424845028812]),
Fp256::new([11454739616096583580, 18111719416759575391, 463464369169095836, 1706463454220476131]),
Fp256::new([3018797931778597698, 10419318108488400682, 14645641859123347738, 6905694756960070262]),
Fp256::new([13171388654358895258, 15528195738974811681, 16793703368871851779, 2803335060126077892]),
Fp256::new([16075574095286747059, 5527914106918380322, 14163459131246838794, 6172704542839199181]),
Fp256::new([8615044640359185014, 4124215179308147679, 8986594639588272636, 6054162342851795720]),
Fp256::new([4319420581507833215, 8897085582877617929, 10387143255934299553, 7956185097844554281])
);
let good_hashed_k = HomogeneousPoint {
x: fp2elem::Fp2Elem {
elem1: Fp256::new([15317763025871500218, 6390131415937895053, 2333868648931173919, 3572043083229448878]),
elem2: Fp256::new([14223329351633427100, 16393628357177966161, 4178163731932019692, 8288476102416800248])
},
y: fp2elem::Fp2Elem {
elem1: Fp256::new([6377061368106074588, 1323000841828716335, 3985357987373299809, 740030627928627720]),
elem2: Fp256::new([5040653610201421212, 6584711892080312693, 9762190934038319400, 5493931597847633801])
},
z: fp2elem::Fp2Elem {
elem1: Fp256::new([15628823850961861711, 10372016414646397245, 6029716315346157217, 359836457304122956]),
elem2: Fp256::new([5575879339459113319, 6203973355951852449, 15340759962329721833, 2924737412456785480])
}
};
assert_eq!(good_encrypted_k, re_key.encrypted_k);
assert_eq!(good_hashed_k, re_key.hashed_k)
}
#[test]
fn reencrypt_roundtrip_with_known_keys() {
let pt_fp12 = Fp12Elem::create_from_t(
Fp256::from(1),
Fp256::from(2),
Fp256::from(3),
Fp256::from(4),
Fp256::from(5),
Fp256::from(6),
Fp256::from(7),
Fp256::from(8),
Fp256::from(9),
Fp256::from(10),
Fp256::from(11),
Fp256::from(12),
);
let salt_fp12 = Fp12Elem::create_from_t(
Fp256::from(11),
Fp256::from(12),
Fp256::from(13),
Fp256::from(14),
Fp256::from(15),
Fp256::from(16),
Fp256::from(17),
Fp256::from(18),
Fp256::from(19),
Fp256::from(110),
Fp256::from(111),
Fp256::from(112),
);
let rand_re_k_fp12 = Fp12Elem::create_from_t(
Fp256::from(21),
Fp256::from(22),
Fp256::from(23),
Fp256::from(24),
Fp256::from(25),
Fp256::from(26),
Fp256::from(27),
Fp256::from(28),
Fp256::from(29),
Fp256::from(210),
Fp256::from(211),
Fp256::from(212),
);
let pairing = pairing::Pairing::new();
let ref curve_points = *curve::FP_256_CURVE_POINTS;
let ref sha256 = sha256::Sha256;
let ref ed25519 = api::test::DummyEd25519;
let salt = gen_rth_root(&pairing, salt_fp12);
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let re_private = PrivateKey::from_fp256(
Fp256::new([
4788877933930756291,
4788243223430685001,
12830453561780987202,
3505141733675108717,
]),
);
let ephem_priv_key = PrivateKey::from_fp256(
Fp256::new([
14793504136496500961,
15175545718199138505,
10822834284350498357,
3911077875457902790,
]),
);
let priv_key = PrivateKey::from_fp256(
Fp256::new([
4343411144194473122,
3301349774239543721,
14670225672814360477,
7004277019202547328,
]),
);
let pub_key = public_keygen(priv_key, curve_points.generator);
let plaintext = pt_fp12;
let encrypt_result = encrypt(
pub_key,
plaintext,
ephem_priv_key,
pbsk,
pvsk,
&pairing,
curve_points,
sha256,
ed25519,
);
let rand_re_priv_key = PrivateKey::from_fp256(
Fp256::new([
12307718303527388876,
9236064098299522403,
14597629839067767666,
2797782574727398164,
]),
);
let rand_re_k = gen_rth_root(&pairing, rand_re_k_fp12);
let re_key = generate_reencryption_key(
priv_key,
pub_key,
re_private,
salt,
pbsk,
pvsk,
curve_points,
&pairing,
sha256,
ed25519,
);
let reencrypted_value = reencrypt(
re_key,
encrypt_result,
rand_re_priv_key,
rand_re_k,
pbsk,
pvsk,
ed25519,
sha256,
curve_points,
&pairing,
).unwrap();
let decrypted_value = decrypt(
priv_key,
reencrypted_value,
&pairing,
curve_points,
sha256,
ed25519,
).unwrap();
assert_eq!(decrypted_value, plaintext)
}
#[test]
fn fail_when_verify_fails() {
let pairing = pairing::Pairing::new();
let ref curve_points = *curve::FP_256_CURVE_POINTS;
let ref sha256 = sha256::Sha256;
let salt1 = gen_rth_root(&pairing, gen_random_fp12(&mut DummyRandomBytes));
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let priv_key = PrivateKey::from_fp256(
Fp256::new([
4343411144194473122,
3301349774239543721,
14670225672814360477,
7004277019202547328,
]),
);
let ephem_priv_key = PrivateKey::from_fp256(
Fp256::new([
4343411144194473352,
5979978379713320361,
12081649158504707828,
14157259700187258052,
]),
);
let pub_key = public_keygen(priv_key, curve_points.generator);
let encrypted_value = encrypt(
pub_key,
salt1,
ephem_priv_key,
pbsk,
pvsk,
&pairing,
curve_points,
sha256,
&AlwaysFailVerifyEd25519Signing,
);
let decrypt_result = decrypt(
priv_key,
encrypted_value,
&pairing,
curve_points,
sha256,
&AlwaysFailVerifyEd25519Signing,
);
if let Err(InternalError::SignatureFailed) = decrypt_result {
} else {
assert!(false, "Error should have been returned")
}
}
#[test]
fn fail_when_auth_hash_does_not_match_wrong_priv_key() {
let pairing = pairing::Pairing::new();
let ref curve_points = *curve::FP_256_CURVE_POINTS;
let ref sha256 = sha256::Sha256;
let salt1 = gen_rth_root(&pairing, gen_random_fp12(&mut DummyRandomBytes));
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let priv_key = PrivateKey::from_fp256(
Fp256::new([
4343411144194473122,
3301349774239543721,
14670225672814360477,
7004277019202547328,
]),
);
let ephem_priv_key = PrivateKey::from_fp256(
Fp256::new([
4343411144194473352,
5979978379713320361,
12081649158504707828,
14157259700187258052,
]),
);
let pub_key = public_keygen(priv_key, curve_points.generator);
let encrypted_value = encrypt(
pub_key,
salt1,
ephem_priv_key,
pbsk,
pvsk,
&pairing,
curve_points,
sha256,
&Mocks,
);
let diff_priv_key = PrivateKey::from_fp256(Fp256::from(42));
let decrypt_result = decrypt(
diff_priv_key,
encrypted_value,
&pairing,
curve_points,
sha256,
&Mocks,
);
if let Err(InternalError::AuthHashMatchFailed) = decrypt_result {
} else {
assert!(false, "Auth hash check should fail")
}
}
#[test]
fn reencrypt_2nd_level_roundtrip_with_known_keys_and_auth_hash_checks() {
let pt_fp12 = Fp12Elem::create_from_t(
Fp256::from(1),
Fp256::from(2),
Fp256::from(3),
Fp256::from(4),
Fp256::from(5),
Fp256::from(6),
Fp256::from(7),
Fp256::from(8),
Fp256::from(9),
Fp256::from(10),
Fp256::from(11),
Fp256::from(12),
);
let salt_1_fp12 = Fp12Elem::create_from_t(
Fp256::from(11),
Fp256::from(12),
Fp256::from(13),
Fp256::from(14),
Fp256::from(15),
Fp256::from(16),
Fp256::from(17),
Fp256::from(18),
Fp256::from(19),
Fp256::from(110),
Fp256::from(111),
Fp256::from(112),
);
let rand_re_k_1_fp12 = Fp12Elem::create_from_t(
Fp256::from(21),
Fp256::from(22),
Fp256::from(23),
Fp256::from(24),
Fp256::from(25),
Fp256::from(26),
Fp256::from(27),
Fp256::from(28),
Fp256::from(29),
Fp256::from(210),
Fp256::from(211),
Fp256::from(212),
);
let salt_2_fp12 = Fp12Elem::create_from_t(
Fp256::from(31),
Fp256::from(32),
Fp256::from(33),
Fp256::from(34),
Fp256::from(35),
Fp256::from(36),
Fp256::from(37),
Fp256::from(38),
Fp256::from(39),
Fp256::from(310),
Fp256::from(311),
Fp256::from(312),
);
let rand_re_k_2_fp12 = Fp12Elem::create_from_t(
Fp256::from(41),
Fp256::from(42),
Fp256::from(43),
Fp256::from(44),
Fp256::from(45),
Fp256::from(46),
Fp256::from(47),
Fp256::from(48),
Fp256::from(49),
Fp256::from(410),
Fp256::from(411),
Fp256::from(412),
);
let pairing = pairing::Pairing::new();
let ref curve_points = *curve::FP_256_CURVE_POINTS;
let ref sha256 = sha256::Sha256;
let ref ed25519 = api::test::DummyEd25519;
let salt1 = gen_rth_root(&pairing, salt_1_fp12);
let pbsk = PublicSigningKey::new([0; 32]);
let pvsk = PrivateSigningKey::new([0; 64]);
let re_private = PrivateKey::from_fp256(
Fp256::new([
4788877933930756291,
4788243223430685001,
12830453561780987202,
3505141733675108717,
]),
);
let ephem_priv_key = PrivateKey::from_fp256(
Fp256::new([
14793504136496500961,
15175545718199138505,
10822834284350498357,
3911077875457902790,
]),
);
let priv_key = PrivateKey::from_fp256(
Fp256::new([
4343411144194473122,
3301349774239543721,
14670225672814360477,
7004277019202547328,
]),
);
let pub_key = public_keygen(priv_key, curve_points.generator);
let priv_key2 = PrivateKey::from_fp256(
Fp256::new([
17194266036165098608,
9037271175465250277,
11853952711362131111,
3547267572045125887,
]),
);
let pub_key2 = public_keygen(priv_key2, curve_points.generator);
let priv_key3 = PrivateKey::from_fp256(
Fp256::new([
17194266036165098608,
12893008869371042789,
10789969574966048103,
5310310528257188173,
]),
);
let pub_key3 = public_keygen(priv_key3, curve_points.generator);
let plaintext = gen_rth_root(&pairing, pt_fp12);
let encrypt_result = encrypt(
pub_key,
plaintext,
ephem_priv_key,
pbsk,
pvsk,
&pairing,
curve_points,
sha256,
ed25519,
);
let rand_re_priv_key = PrivateKey::from_fp256(
Fp256::new([
12307718303527388876,
9236064098299522403,
14597629839067767666,
2797782574727398164,
]),
);
let rand_re_k = gen_rth_root(&pairing, rand_re_k_1_fp12);
let re_key = generate_reencryption_key(
priv_key,
pub_key2,
re_private,
salt1,
pbsk,
pvsk,
curve_points,
&pairing,
sha256,
ed25519,
);
let reencrypted_value = reencrypt(
re_key,
encrypt_result,
rand_re_priv_key,
rand_re_k,
pbsk,
pvsk,
ed25519,
sha256,
curve_points,
&pairing,
).unwrap();
let rand_re_priv_key_2 = PrivateKey::from_fp256(
Fp256::new([
14537025737697333248,
14405801590671684734,
8720510408043004481,
279778257,
]),
);
let re_priv_2 = PrivateKey::from_fp256(
Fp256::new([
9459678164233369795,
13577299277762900646,
12830453561780987198,
3505141733675108717,
]),
);
let rand_re_k_2 = gen_rth_root(&pairing, rand_re_k_2_fp12);
let salt2 = gen_rth_root(&pairing, salt_2_fp12);
let reencryption_key_2 = generate_reencryption_key(
priv_key2,
pub_key3,
re_priv_2,
salt2,
pbsk,
pvsk,
curve_points,
&pairing,
sha256,
ed25519,
);
let reencrypted_value_2 = reencrypt(
reencryption_key_2,
reencrypted_value,
rand_re_priv_key_2,
rand_re_k_2,
pbsk,
pvsk,
ed25519,
sha256,
curve_points,
&pairing,
).unwrap();
if let EncryptedValue::Reencrypted(v) = reencrypted_value_2.payload.clone() {
assert_eq!(2, v.encryption_blocks.len())
} else {
assert!(false, "This should be a reencrypted value")
}
let decrypted_value = decrypt(
priv_key3,
reencrypted_value_2.clone(),
&pairing,
curve_points,
sha256,
ed25519,
).unwrap();
assert_eq!(decrypted_value, plaintext);
let invalid_priv_key = PrivateKey::from_fp256(Fp256::from(42));
let decrypt_auth_failure = decrypt(
invalid_priv_key,
reencrypted_value_2,
&pairing,
curve_points,
sha256,
ed25519,
);
if let Err(InternalError::AuthHashMatchFailed) = decrypt_auth_failure {
} else {
assert!(false, "Private key should have caused an auth hash failure")
}
}
fn good_signing_keys() -> (PrivateSigningKey, PublicSigningKey) {
let pub_signing_key = ed25519::PublicSigningKey::new([
138, 136, 227, 221, 116, 9, 241, 149, 253, 82, 219, 45, 60, 186, 93, 114, 202, 103, 9,
191, 29, 148, 18, 27, 243, 116, 136, 1, 180, 15, 111, 92,
]);
let priv_signing_key = ed25519::PrivateSigningKey::new([
88, 232, 110, 251, 117, 250, 78, 44, 65, 15, 70, 225, 109, 233, 246, 172, 174, 26, 23,
3, 82, 134, 81, 182, 155, 193, 118, 192, 136, 190, 243, 110, 177, 122, 42, 44, 243,
212, 164, 26, 142, 78, 24, 204, 69, 200, 101, 109, 85, 142, 206, 221, 176, 173, 180,
107, 250, 8, 138, 95, 83, 190, 210, 82,
]);
(priv_signing_key, pub_signing_key)
}
proptest! {
#[test]
fn sign_verify_roundtrip(fp256 in arb_fp256()) {
let (priv_signing_key, pub_signing_key) = good_signing_keys();
let signed_value = sign_value(fp256, pub_signing_key, priv_signing_key, &Ed25519);
let verified = verify_signed_value(signed_value, &Ed25519);
assert!(verified.is_some())
}
#[test]
fn encrypt_decrypt_roundtrip(priv_key in arb_priv_key(), plaintext in arb_fp12().prop_filter("", |a| !(*a == Fp12Elem::<Fp256>::zero()))) {
let pub_key = public_keygen(priv_key, curve::FP_256_CURVE_POINTS.generator);
let ephem_secret_key = PrivateKey::from_fp256(Fp256::new_from_u64(42));
let (priv_signing_key, pub_signing_key) = good_signing_keys();
let pairing = pairing::Pairing::new();
let curve_points = &*curve::FP_256_CURVE_POINTS;
let encrypt_result = encrypt(
pub_key,
plaintext,
ephem_secret_key,
pub_signing_key,
priv_signing_key,
&pairing,
curve_points,
&Sha256,
&Ed25519
);
let decrypt_result = decrypt(
priv_key,
encrypt_result,
&pairing,
curve_points,
&Sha256,
&Ed25519
).unwrap();
assert_eq!(plaintext, decrypt_result);
}
#[test]
fn sum_n_is_times(x in any::<i32>(), n in any::<i32>()) {
let computed_result = if n < 0 {
-sum_n(x as i64, n.abs() as u64)
} else{
sum_n(x as i64, n as u64)
};
prop_assert_eq!(computed_result, (x as i64) * (n as i64));
}
#[test]
fn generate_reencryption_key_sig_not_over_hashedk(
signed_re_key in arb_reencryption_key(),
fp in arb_fp256()
) {
let cpoints = &*curve::FP_256_CURVE_POINTS;
let new_hashed_k = cpoints.g1 * fp;
let re_key: ReencryptionKey<Fp256> = signed_re_key.payload.clone();
let re_key_copy = ReencryptionKey {
re_public_key: re_key.re_public_key,
to_public_key: re_key.to_public_key,
encrypted_k: re_key.encrypted_k,
hashed_k: new_hashed_k
};
prop_assert_eq!(signed_re_key.payload.to_bytes(), re_key_copy.to_bytes())
}
}
prop_compose! {
fn arb_pub_key()(ref hpoint in arb_homogeneous().prop_filter("", |a| !(*a == Zero::zero()))) -> PublicKey<Fp256> {
PublicKey { value: *hpoint }
}
}
prop_compose! {
fn arb_priv_key()(fp256 in arb_fp256().prop_filter("", |a| !(*a == Zero::zero()))) -> PrivateKey<Fp256> {
PrivateKey { value: fp256 }
}
}
prop_compose! {
fn arb_reencryption_key()
(ref reencryption_private_key in arb_priv_key(),
ref new_k in arb_fp12(),
to_public_key in arb_pub_key(),
from_private_key in arb_priv_key())
-> SignedValue<ReencryptionKey<Fp256>> {
let pairing = pairing::Pairing::new();
let curve_points = &*curve::FP_256_CURVE_POINTS;
generate_reencryption_key(
from_private_key,
to_public_key,
*reencryption_private_key,
*new_k,
PublicSigningKey::new([0; 32]),
PrivateSigningKey::new([0;64]),
&curve_points,
&pairing,
&Mocks,
&Mocks
)
}
}
}