use super::{WriteInsError, WriteInsErrorRepr};
use rust_ev_crypto_primitives::{
alphabets::ALPHABET_LATIN, elgamal::EncryptionParameters, ConstantsTrait, Integer,
OperationsTrait,
};
pub fn quadratic_residue_to_write_in(
encryption_parameters: &EncryptionParameters,
y: &Integer,
) -> Result<String, WriteInsError> {
let p = encryption_parameters.p();
let q = encryption_parameters.q();
let mut x = y
.mod_exponentiate(&(Integer::from(p + 1) / 4), p)
.map_err(|e| WriteInsErrorRepr::QuadraticToWriteIns { source: e })?;
if &x > q {
x = p - x;
}
integer_to_write_in(encryption_parameters.q(), &x)
}
fn integer_to_write_in(q: &Integer, x: &Integer) -> Result<String, WriteInsError> {
if x <= Integer::zero() {
return Err(WriteInsError::from(WriteInsErrorRepr::XPositive));
}
let a = ALPHABET_LATIN.size();
let mut x_internal = Integer::from(x % q);
let mut res = String::new();
loop {
if &x_internal == Integer::zero() {
break;
}
let b = x_internal.mod_u(a as u32) as usize;
let c = ALPHABET_LATIN.character_at_pos(b).unwrap();
res.insert(0, c);
x_internal = (x_internal - b) / a;
}
Ok(res)
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
test_data::get_test_data_writeins,
test_json_data::{json_to_encryption_parameters_base64, json_value_to_integer_base64},
};
#[test]
fn test_integer_to_write_in() {
let value = get_test_data_writeins("integer-to-write-in.json");
for tc in value.as_array().unwrap().iter() {
let description = tc["description"].as_str().unwrap();
let q = json_value_to_integer_base64(&tc["context"]["q"]);
let x = json_value_to_integer_base64(&tc["input"]["x"]);
let expected = tc["output"]["output"].as_str().unwrap();
assert_eq!(
integer_to_write_in(&q, &x).unwrap().as_str(),
expected,
"{description}"
)
}
assert!(integer_to_write_in(
&json_value_to_integer_base64(&value[0]["context"]["q"]),
Integer::zero()
)
.is_err())
}
#[test]
fn test_qr_to_write_in() {
let value = get_test_data_writeins("quadratic-residue-to-write-in.json");
for tc in value.as_array().unwrap().iter() {
let description = tc["description"].as_str().unwrap();
let ep = json_to_encryption_parameters_base64(&tc["context"]);
let y = json_value_to_integer_base64(&tc["input"]["y"]);
let expected = tc["output"]["output"].as_str().unwrap();
assert_eq!(
quadratic_residue_to_write_in(&ep, &y).unwrap().as_str(),
expected,
"{description}"
)
}
}
}