mod hadamard_argument;
mod multi_exponentiation_argument;
mod product_argument;
mod shuffle_argument;
mod single_value_product_argument;
mod zero_argument;
use super::commitments::CommitmentKey;
use crate::{
elgamal::EncryptionParameters, integer::ModExponentiateError, ConstantsTrait, Integer,
OperationsTrait,
};
pub use hadamard_argument::{HadamardArgument, HadamardArgumentError};
pub use multi_exponentiation_argument::{
MultiExponentiationArgument, MultiExponentiationArgumentError,
};
pub use product_argument::{ProductArgument, ProductArgumentError};
pub use shuffle_argument::{
verify_shuffle_argument, ShuffleArgument, ShuffleArgumentError, ShuffleArgumentVerifyInput,
ShuffleStatement, VerifyShuffleArgumentResult,
};
pub use single_value_product_argument::{
SingleValueProductArgument, SingleValueProductArgumentError,
};
use std::ops::ControlFlow;
use thiserror::Error;
pub use zero_argument::{ZeroArgument, ZeroArgumentError};
#[derive(Clone, Debug)]
pub struct ArgumentContext<'a> {
ep: &'a EncryptionParameters,
pks: &'a [Integer],
ck: &'a CommitmentKey,
}
#[derive(Error, Debug)]
pub enum StarMapError {
#[error("vectors a and b have not the same size")]
VectorNotSameLen,
#[error("Error calculating y^(j+1) mod p")]
Exp { source: ModExponentiateError },
}
fn star_map(
q: &Integer,
y: &Integer,
a: &[Integer],
b: &[Integer],
) -> Result<Integer, StarMapError> {
if a.len() != b.len() {
return Err(StarMapError::VectorNotSameLen);
}
match a
.iter()
.zip(b.iter())
.enumerate()
.map(|(j, (a_j, b_j))| {
y.mod_exponentiate(&Integer::from(j + 1), q)
.map(|v| a_j.mod_multiply(b_j, q).mod_multiply(&v, q))
.map_err(|e| StarMapError::Exp { source: e })
})
.try_fold(Integer::zero().clone(), |acc, v_res| match v_res {
Ok(v) => ControlFlow::Continue(acc + v),
Err(e) => ControlFlow::Break(e),
}) {
ControlFlow::Continue(v) => Ok(v.modulo(q)),
ControlFlow::Break(e) => Err(e),
}
}
impl<'a> ArgumentContext<'a> {
pub fn new(ep: &'a EncryptionParameters, pks: &'a [Integer], ck: &'a CommitmentKey) -> Self {
Self { ep, pks, ck }
}
}
#[cfg(test)]
mod test_json_data {
use super::*;
use crate::test_json_data::{
json_64_value_to_integer, json_array_64_value_to_array_integer,
json_value_to_encryption_parameters,
};
use serde_json::Value;
pub struct CommitmentKeyValues {
pub h: Integer,
pub gs: Vec<Integer>,
}
pub struct ContextValues {
pub ep: EncryptionParameters,
pub pk: Vec<Integer>,
pub ck: CommitmentKey,
}
impl<'a> From<&'a ContextValues> for ArgumentContext<'a> {
fn from(value: &'a ContextValues) -> Self {
Self {
ep: &value.ep,
pks: &value.pk,
ck: &value.ck,
}
}
}
impl From<&CommitmentKeyValues> for CommitmentKey {
fn from(value: &CommitmentKeyValues) -> Self {
CommitmentKey {
h: value.h.clone(),
gs: value.gs.clone(),
}
}
}
pub fn json_to_commitment_key_values(value: &Value) -> CommitmentKeyValues {
CommitmentKeyValues {
h: json_64_value_to_integer(&value["h"]),
gs: json_array_64_value_to_array_integer(&value["g"]),
}
}
pub fn json_to_commitment_key(value: &Value) -> CommitmentKey {
CommitmentKey::from(&json_to_commitment_key_values(value))
}
pub fn json_to_context_values(value: &Value) -> ContextValues {
ContextValues {
ep: json_value_to_encryption_parameters(value),
pk: json_array_64_value_to_array_integer(&value["pk"]),
ck: json_to_commitment_key(&value["ck"]),
}
}
}
#[cfg(test)]
mod test {
use serde_json::Value;
use crate::{
mix_net::arguments::test_json_data::json_to_context_values,
test_json_data::{
get_test_cases_from_json_file, json_64_value_to_integer,
json_array_64_value_to_array_integer,
},
};
use super::*;
fn get_input(tc: &Value) -> (Integer, Vec<Integer>, Vec<Integer>) {
let input = tc["input"].clone();
(
json_64_value_to_integer(&input["y"]),
json_array_64_value_to_array_integer(&input["a"]),
json_array_64_value_to_array_integer(&input["b"]),
)
}
#[test]
fn test_star_map() {
for tc in get_test_cases_from_json_file("mixnet", "bilinearMap.json").iter() {
let context_values = json_to_context_values(&tc["context"]);
let context = ArgumentContext::from(&context_values);
let (y, a, b) = get_input(tc);
let s_res = star_map(context.ep.q(), &y, &a, &b);
assert!(
s_res.is_ok(),
"Error unwraping {}: {}",
tc["description"],
s_res.unwrap_err()
);
assert_eq!(
s_res.unwrap(),
json_64_value_to_integer(&tc["output"]["value"]),
"{}",
tc["description"]
);
}
}
}