You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

194 lines
6.2 KiB

use crate::crh::{
pedersen::{PedersenCRH, PedersenParameters, PedersenWindow},
FixedLengthCRHGadget,
};
use algebra::{Field, Group};
use r1cs_core::{ConstraintSystem, SynthesisError};
use r1cs_std::prelude::*;
use std::{borrow::Borrow, marker::PhantomData};
#[derive(Derivative)]
#[derivative(Clone(
bound = "G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>"
))]
pub struct PedersenCRHGadgetParameters<
G: Group,
W: PedersenWindow,
ConstraintF: Field,
GG: GroupGadget<G, ConstraintF>,
> {
params: PedersenParameters<G>,
_group_g: PhantomData<GG>,
_engine: PhantomData<ConstraintF>,
_window: PhantomData<W>,
}
pub struct PedersenCRHGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>> {
#[doc(hideen)]
_group: PhantomData<*const G>,
#[doc(hideen)]
_group_gadget: PhantomData<*const GG>,
#[doc(hideen)]
_engine: PhantomData<ConstraintF>,
}
impl<ConstraintF, G, GG, W> FixedLengthCRHGadget<PedersenCRH<G, W>, ConstraintF>
for PedersenCRHGadget<G, ConstraintF, GG>
where
ConstraintF: Field,
G: Group,
GG: GroupGadget<G, ConstraintF>,
W: PedersenWindow,
{
type OutputGadget = GG;
type ParametersGadget = PedersenCRHGadgetParameters<G, W, ConstraintF, GG>;
fn check_evaluation_gadget<CS: ConstraintSystem<ConstraintF>>(
cs: CS,
parameters: &Self::ParametersGadget,
input: &[UInt8],
) -> Result<Self::OutputGadget, SynthesisError> {
let mut padded_input = input.to_vec();
// Pad the input if it is not the current length.
if input.len() * 8 < W::WINDOW_SIZE * W::NUM_WINDOWS {
let current_length = input.len();
for _ in current_length..(W::WINDOW_SIZE * W::NUM_WINDOWS / 8) {
padded_input.push(UInt8::constant(0u8));
}
}
assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
// Allocate new variable for the result.
let input_in_bits: Vec<_> = padded_input
.iter()
.flat_map(|byte| byte.into_bits_le())
.collect();
let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
let result =
GG::precomputed_base_multiscalar_mul(cs, &parameters.params.generators, input_in_bits)?;
Ok(result)
}
}
impl<G: Group, W: PedersenWindow, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>>
AllocGadget<PedersenParameters<G>, ConstraintF>
for PedersenCRHGadgetParameters<G, W, ConstraintF, GG>
{
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(
_cs: CS,
value_gen: F,
) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PedersenParameters<G>>,
{
let params = value_gen()?.borrow().clone();
Ok(PedersenCRHGadgetParameters {
params,
_group_g: PhantomData,
_engine: PhantomData,
_window: PhantomData,
})
}
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
_cs: CS,
value_gen: F,
) -> Result<Self, SynthesisError>
where
F: FnOnce() -> Result<T, SynthesisError>,
T: Borrow<PedersenParameters<G>>,
{
let params = value_gen()?.borrow().clone();
Ok(PedersenCRHGadgetParameters {
params,
_group_g: PhantomData,
_engine: PhantomData,
_window: PhantomData,
})
}
}
#[cfg(test)]
mod test {
use algebra::fields::bls12_381::fr::Fr;
use rand::{thread_rng, Rng};
use crate::crh::{
pedersen::{constraints::PedersenCRHGadget, PedersenCRH, PedersenWindow},
FixedLengthCRH, FixedLengthCRHGadget,
};
use algebra::curves::{jubjub::JubJubProjective as JubJub, ProjectiveCurve};
use r1cs_core::ConstraintSystem;
use r1cs_std::{
groups::curves::twisted_edwards::jubjub::JubJubGadget, prelude::*,
test_constraint_system::TestConstraintSystem,
};
type TestCRH = PedersenCRH<JubJub, Window>;
type TestCRHGadget = PedersenCRHGadget<JubJub, Fr, JubJubGadget>;
#[derive(Clone, PartialEq, Eq, Hash)]
pub(super) struct Window;
impl PedersenWindow for Window {
const WINDOW_SIZE: usize = 128;
const NUM_WINDOWS: usize = 8;
}
fn generate_input<CS: ConstraintSystem<Fr>, R: Rng>(
mut cs: CS,
rng: &mut R,
) -> ([u8; 128], Vec<UInt8>) {
let mut input = [1u8; 128];
rng.fill_bytes(&mut input);
let mut input_bytes = vec![];
for (byte_i, input_byte) in input.into_iter().enumerate() {
let cs = cs.ns(|| format!("input_byte_gadget_{}", byte_i));
input_bytes.push(UInt8::alloc(cs, || Ok(*input_byte)).unwrap());
}
(input, input_bytes)
}
#[test]
fn crh_primitive_gadget_test() {
let rng = &mut thread_rng();
let mut cs = TestConstraintSystem::<Fr>::new();
let (input, input_bytes) = generate_input(&mut cs, rng);
println!("number of constraints for input: {}", cs.num_constraints());
let parameters = TestCRH::setup(rng).unwrap();
let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
let gadget_parameters =
<TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersGadget::alloc(
&mut cs.ns(|| "gadget_parameters"),
|| Ok(&parameters),
)
.unwrap();
println!(
"number of constraints for input + params: {}",
cs.num_constraints()
);
let gadget_result =
<TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::check_evaluation_gadget(
&mut cs.ns(|| "gadget_evaluation"),
&gadget_parameters,
&input_bytes,
)
.unwrap();
println!("number of constraints total: {}", cs.num_constraints());
let primitive_result = primitive_result.into_affine();
assert_eq!(primitive_result.x, gadget_result.x.value.unwrap());
assert_eq!(primitive_result.y, gadget_result.y.value.unwrap());
assert!(cs.is_satisfied());
}
}