arcium-primitives 0.4.3

Arcium primitives
Documentation
use ff::Field;

use crate::{
    algebra::{
        field::{FieldExtension, SubfieldElement},
        BoxedUint,
    },
    correlated_randomness::pow::types::{PowPair, PowPairs},
    izip_eq,
    random::{CryptoRngCore, Random, RandomWith},
    sharing::{FieldShare, FieldShares, GlobalFieldKey},
    types::{heap_array::SubfieldElements, Positive},
};
// -------------------------
// |   Random Generation   |
// -------------------------

impl<F: FieldExtension> RandomWith<BoxedUint> for PowPair<F> {
    fn random_with(_rng: impl CryptoRngCore, _exp: BoxedUint) -> Self {
        unimplemented!("PowPairs are correlated randomness. Use `random_n_with` to establish correlation for n_parties")
    }

    fn random_n_with<Container: FromIterator<Self>>(
        mut rng: impl CryptoRngCore,
        n_parties: usize,
        exp: BoxedUint,
    ) -> Container {
        let alphas = Vec::<GlobalFieldKey<F>>::random_n_with(&mut rng, n_parties, n_parties - 1);
        PowPair::random_n_with(&mut rng, n_parties, (exp, alphas))
    }
}

impl<F: FieldExtension> RandomWith<(BoxedUint, Vec<Vec<GlobalFieldKey<F>>>)> for PowPair<F> {
    fn random_with(
        _rng: impl CryptoRngCore,
        _data: (BoxedUint, Vec<Vec<GlobalFieldKey<F>>>),
    ) -> Self {
        unimplemented!("PowPairs are correlated randomness. Use `random_n_with` to establish correlation for n_parties")
    }

    /// Generates a vector of `n_parties` `PowPair`s, where each `PowPair` is
    /// generated with the same `exp` and authenticated toward all other parties.
    fn random_n_with<Container: FromIterator<Self>>(
        mut rng: impl CryptoRngCore,
        n_parties: usize,
        (exp, all_alphas): (BoxedUint, Vec<Vec<GlobalFieldKey<F>>>),
    ) -> Container {
        assert_eq!(n_parties, all_alphas.len());

        let mut lambda = <SubfieldElement<F> as Random>::random(&mut rng);
        let mut lambda_pow_neg_exp = lambda.pow(&exp).invert().into_option();
        while lambda_pow_neg_exp.is_none() {
            // If λ^(-exp) is not invertible, we need to resample λ until we get an invertible one.
            let lambda_new = <SubfieldElement<F> as Random>::random(&mut rng);
            let lambda_new_pow_neg_exp = lambda_new.pow(&exp).invert().into_option();
            if let Some(lambda_new_pow_neg_exp) = lambda_new_pow_neg_exp {
                lambda = lambda_new;
                lambda_pow_neg_exp = Some(lambda_new_pow_neg_exp);
                break;
            }
        }

        let lambda_shares: Vec<_> =
            FieldShare::<F>::random_n_with(&mut rng, n_parties, (lambda, all_alphas.clone()));
        let lambda_pow_neg_exp_shares: Vec<_> = FieldShare::<F>::random_n_with(
            &mut rng,
            n_parties,
            (
                lambda_pow_neg_exp.expect("We sampled λ so that it was invertible"),
                all_alphas,
            ),
        );

        izip_eq!(lambda_shares, lambda_pow_neg_exp_shares)
            .map(PowPair::new)
            .collect()
    }
}

impl<F: FieldExtension, N: Positive> RandomWith<BoxedUint> for PowPairs<F, N> {
    fn random_with(_rng: impl CryptoRngCore, _exp: BoxedUint) -> Self {
        unimplemented!("PowPairs are correlated randomness. Use `random_n_with` to establish correlation for n_parties")
    }

    fn random_n_with<Container: FromIterator<Self>>(
        mut rng: impl CryptoRngCore,
        n_parties: usize,
        exp: BoxedUint,
    ) -> Container {
        let alphas = Vec::<GlobalFieldKey<F>>::random_n_with(&mut rng, n_parties, n_parties - 1);
        PowPairs::random_n_with(&mut rng, n_parties, (exp, alphas))
    }
}

impl<F: FieldExtension, M: Positive> RandomWith<(BoxedUint, Vec<Vec<GlobalFieldKey<F>>>)>
    for PowPairs<F, M>
{
    fn random_with(
        _rng: impl CryptoRngCore,
        _data: (BoxedUint, Vec<Vec<GlobalFieldKey<F>>>),
    ) -> Self {
        unimplemented!("PowPairs are correlated randomness. Use `random_n_with` to establish correlation for n_parties")
    }

    fn random_n_with<Container: FromIterator<Self>>(
        mut rng: impl CryptoRngCore,
        n_parties: usize,
        (exp, all_alphas): (BoxedUint, Vec<Vec<GlobalFieldKey<F>>>),
    ) -> Container {
        assert_eq!(n_parties, all_alphas.len());

        // TODO: lambdas = <SubfieldElements<F, M> as RandomNonZero>::random_non_zero(rng);
        let lambdas = <SubfieldElements<F, M> as Random>::random(&mut rng);
        let lambdas_pow_neg_exp = lambdas.pow(exp).invert().expect("λ^exp is not invertible");

        let lambda_shares: Vec<_> =
            FieldShares::<F, M>::random_n_with(&mut rng, n_parties, (lambdas, all_alphas.clone()));
        let lambda_pow_neg_exp_shares: Vec<_> = FieldShares::<F, M>::random_n_with(
            &mut rng,
            n_parties,
            (lambdas_pow_neg_exp, all_alphas),
        );

        izip_eq!(lambda_shares, lambda_pow_neg_exp_shares)
            .map(PowPairs::new)
            .collect()
    }
}