#[cfg(feature = "experimental")]
use crate::dp::DifferentialPrivacyStrategy;
use crate::field::{FieldElement, FieldElementWithInteger, FieldError, NttFriendlyFieldElement};
use crate::fp::log2;
use crate::ntt::{ntt, ntt_inv_finish, NttError};
use crate::polynomial::poly_eval;
use std::any::Any;
use std::convert::TryFrom;
use std::fmt::Debug;
pub mod gadgets;
pub mod types;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum FlpError {
#[error("prove error: {0}")]
Prove(String),
#[error("query error: {0}")]
Query(String),
#[error("decide error: {0}")]
Decide(String),
#[error("gadget error: {0}")]
Gadget(String),
#[error("validity circuit error: {0}")]
Valid(String),
#[error("value error: {0}")]
Encode(String),
#[error("value error: {0}")]
Decode(String),
#[error("truncate error: {0}")]
Truncate(String),
#[error("invalid paramter: {0}")]
InvalidParameter(String),
#[error("NTT error: {0}")]
Ntt(#[from] NttError),
#[error("Field error: {0}")]
Field(#[from] FieldError),
#[cfg(feature = "experimental")]
#[error("differential privacy error: {0}")]
DifferentialPrivacy(#[from] crate::dp::DpError),
}
pub trait Flp: Sized + Eq + Clone + Debug {
type Field: NttFriendlyFieldElement;
fn gadget(&self) -> Vec<Box<dyn Gadget<Self::Field>>>;
fn num_gadgets(&self) -> usize;
fn valid(
&self,
gadgets: &mut Vec<Box<dyn Gadget<Self::Field>>>,
input: &[Self::Field],
joint_rand: &[Self::Field],
num_shares: usize,
) -> Result<Vec<Self::Field>, FlpError>;
fn input_len(&self) -> usize;
fn proof_len(&self) -> usize;
fn verifier_len(&self) -> usize;
fn joint_rand_len(&self) -> usize;
fn eval_output_len(&self) -> usize;
fn prove_rand_len(&self) -> usize;
fn query_rand_len(&self) -> usize {
let mut n = self.num_gadgets();
let eval_elems = self.eval_output_len();
if eval_elems > 1 {
n += eval_elems;
}
n
}
fn prove(
&self,
input: &[Self::Field],
prove_rand: &[Self::Field],
joint_rand: &[Self::Field],
) -> Result<Vec<Self::Field>, FlpError> {
if input.len() != self.input_len() {
return Err(FlpError::Prove(format!(
"unexpected input length: got {}; want {}",
input.len(),
self.input_len()
)));
}
if prove_rand.len() != self.prove_rand_len() {
return Err(FlpError::Prove(format!(
"unexpected prove randomness length: got {}; want {}",
prove_rand.len(),
self.prove_rand_len()
)));
}
if joint_rand.len() != self.joint_rand_len() {
return Err(FlpError::Prove(format!(
"unexpected joint randomness length: got {}; want {}",
joint_rand.len(),
self.joint_rand_len()
)));
}
let mut prove_rand_len = 0;
let mut shims = self
.gadget()
.into_iter()
.map(|inner| {
let inner_arity = inner.arity();
if prove_rand_len + inner_arity > prove_rand.len() {
return Err(FlpError::Prove(format!(
"short prove randomness: got {}; want at least {}",
prove_rand.len(),
prove_rand_len + inner_arity
)));
}
let gadget = Box::new(ProveShimGadget::new(
inner,
&prove_rand[prove_rand_len..prove_rand_len + inner_arity],
)?) as Box<dyn Gadget<Self::Field>>;
prove_rand_len += inner_arity;
Ok(gadget)
})
.collect::<Result<Vec<_>, FlpError>>()?;
assert_eq!(prove_rand_len, self.prove_rand_len());
let data_len = shims
.iter()
.map(|shim| {
let gadget_poly_len = gadget_poly_len(shim.degree(), wire_poly_len(shim.calls()));
shim.arity() + gadget_poly_len.next_power_of_two()
})
.sum();
let mut proof = vec![Self::Field::zero(); data_len];
let _ = self.valid(&mut shims, input, joint_rand, 1)?;
let mut proof_len = 0;
for shim in shims.iter_mut() {
let gadget = shim
.as_any()
.downcast_mut::<ProveShimGadget<Self::Field>>()
.unwrap();
let m = wire_poly_len(gadget.calls());
let m_inv = Self::Field::from(
<Self::Field as FieldElementWithInteger>::Integer::try_from(m).unwrap(),
)
.inv();
let mut f = vec![vec![Self::Field::zero(); m]; gadget.arity()];
for ((coefficients, values), proof_val) in f[..gadget.arity()]
.iter_mut()
.zip(gadget.f_vals[..gadget.arity()].iter())
.zip(proof[proof_len..proof_len + gadget.arity()].iter_mut())
{
ntt(coefficients, values, m)?;
ntt_inv_finish(coefficients, m, m_inv);
*proof_val = values[0];
}
let gadget_poly_len = gadget_poly_len(gadget.degree(), m);
let start = proof_len + gadget.arity();
let end = start + gadget_poly_len.next_power_of_two();
gadget.call_poly(&mut proof[start..end], &f)?;
proof_len += gadget.arity() + gadget_poly_len;
}
assert_eq!(proof_len, self.proof_len());
proof.truncate(proof_len);
Ok(proof)
}
fn query(
&self,
input: &[Self::Field],
proof: &[Self::Field],
query_rand: &[Self::Field],
joint_rand: &[Self::Field],
num_shares: usize,
) -> Result<Vec<Self::Field>, FlpError> {
if input.len() != self.input_len() {
return Err(FlpError::Query(format!(
"unexpected input length: got {}; want {}",
input.len(),
self.input_len()
)));
}
if proof.len() != self.proof_len() {
return Err(FlpError::Query(format!(
"unexpected proof length: got {}; want {}",
proof.len(),
self.proof_len()
)));
}
if query_rand.len() != self.query_rand_len() {
return Err(FlpError::Query(format!(
"unexpected query randomness length: got {}; want {}",
query_rand.len(),
self.query_rand_len()
)));
}
let (query_rand_for_validity, query_rand_for_gadgets) = if self.eval_output_len() > 1 {
query_rand.split_at(self.eval_output_len())
} else {
query_rand.split_at(0)
};
let my_gadgets = self.gadget();
if query_rand_for_gadgets.len() != my_gadgets.len() {
return Err(FlpError::Query(format!(
"length of query randomness for gadgets doesn't match number of gadgets: \
got {}; want {}",
query_rand_for_gadgets.len(),
my_gadgets.len()
)));
}
if joint_rand.len() != self.joint_rand_len() {
return Err(FlpError::Query(format!(
"unexpected joint randomness length: got {}; want {}",
joint_rand.len(),
self.joint_rand_len()
)));
}
let mut proof_len = 0;
let mut shims = my_gadgets
.into_iter()
.zip(query_rand_for_gadgets)
.map(|(gadget, &r)| {
let gadget_degree = gadget.degree();
let gadget_arity = gadget.arity();
let m = (1 + gadget.calls()).next_power_of_two();
if r.pow(<Self::Field as FieldElementWithInteger>::Integer::try_from(m).unwrap())
== Self::Field::one()
{
return Err(FlpError::Query(format!(
"invalid query randomness: encountered 2^{m}-th root of unity"
)));
}
let next_len = gadget_arity + gadget_degree * (m - 1) + 1;
let proof_data = &proof[proof_len..proof_len + next_len];
proof_len += next_len;
Ok(Box::new(QueryShimGadget::new(gadget, r, proof_data)?)
as Box<dyn Gadget<Self::Field>>)
})
.collect::<Result<Vec<_>, _>>()?;
let data_len = 1 + shims.iter().map(|shim| shim.arity() + 1).sum::<usize>();
let mut verifier = Vec::with_capacity(data_len);
let validity = self.valid(&mut shims, input, joint_rand, num_shares)?;
assert_eq!(validity.len(), self.eval_output_len());
let check = if validity.len() > 1 {
validity
.iter()
.zip(query_rand_for_validity)
.fold(Self::Field::zero(), |acc, (&val, &r)| acc + r * val)
} else {
validity.first().cloned().unwrap_or(Self::Field::zero())
};
verifier.push(check);
for (query_rand_val, shim) in query_rand_for_gadgets.iter().zip(shims.iter_mut()) {
let gadget = shim
.as_any()
.downcast_ref::<QueryShimGadget<Self::Field>>()
.unwrap();
let m = (1 + gadget.calls()).next_power_of_two();
let m_inv = Self::Field::from(
<Self::Field as FieldElementWithInteger>::Integer::try_from(m).unwrap(),
)
.inv();
let mut f = vec![Self::Field::zero(); m];
for wire in 0..gadget.arity() {
ntt(&mut f, &gadget.f_vals[wire], m)?;
ntt_inv_finish(&mut f, m, m_inv);
verifier.push(poly_eval(&f, *query_rand_val));
}
verifier.push(gadget.p_at_r);
}
assert_eq!(verifier.len(), self.verifier_len());
Ok(verifier)
}
fn decide(&self, verifier: &[Self::Field]) -> Result<bool, FlpError> {
if verifier.len() != self.verifier_len() {
return Err(FlpError::Decide(format!(
"unexpected verifier length: got {}; want {}",
verifier.len(),
self.verifier_len()
)));
}
if verifier[0] != Self::Field::zero() {
return Ok(false);
}
let mut gadgets = self.gadget();
let mut verifier_len = 1;
for gadget in gadgets.iter_mut() {
let next_len = 1 + gadget.arity();
let e = gadget.call(&verifier[verifier_len..verifier_len + next_len - 1])?;
if e != verifier[verifier_len + next_len - 1] {
return Ok(false);
}
verifier_len += next_len;
}
Ok(true)
}
fn valid_call_check(
&self,
input: &[Self::Field],
joint_rand: &[Self::Field],
) -> Result<(), FlpError> {
if input.len() != self.input_len() {
return Err(FlpError::Valid(format!(
"unexpected input length: got {}; want {}",
input.len(),
self.input_len(),
)));
}
if joint_rand.len() != self.joint_rand_len() {
return Err(FlpError::Valid(format!(
"unexpected joint randomness length: got {}; want {}",
joint_rand.len(),
self.joint_rand_len()
)));
}
Ok(())
}
fn truncate_call_check(&self, input: &[Self::Field]) -> Result<(), FlpError> {
if input.len() != self.input_len() {
return Err(FlpError::Truncate(format!(
"Unexpected input length: got {}; want {}",
input.len(),
self.input_len()
)));
}
Ok(())
}
}
pub trait Type: Flp {
type Measurement: Clone + Debug;
type AggregateResult: Clone + Debug;
fn encode_measurement(
&self,
measurement: &Self::Measurement,
) -> Result<Vec<Self::Field>, FlpError>;
fn truncate(&self, input: Vec<Self::Field>) -> Result<Vec<Self::Field>, FlpError>;
fn decode_result(
&self,
data: &[Self::Field],
num_measurements: usize,
) -> Result<Self::AggregateResult, FlpError>;
fn output_len(&self) -> usize;
}
#[cfg(feature = "experimental")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub trait TypeWithNoise<S>: Type
where
S: DifferentialPrivacyStrategy,
{
fn add_noise_to_result(
&self,
dp_strategy: &S,
agg_result: &mut [Self::Field],
num_measurements: usize,
) -> Result<(), FlpError>;
}
pub trait Gadget<F: NttFriendlyFieldElement>: Debug {
fn call(&mut self, inp: &[F]) -> Result<F, FlpError>;
fn call_poly(&mut self, outp: &mut [F], inp: &[Vec<F>]) -> Result<(), FlpError>;
fn arity(&self) -> usize;
fn degree(&self) -> usize;
fn calls(&self) -> usize;
fn as_any(&mut self) -> &mut dyn Any;
}
#[derive(Debug)]
struct ProveShimGadget<F: NttFriendlyFieldElement> {
inner: Box<dyn Gadget<F>>,
f_vals: Vec<Vec<F>>,
ct: usize,
}
impl<F: NttFriendlyFieldElement> ProveShimGadget<F> {
fn new(inner: Box<dyn Gadget<F>>, prove_rand: &[F]) -> Result<Self, FlpError> {
let mut f_vals = vec![vec![F::zero(); 1 + inner.calls()]; inner.arity()];
for (prove_rand_val, wire_poly_vals) in
prove_rand[..f_vals.len()].iter().zip(f_vals.iter_mut())
{
wire_poly_vals[0] = *prove_rand_val;
}
Ok(Self {
inner,
f_vals,
ct: 1,
})
}
}
impl<F: NttFriendlyFieldElement> Gadget<F> for ProveShimGadget<F> {
fn call(&mut self, inp: &[F]) -> Result<F, FlpError> {
for (wire_poly_vals, inp_val) in self.f_vals[..inp.len()].iter_mut().zip(inp.iter()) {
wire_poly_vals[self.ct] = *inp_val;
}
self.ct += 1;
self.inner.call(inp)
}
fn call_poly(&mut self, outp: &mut [F], inp: &[Vec<F>]) -> Result<(), FlpError> {
self.inner.call_poly(outp, inp)
}
fn arity(&self) -> usize {
self.inner.arity()
}
fn degree(&self) -> usize {
self.inner.degree()
}
fn calls(&self) -> usize {
self.inner.calls()
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
#[derive(Debug)]
struct QueryShimGadget<F: NttFriendlyFieldElement> {
inner: Box<dyn Gadget<F>>,
f_vals: Vec<Vec<F>>,
p_vals: Vec<F>,
p_at_r: F,
step: usize,
ct: usize,
}
impl<F: NttFriendlyFieldElement> QueryShimGadget<F> {
fn new(inner: Box<dyn Gadget<F>>, r: F, proof_data: &[F]) -> Result<Self, FlpError> {
let gadget_degree = inner.degree();
let gadget_arity = inner.arity();
let m = (1 + inner.calls()).next_power_of_two();
let p = m * gadget_degree;
let mut f_vals = vec![vec![F::zero(); 1 + inner.calls()]; gadget_arity];
for wire in 0..gadget_arity {
f_vals[wire][0] = proof_data[wire];
}
let size = p.next_power_of_two();
let mut p_vals = vec![F::zero(); size];
ntt(&mut p_vals, &proof_data[gadget_arity..], size)?;
let step = (1 << (log2(p as u128) - log2(m as u128))) as usize;
let p_at_r = poly_eval(&proof_data[gadget_arity..], r);
Ok(Self {
inner,
f_vals,
p_vals,
p_at_r,
step,
ct: 1,
})
}
}
impl<F: NttFriendlyFieldElement> Gadget<F> for QueryShimGadget<F> {
fn call(&mut self, inp: &[F]) -> Result<F, FlpError> {
for (wire_poly_vals, inp_val) in self.f_vals[..inp.len()].iter_mut().zip(inp.iter()) {
wire_poly_vals[self.ct] = *inp_val;
}
let outp = self.p_vals[self.ct * self.step];
self.ct += 1;
Ok(outp)
}
fn call_poly(&mut self, _outp: &mut [F], _inp: &[Vec<F>]) -> Result<(), FlpError> {
panic!("no-op");
}
fn arity(&self) -> usize {
self.inner.arity()
}
fn degree(&self) -> usize {
self.inner.degree()
}
fn calls(&self) -> usize {
self.inner.calls()
}
fn as_any(&mut self) -> &mut dyn Any {
self
}
}
#[inline]
pub(crate) fn wire_poly_len(num_calls: usize) -> usize {
(1 + num_calls).next_power_of_two()
}
#[inline]
pub(crate) fn gadget_poly_len(gadget_degree: usize, wire_poly_len: usize) -> usize {
gadget_degree * (wire_poly_len - 1) + 1
}
#[cfg(feature = "test-util")]
#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
pub mod test_utils {
use super::*;
use crate::field::{add_vector, sub_assign_vector, FieldElement, FieldElementWithInteger};
#[cfg_attr(docsrs, doc(cfg(feature = "test-util")))]
pub struct TypeTest<'a, T: Type> {
pub flp: &'a T,
pub name: Option<&'a str>,
pub input: &'a [T::Field],
pub expected_output: Option<&'a [T::Field]>,
pub expect_valid: bool,
}
impl<T: Type> TypeTest<'_, T> {
pub fn expect_valid<const SHARES: usize>(
flp: &T,
input: &[T::Field],
expected_output: &[T::Field],
) {
TypeTest {
flp,
name: None,
input,
expected_output: Some(expected_output),
expect_valid: true,
}
.run::<SHARES>()
}
pub fn expect_invalid<const SHARES: usize>(flp: &T, input: &[T::Field]) {
TypeTest {
flp,
name: None,
input,
expect_valid: false,
expected_output: None,
}
.run::<SHARES>()
}
pub fn expect_valid_no_output<const SHARES: usize>(flp: &T, input: &[T::Field]) {
TypeTest {
flp,
name: None,
input,
expect_valid: true,
expected_output: None,
}
.run::<SHARES>()
}
pub fn run<const SHARES: usize>(&self) {
let name = self.name.unwrap_or("unnamed test");
assert_eq!(
self.input.len(),
self.flp.input_len(),
"{name}: unexpected input length"
);
let mut gadgets = self.flp.gadget();
let joint_rand = T::Field::random_vector(self.flp.joint_rand_len());
let prove_rand = T::Field::random_vector(self.flp.prove_rand_len());
let query_rand = T::Field::random_vector(self.flp.query_rand_len());
assert_eq!(
self.flp.joint_rand_len(),
joint_rand.len(),
"{name}: unexpected joint rand length"
);
assert_eq!(
self.flp.prove_rand_len(),
prove_rand.len(),
"{name}: unexpected prove rand length",
);
assert_eq!(
self.flp.query_rand_len(),
query_rand.len(),
"{name}: unexpected query rand length",
);
let v = self
.flp
.valid(&mut gadgets, self.input, &joint_rand, 1)
.unwrap();
assert_eq!(
v.iter().all(|f| f == &T::Field::zero()),
self.expect_valid,
"{name}: unexpected output of valid() returned {v:?}",
);
let proof = self
.flp
.prove(self.input, &prove_rand, &joint_rand)
.unwrap();
assert_eq!(
proof.len(),
self.flp.proof_len(),
"{name}: unexpected proof length"
);
let verifier = self
.flp
.query(self.input, &proof, &query_rand, &joint_rand, 1)
.unwrap();
assert_eq!(
verifier.len(),
self.flp.verifier_len(),
"{name}: unexpected verifier length"
);
let res = self.flp.decide(&verifier).unwrap();
assert_eq!(res, self.expect_valid, "{name}: unexpected decision");
let input_shares = split_vector::<_, SHARES>(self.input);
let proof_shares = split_vector::<_, SHARES>(&proof);
let verifier: Vec<T::Field> = (0..SHARES)
.map(|i| {
self.flp
.query(
&input_shares[i],
&proof_shares[i],
&query_rand,
&joint_rand,
SHARES,
)
.unwrap()
})
.reduce(add_vector)
.unwrap();
let res = self.flp.decide(&verifier).unwrap();
assert_eq!(
res, self.expect_valid,
"{name}: unexpected distributed decision"
);
for i in 0..std::cmp::min(proof.len(), 10) {
let mut mutated_proof = proof.clone();
mutated_proof[i] *= T::Field::from(
<T::Field as FieldElementWithInteger>::Integer::try_from(23).unwrap(),
);
let verifier = self
.flp
.query(self.input, &mutated_proof, &query_rand, &joint_rand, 1)
.unwrap();
assert!(
!self.flp.decide(&verifier).unwrap(),
"{name}: proof mutant {} deemed valid",
i
);
}
if let Some(ref expected_output) = self.expected_output {
let output = self.flp.truncate(self.input.to_vec()).unwrap();
assert_eq!(
output.len(),
self.flp.output_len(),
"{name}: unexpected output length of truncate()"
);
assert_eq!(
&output, expected_output,
"{name}: unexpected output of truncate()"
);
}
}
}
fn split_vector<F: FieldElement, const SHARES: usize>(inp: &[F]) -> [Vec<F>; SHARES] {
let mut outp = Vec::with_capacity(SHARES);
outp.push(inp.to_vec());
for _ in 1..SHARES {
let share = F::random_vector(inp.len());
sub_assign_vector(&mut outp[0], share.iter().copied());
outp.push(share);
}
outp.try_into().unwrap()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::field::{add_vector, split_vector, Field128};
use crate::flp::gadgets::{Mul, PolyEval};
use crate::polynomial::poly_range_check;
use std::marker::PhantomData;
#[test]
fn test_flp() {
const NUM_SHARES: usize = 2;
let typ: TestType<Field128> = TestType::new();
let input = typ.encode_measurement(&3).unwrap();
assert_eq!(input.len(), typ.input_len());
let input_shares: Vec<Vec<Field128>> = split_vector(input.as_slice(), NUM_SHARES)
.into_iter()
.collect();
let joint_rand = Field128::random_vector(typ.joint_rand_len());
let prove_rand = Field128::random_vector(typ.prove_rand_len());
let query_rand = Field128::random_vector(typ.query_rand_len());
let proof = typ.prove(&input, &prove_rand, &joint_rand).unwrap();
assert_eq!(proof.len(), typ.proof_len());
let proof_shares: Vec<Vec<Field128>> =
split_vector(&proof, NUM_SHARES).into_iter().collect();
let verifier: Vec<Field128> = (0..NUM_SHARES)
.map(|i| {
typ.query(
&input_shares[i],
&proof_shares[i],
&query_rand,
&joint_rand,
NUM_SHARES,
)
.unwrap()
})
.reduce(add_vector)
.unwrap();
assert_eq!(verifier.len(), typ.verifier_len());
assert!(typ.decide(&verifier).unwrap());
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct TestType<F>(PhantomData<F>);
impl<F> TestType<F> {
fn new() -> Self {
Self(PhantomData)
}
}
impl<F: NttFriendlyFieldElement> Flp for TestType<F> {
type Field = F;
fn valid(
&self,
g: &mut Vec<Box<dyn Gadget<F>>>,
input: &[F],
joint_rand: &[F],
_num_shares: usize,
) -> Result<Vec<F>, FlpError> {
let r = joint_rand[0];
let mut res = F::zero();
let mut inp = [input[0], input[0]];
inp[0] = g[0].call(&inp)?;
inp[0] = g[0].call(&inp)?;
let x3_diff = inp[0] - input[1];
res += r * x3_diff;
let x_checked = g[1].call(&[input[0]])?;
res += (r * r) * x_checked;
Ok(vec![res])
}
fn input_len(&self) -> usize {
2
}
fn proof_len(&self) -> usize {
let mul = 2 + 2 * (
(1 + 2_usize ).next_power_of_two() - 1) + 1;
let poly = 1 + 3 * (
(1 + 1_usize ).next_power_of_two() - 1) + 1;
mul + poly
}
fn verifier_len(&self) -> usize {
let mul = 1 + 2 ;
let poly = 1 + 1 ;
1 + mul + poly
}
fn joint_rand_len(&self) -> usize {
1
}
fn eval_output_len(&self) -> usize {
1
}
fn prove_rand_len(&self) -> usize {
3
}
fn gadget(&self) -> Vec<Box<dyn Gadget<F>>> {
vec![
Box::new(Mul::new(2)),
Box::new(PolyEval::new(poly_range_check(2, 5), 1)),
]
}
fn num_gadgets(&self) -> usize {
2
}
}
impl<F: NttFriendlyFieldElement> Type for TestType<F> {
type Measurement = F::Integer;
type AggregateResult = F::Integer;
fn encode_measurement(&self, measurement: &F::Integer) -> Result<Vec<F>, FlpError> {
Ok(vec![
F::from(*measurement),
F::from(*measurement).pow(F::Integer::try_from(3).unwrap()),
])
}
fn truncate(&self, input: Vec<F>) -> Result<Vec<F>, FlpError> {
Ok(input)
}
fn decode_result(
&self,
_data: &[F],
_num_measurements: usize,
) -> Result<F::Integer, FlpError> {
panic!("not implemented");
}
fn output_len(&self) -> usize {
self.input_len()
}
}
#[test]
fn issue254() {
let typ: Issue254Type<Field128> = Issue254Type::new();
let input = typ.encode_measurement(&0).unwrap();
assert_eq!(input.len(), typ.input_len());
let joint_rand = Field128::random_vector(typ.joint_rand_len());
let prove_rand = Field128::random_vector(typ.prove_rand_len());
let query_rand = Field128::random_vector(typ.query_rand_len());
let proof = typ.prove(&input, &prove_rand, &joint_rand).unwrap();
let verifier = typ
.query(&input, &proof, &query_rand, &joint_rand, 1)
.unwrap();
assert_eq!(verifier.len(), typ.verifier_len());
assert!(typ.decide(&verifier).unwrap());
}
#[derive(Clone, Debug, PartialEq, Eq)]
struct Issue254Type<F> {
num_gadget_calls: [usize; 2],
phantom: PhantomData<F>,
}
impl<F> Issue254Type<F> {
fn new() -> Self {
Self {
num_gadget_calls: [100, 0],
phantom: PhantomData,
}
}
}
impl<F: NttFriendlyFieldElement> Flp for Issue254Type<F> {
type Field = F;
fn valid(
&self,
g: &mut Vec<Box<dyn Gadget<F>>>,
input: &[F],
_joint_rand: &[F],
_num_shares: usize,
) -> Result<Vec<F>, FlpError> {
let mut res = F::zero();
for _ in 0..self.num_gadget_calls[0] {
res += g[0].call(&[input[0]])?;
}
for _ in 0..self.num_gadget_calls[1] {
res += g[1].call(&[input[0]])?;
}
Ok(vec![res])
}
fn input_len(&self) -> usize {
1
}
fn proof_len(&self) -> usize {
let first = 1 + 2 * (
(1 + self.num_gadget_calls[0]).next_power_of_two() - 1) + 1;
let second = 1 + 2 * (
(1 + self.num_gadget_calls[1]).next_power_of_two() - 1) + 1;
first + second
}
fn verifier_len(&self) -> usize {
let first = 1 + 1 ;
let second = 1 + 1 ;
1 + first + second
}
fn joint_rand_len(&self) -> usize {
0
}
fn eval_output_len(&self) -> usize {
1
}
fn prove_rand_len(&self) -> usize {
let first = 1;
let second = 1;
first + second
}
fn gadget(&self) -> Vec<Box<dyn Gadget<F>>> {
let poly = poly_range_check(0, 2); vec![
Box::new(PolyEval::new(poly.clone(), self.num_gadget_calls[0])),
Box::new(PolyEval::new(poly, self.num_gadget_calls[1])),
]
}
fn num_gadgets(&self) -> usize {
2
}
}
impl<F: NttFriendlyFieldElement> Type for Issue254Type<F> {
type Measurement = F::Integer;
type AggregateResult = F::Integer;
fn encode_measurement(&self, measurement: &F::Integer) -> Result<Vec<F>, FlpError> {
Ok(vec![F::from(*measurement)])
}
fn truncate(&self, input: Vec<F>) -> Result<Vec<F>, FlpError> {
Ok(input)
}
fn decode_result(
&self,
_data: &[F],
_num_measurements: usize,
) -> Result<F::Integer, FlpError> {
panic!("not implemented");
}
fn output_len(&self) -> usize {
self.input_len()
}
}
}