use super::MixOfflineError;
use crate::{
preliminaries::{EPPTableAsContext, PTableTrait, decode_write_ins, factorize},
tally_phase::mix_offline::MixOfflineErrorRepr,
};
use rust_ev_crypto_primitives::{ConstantsTrait, Integer};
pub struct ProcessPlaintextsOutput {
pub l_votes: Vec<Vec<usize>>,
pub l_decoded_votes: Vec<Vec<String>>,
pub l_write_ins: Vec<Vec<String>>,
}
impl ProcessPlaintextsOutput {
pub fn process_plaintexts(
context: &EPPTableAsContext,
plaintext_votes: &[&[Integer]],
) -> Result<Self, MixOfflineError> {
Self::process_plaintexts_impl(context, plaintext_votes).map_err(MixOfflineError)
}
fn process_plaintexts_impl(
context: &EPPTableAsContext,
plaintext_votes: &[&[Integer]],
) -> Result<Self, MixOfflineErrorRepr> {
let upper_n_hat_upper_c = plaintext_votes.len();
if upper_n_hat_upper_c < 2 {
return Err(MixOfflineErrorRepr::ProcessPlaintextsInput(format!(
"N_C={upper_n_hat_upper_c} must be geater than 2"
)));
}
let delta = plaintext_votes[0].len();
if plaintext_votes.iter().any(|m_i| m_i.len() != delta) {
return Err(MixOfflineErrorRepr::ProcessPlaintextsInput(
"Not all vectors of plaintext_votes have the size of delta".to_string(),
));
}
let ones = vec![Integer::one().clone(); delta];
let tau_hat = context
.p_table()
.get_blank_correctness_information()
.map_err(|e| {
MixOfflineErrorRepr::ProcessPlaintextsProcess(format!(
"Electoral model error processing tau_hat: {e:?}",
))
})?;
let mut l_votes = vec![];
let mut l_decoded_votes = vec![];
let mut l_write_ins = vec![];
for m_i in plaintext_votes.iter() {
if m_i != &ones {
let p_hat_k = factorize(context, &m_i[0]).map_err(|e| {
MixOfflineErrorRepr::ProcessPlaintextsProcess(format!(
"Electoral model error facorizing: {e:?}",
))
})?;
let v_hat_k = context
.p_table()
.get_actual_voting_options(&p_hat_k)
.map_err(|e| {
MixOfflineErrorRepr::ProcessPlaintextsProcess(format!(
"Electoral model error getting actual voting options: {e:?}",
))
})?
.iter()
.map(|&s| s.as_str())
.collect::<Vec<_>>();
let tau_prime = context
.p_table()
.get_correctness_information(v_hat_k.as_slice())
.map_err(|e| {
MixOfflineErrorRepr::ProcessPlaintextsProcess(format!(
"Electoral model error getting correctnes information: {e:?}",
))
})?;
if tau_prime != tau_hat {
return Err(MixOfflineErrorRepr::ProcessPlaintextsProcess(
"tau_prime is differant that tau_hat".to_string(),
));
}
let w_k = m_i.iter().skip(1).collect::<Vec<_>>();
let s_hat_k = decode_write_ins(
context.encryption_parameters(),
context
.p_table()
.get_write_in_encoded_voting_options()
.as_slice(),
context
.p_table()
.get_psi()
.map_err(|e| MixOfflineErrorRepr::GetPsi { source: e })?,
context.p_table().get_delta(),
&p_hat_k,
&w_k,
)
.map_err(|e| {
MixOfflineErrorRepr::ProcessPlaintextsProcess(format!(
"Write-in error decoding the write-ins: {e:?}",
))
})?;
l_votes.push(p_hat_k);
l_decoded_votes.push(v_hat_k.iter().map(|s| s.to_string()).collect());
l_write_ins.push(s_hat_k);
}
}
Ok(Self {
l_votes,
l_decoded_votes,
l_write_ins,
})
}
}