pub fn encrypt_and_prove(
    seed: Randomness,
    key_message_pairs: &[(FsEncryptionPublicKey, FsEncryptionPlaintext)],
    epoch: Epoch,
    public_coefficients: &PublicCoefficientsBytes,
    associated_data: &[u8],
) -> Result<(FsEncryptionCiphertext, ZKProofDec, ZKProofShare), EncryptAndZKProveError> {
    let public_keys: Result<Vec<miracl::ECP>, EncryptAndZKProveError> = key_message_pairs
        .as_ref()
        .iter()
        .zip(0..)
        .map(|((public_key, _plaintext), receiver_index)| {
            miracl_g1_from_bytes(public_key.as_bytes()).map_err(|_| {
                EncryptAndZKProveError::MalformedFsPublicKeyError {
                    receiver_index,
                    error: MalformedPublicKeyError {
                        algorithm: AlgorithmId::NiDkg_Groth20_Bls12_381,
                        key_bytes: Some(public_key.as_bytes().to_vec()),
                        internal_error: "Could not parse public key.".to_string(),
                    },
                }
            })
        })
        .collect();
    let public_keys = public_keys?;

    let plaintext_chunks: Vec<_> = key_message_pairs
        .as_ref()
        .iter()
        .map(|(_public_key, plaintext)| plaintext_from_bytes(&plaintext.chunks))
        .collect();

    // The API takes a vector of pointers so we need to keep the values but generate
    // another vector with the values.
    let public_key_pointers: Vec<&miracl::ECP> = public_keys.iter().collect();
    let tau = Tau::from(epoch);
    let mut rng = crypto::RAND_ChaCha20::new(seed.get());
    let (ciphertext, toxic_waste) = crypto::enc_chunks(
        &plaintext_chunks,
        public_key_pointers,
        &tau.0[..],
        associated_data,
        &SYS_PARAMS,
        &mut rng,
    )
    .expect(
        "TODO (CRP-815): I think the result should never be None.  Can the return type be changed?",
    );

    let chunking_proof = prove_chunking(
        &public_keys,
        &ciphertext,
        &plaintext_chunks,
        &toxic_waste,
        &mut rng,
    );
    let miracl_public_coefficients = public_coefficients_to_miracl(public_coefficients)
        .map_err(|_| EncryptAndZKProveError::MalformedPublicCoefficients)?;
    let sharing_proof = prove_sharing(
        &public_keys,
        &miracl_public_coefficients,
        &ciphertext,
        &plaintext_chunks,
        &toxic_waste,
        &mut rng,
    );

    #[cfg(test)]
    {
        assert_eq!(
            crypto::verify_chunking(
                &crypto::ChunkingInstance {
                    g1_gen: miracl::ECP::generator(),
                    public_keys: public_keys.clone(),
                    ciphertext_chunks: ciphertext.cc.clone(),
                    randomizers_r: ciphertext.rr.clone(),
                },
                &chunking_proof,
            ),
            Ok(()),
            "We just created an invalid chunking proof"
        );
        let combined_ciphertexts: Vec<miracl::ECP> = ciphertext
            .cc
            .iter()
            .map(util::ecp_from_big_endian_chunks)
            .collect();

        assert_eq!(
            crypto::verify_sharing(
                &crypto::SharingInstance {
                    g1_gen: miracl::ECP::generator(),
                    g2_gen: miracl::ECP2::generator(),
                    public_keys,
                    public_coefficients: miracl_public_coefficients,
                    combined_randomizer: util::ecp_from_big_endian_chunks(&ciphertext.rr),
                    combined_ciphertexts,
                },
                &sharing_proof,
            ),
            Ok(()),
            "We just created an invalid sharing proof"
        );
    }

    Ok((
        ciphertext_from_miracl(&ciphertext),
        chunking_proof_from_miracl(&chunking_proof),
        sharing_proof_from_miracl(&sharing_proof),
    ))
}
/// Encrypts several messages to several recipients
///
/// # Errors
/// This should never return an error if the protocol is followed.  Every error
/// should be prevented by the caller validating the arguments beforehand.
///
/// # Panics
/// * If the `enc_chunks` function fails. Though, this truly should never happen
///   (cf. CRP-815).
Encrypts several messages to several recipients
Encrypts several messages to several recipients
pub fn encrypt_and_prove(
    seed: Randomness,
    key_message_pairs: &[(FsEncryptionPublicKey, FsEncryptionPlaintext)],
    epoch: Epoch,
    public_coefficients: &PublicCoefficientsBytes,
    associated_data: &[u8],
) -> Result<(FsEncryptionCiphertext, ZKProofDec, ZKProofShare), EncryptAndZKProveError> {
    let public_keys: Result<Vec<miracl::ECP>, EncryptAndZKProveError> = key_message_pairs
        .as_ref()
        .iter()
        .zip(0..)
        .map(|((public_key, _plaintext), receiver_index)| {
            miracl_g1_from_bytes(public_key.as_bytes()).map_err(|_| {
                EncryptAndZKProveError::MalformedFsPublicKeyError {
                    receiver_index,
                    error: MalformedPublicKeyError {
                        algorithm: AlgorithmId::NiDkg_Groth20_Bls12_381,
                        key_bytes: Some(public_key.as_bytes().to_vec()),
                        internal_error: "Could not parse public key.".to_string(),
                    },
                }
            })
        })
        .collect();
    let public_keys = public_keys?;
    let plaintext_chunks: Vec<_> = key_message_pairs
        .as_ref()
        .iter()
        .map(|(_public_key, plaintext)| plaintext_from_bytes(&plaintext.chunks))
        .collect();
    // The API takes a vector of pointers so we need to keep the values but generate
    // another vector with the values.
    let public_key_pointers: Vec<&miracl::ECP> = public_keys.iter().collect();
    let tau = Tau::from(epoch);
    let mut rng = crypto::RAND_ChaCha20::new(seed.get());
    let (ciphertext, toxic_waste) = crypto::enc_chunks(
        &plaintext_chunks,
        public_key_pointers,
        &tau.0[..],
        associated_data,
        &SYS_PARAMS,
        &mut rng,
    )
    .expect(
        "TODO (CRP-815): I think the result should never be None.  Can the return type be changed?",
    );
    let chunking_proof = prove_chunking(
        &public_keys,
        &ciphertext,
        &plaintext_chunks,
        &toxic_waste,
        &mut rng,
    );
    let miracl_public_coefficients = public_coefficients_to_miracl(public_coefficients)
        .map_err(|_| EncryptAndZKProveError::MalformedPublicCoefficients)?;
    let sharing_proof = prove_sharing(
        &public_keys,
        &miracl_public_coefficients,
        &ciphertext,
        &plaintext_chunks,
        &toxic_waste,
        &mut rng,
    );
    #[cfg(test)]
    {
        assert_eq!(
            crypto::verify_chunking(
                &crypto::ChunkingInstance {
                    g1_gen: miracl::ECP::generator(),
                    public_keys: public_keys.clone(),
                    ciphertext_chunks: ciphertext.cc.clone(),
                    randomizers_r: ciphertext.rr.clone(),
                },
                &chunking_proof,
            ),
            Ok(()),
            "We just created an invalid chunking proof"
        );
        let combined_ciphertexts: Vec<miracl::ECP> = ciphertext
            .cc
            .iter()
            .map(util::ecp_from_big_endian_chunks)
            .collect();
        assert_eq!(
            crypto::verify_sharing(
                &crypto::SharingInstance {
                    g1_gen: miracl::ECP::generator(),
                    g2_gen: miracl::ECP2::generator(),
                    public_keys,
                    public_coefficients: miracl_public_coefficients,
                    combined_randomizer: util::ecp_from_big_endian_chunks(&ciphertext.rr),
                    combined_ciphertexts,
                },
                &sharing_proof,
            ),
            Ok(()),
            "We just created an invalid sharing proof"
        );
    }
    Ok((
        ciphertext_from_miracl(&ciphertext),
        chunking_proof_from_miracl(&chunking_proof),
        sharing_proof_from_miracl(&sharing_proof),
    ))
}
pub fn encrypt_and_prove ( seed : Randomness , key_message_pairs : & [ ( FsEncryptionPublicKey , FsEncryptionPlaintext ) ] , epoch : Epoch , public_coefficients : & PublicCoefficientsBytes , associated_data : & [ u8 ] , ) -> Result < ( FsEncryptionCiphertext , ZKProofDec , ZKProofShare ) , EncryptAndZKProveError > { let public_keys : Result < Vec < miracl :: ECP > , EncryptAndZKProveError > = key_message_pairs . as_ref ( ) . iter ( ) . zip ( 0 .. ) . map ( | ( ( public_key , _plaintext ) , receiver_index ) | { miracl_g1_from_bytes ( public_key . as_bytes ( ) ) . map_err ( | _ | { EncryptAndZKProveError :: MalformedFsPublicKeyError { receiver_index , error : MalformedPublicKeyError { algorithm : AlgorithmId :: NiDkg_Groth20_Bls12_381 , key_bytes : Some ( public_key . as_bytes ( ) . to_vec ( ) ) , internal_error : " " . to_string ( ) , } , } } ) } ) . collect ( ) ; let public_keys = public_keys ? ; let plaintext_chunks : Vec < _ > = key_message_pairs . as_ref ( ) . iter ( ) . map ( | ( _public_key , plaintext ) | plaintext_from_bytes ( & plaintext . chunks ) ) . collect ( ) ; // The API takes a vector of pointers so we need to keep the values but generate // another vector with the values. let public_key_pointers : Vec < & miracl :: ECP > = public_keys . iter ( ) . collect ( ) ; let tau = Tau :: from ( epoch ) ; let mut rng = crypto :: RAND_ChaCha20 :: new ( seed . get ( ) ) ; let ( ciphertext , toxic_waste ) = crypto :: enc_chunks ( & plaintext_chunks , public_key_pointers , & tau . 0 [ .. ] , associated_data , & SYS_PARAMS , & mut rng , ) . expect ( " " , ) ; let chunking_proof = prove_chunking ( & public_keys , & ciphertext , & plaintext_chunks , & toxic_waste , & mut rng , ) ; let miracl_public_coefficients = public_coefficients_to_miracl ( public_coefficients ) . map_err ( | _ | EncryptAndZKProveError :: MalformedPublicCoefficients ) ? ; let sharing_proof = prove_sharing ( & public_keys , & miracl_public_coefficients , & ciphertext , & plaintext_chunks , & toxic_waste , & mut rng , ) ; # [ cfg ( test ) ] { assert_eq ! ( crypto verify_chunking ( crypto ChunkingInstance { g1_gen miracl ECP generator ( ) public_keys public_keys clone ( ) ciphertext_chunks ciphertext cc clone ( ) randomizers_r ciphertext rr clone ( ) } chunking_proof ) Ok ( ( ) ) " " ) ; let combined_ciphertexts : Vec < miracl :: ECP > = ciphertext . cc . iter ( ) . map ( util :: ecp_from_big_endian_chunks ) . collect ( ) ; assert_eq ! ( crypto verify_sharing ( crypto SharingInstance { g1_gen miracl ECP generator ( ) g2_gen miracl ECP2 generator ( ) public_keys public_coefficients miracl_public_coefficients combined_randomizer util ecp_from_big_endian_chunks ( ciphertext rr ) combined_ciphertexts } sharing_proof ) Ok ( ( ) ) " " ) ; } Ok ( ( ciphertext_from_miracl ( & ciphertext ) , chunking_proof_from_miracl ( & chunking_proof ) , sharing_proof_from_miracl ( & sharing_proof ) , ) ) }
Encrypts several messages to several recipients
Encrypts several messages to several recipients
seed
Randomness
key_message_pairs
&[(FsEncryptionPublicKey, FsEncryptionPlaintext)]
epoch
Epoch
public_coefficients
&PublicCoefficientsBytes
associated_data
&[u8]
seed
Randomness
key_message_pairs
&[(FsEncryptionPublicKey, FsEncryptionPlaintext)]
epoch
Epoch
public_coefficients
&PublicCoefficientsBytes
associated_data
&[u8]
errors
This should never return an error if the protocol is followed.  Every error
should be prevented by the caller validating the arguments beforehand.
This should never return an error if the protocol is followed . Every error should be prevented by the caller validating the arguments beforehand .
panics
If the `enc_chunks` function fails. Though, this truly should never happen
(cf.
If the ` enc_chunks ` function fails . Though this truly should never happen ( cf .