mirror of
https://github.com/arnaucube/ark-r1cs-std.git
synced 2026-01-12 00:41:32 +01:00
Initial commit to extract crypto-primitives to new crate
This commit is contained in:
169
crypto-primitives/src/commitment/blake2s/constraints.rs
Normal file
169
crypto-primitives/src/commitment/blake2s/constraints.rs
Normal file
@@ -0,0 +1,169 @@
|
||||
use crate::crypto_primitives::commitment::blake2s::Blake2sCommitment;
|
||||
use r1cs_core::{ConstraintSystem, SynthesisError};
|
||||
|
||||
use crate::gadgets::{
|
||||
prf::blake2s::{blake2s_gadget, Blake2sOutputGadget},
|
||||
CommitmentGadget,
|
||||
};
|
||||
use algebra::{PrimeField, Field};
|
||||
use r1cs_std::prelude::*;
|
||||
|
||||
use std::borrow::Borrow;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Blake2sParametersGadget;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Blake2sRandomnessGadget(pub Vec<UInt8>);
|
||||
|
||||
pub struct Blake2sCommitmentGadget;
|
||||
|
||||
impl<ConstraintF: PrimeField> CommitmentGadget<Blake2sCommitment, ConstraintF> for Blake2sCommitmentGadget {
|
||||
type OutputGadget = Blake2sOutputGadget;
|
||||
type ParametersGadget = Blake2sParametersGadget;
|
||||
type RandomnessGadget = Blake2sRandomnessGadget;
|
||||
|
||||
fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
_: &Self::ParametersGadget,
|
||||
input: &[UInt8],
|
||||
r: &Self::RandomnessGadget,
|
||||
) -> Result<Self::OutputGadget, SynthesisError> {
|
||||
let mut input_bits = Vec::with_capacity(512);
|
||||
for byte in input.into_iter().chain(r.0.iter()) {
|
||||
input_bits.extend_from_slice(&byte.into_bits_le());
|
||||
}
|
||||
let mut result = Vec::new();
|
||||
for (i, int) in blake2s_gadget(cs.ns(|| "Blake2s Eval"), &input_bits)?
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
{
|
||||
let chunk = int.to_bytes(&mut cs.ns(|| format!("Result ToBytes {}", i)))?;
|
||||
result.extend_from_slice(&chunk);
|
||||
}
|
||||
Ok(Blake2sOutputGadget(result))
|
||||
}
|
||||
}
|
||||
|
||||
impl<ConstraintF: Field> AllocGadget<(), ConstraintF> for Blake2sParametersGadget {
|
||||
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(_: CS, _: F) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<()>,
|
||||
{
|
||||
Ok(Blake2sParametersGadget)
|
||||
}
|
||||
|
||||
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(_: CS, _: F) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<()>,
|
||||
{
|
||||
Ok(Blake2sParametersGadget)
|
||||
}
|
||||
}
|
||||
|
||||
impl<ConstraintF: PrimeField> AllocGadget<[u8; 32], ConstraintF> for Blake2sRandomnessGadget {
|
||||
#[inline]
|
||||
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, value_gen: F) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<[u8; 32]>,
|
||||
{
|
||||
let zeros = [0u8; 32];
|
||||
let value = match value_gen() {
|
||||
Ok(val) => *(val.borrow()),
|
||||
Err(_) => zeros,
|
||||
};
|
||||
let bytes = <UInt8>::alloc_vec(cs, &value)?;
|
||||
|
||||
Ok(Blake2sRandomnessGadget(bytes))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
|
||||
cs: CS,
|
||||
value_gen: F,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<[u8; 32]>,
|
||||
{
|
||||
let zeros = [0u8; 32];
|
||||
let value = match value_gen() {
|
||||
Ok(val) => *(val.borrow()),
|
||||
Err(_) => zeros,
|
||||
};
|
||||
let bytes = <UInt8>::alloc_input_vec(cs, &value)?;
|
||||
|
||||
Ok(Blake2sRandomnessGadget(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use algebra::fields::bls12_381::Fr;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
use crate::{
|
||||
crypto_primitives::commitment::{blake2s::Blake2sCommitment, CommitmentScheme},
|
||||
gadgets::commitment::{
|
||||
blake2s::{Blake2sCommitmentGadget, Blake2sRandomnessGadget},
|
||||
CommitmentGadget,
|
||||
},
|
||||
};
|
||||
use r1cs_core::ConstraintSystem;
|
||||
use r1cs_std::prelude::*;
|
||||
use r1cs_std::test_constraint_system::TestConstraintSystem;
|
||||
|
||||
#[test]
|
||||
fn commitment_gadget_test() {
|
||||
let mut cs = TestConstraintSystem::<Fr>::new();
|
||||
|
||||
let input = [1u8; 32];
|
||||
|
||||
let rng = &mut thread_rng();
|
||||
|
||||
type TestCOMM = Blake2sCommitment;
|
||||
type TestCOMMGadget = Blake2sCommitmentGadget;
|
||||
|
||||
let mut randomness = [0u8; 32];
|
||||
rng.fill(&mut randomness);
|
||||
|
||||
let parameters = ();
|
||||
let primitive_result = Blake2sCommitment::commit(¶meters, &input, &randomness).unwrap();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
let mut randomness_bytes = vec![];
|
||||
for (byte_i, random_byte) in randomness.into_iter().enumerate() {
|
||||
let cs = cs.ns(|| format!("randomness_byte_gadget_{}", byte_i));
|
||||
randomness_bytes.push(UInt8::alloc(cs, || Ok(*random_byte)).unwrap());
|
||||
}
|
||||
let randomness_bytes = Blake2sRandomnessGadget(randomness_bytes);
|
||||
|
||||
let gadget_parameters =
|
||||
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersGadget::alloc(
|
||||
&mut cs.ns(|| "gadget_parameters"),
|
||||
|| Ok(¶meters),
|
||||
)
|
||||
.unwrap();
|
||||
let gadget_result =
|
||||
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::check_commitment_gadget(
|
||||
&mut cs.ns(|| "gadget_evaluation"),
|
||||
&gadget_parameters,
|
||||
&input_bytes,
|
||||
&randomness_bytes,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
for i in 0..32 {
|
||||
assert_eq!(primitive_result[i], gadget_result.0[i].get_value().unwrap());
|
||||
}
|
||||
assert!(cs.is_satisfied());
|
||||
}
|
||||
}
|
||||
30
crypto-primitives/src/commitment/blake2s/mod.rs
Normal file
30
crypto-primitives/src/commitment/blake2s/mod.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use super::CommitmentScheme;
|
||||
use blake2::Blake2s as b2s;
|
||||
use digest::Digest;
|
||||
use crate::Error;
|
||||
use rand::Rng;
|
||||
|
||||
pub struct Blake2sCommitment;
|
||||
|
||||
impl CommitmentScheme for Blake2sCommitment {
|
||||
type Parameters = ();
|
||||
type Randomness = [u8; 32];
|
||||
type Output = [u8; 32];
|
||||
|
||||
fn setup<R: Rng>(_: &mut R) -> Result<Self::Parameters, Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn commit(
|
||||
_: &Self::Parameters,
|
||||
input: &[u8],
|
||||
randomness: &Self::Randomness,
|
||||
) -> Result<Self::Output, Error> {
|
||||
let mut h = b2s::new();
|
||||
h.input(input);
|
||||
h.input(randomness.as_ref());
|
||||
let mut result = [0u8; 32];
|
||||
result.copy_from_slice(&h.result());
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
23
crypto-primitives/src/commitment/constraints.rs
Normal file
23
crypto-primitives/src/commitment/constraints.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use crate::CommitmentScheme;
|
||||
use algebra::Field;
|
||||
use r1cs_core::{ConstraintSystem, SynthesisError};
|
||||
use r1cs_std::prelude::*;
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub trait CommitmentGadget<C: CommitmentScheme, ConstraintF: Field> {
|
||||
type OutputGadget: EqGadget<ConstraintF>
|
||||
+ ToBytesGadget<ConstraintF>
|
||||
+ AllocGadget<C::Output, ConstraintF>
|
||||
+ Clone
|
||||
+ Sized
|
||||
+ Debug;
|
||||
type ParametersGadget: AllocGadget<C::Parameters, ConstraintF> + Clone;
|
||||
type RandomnessGadget: AllocGadget<C::Randomness, ConstraintF> + Clone;
|
||||
|
||||
fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
|
||||
cs: CS,
|
||||
parameters: &Self::ParametersGadget,
|
||||
input: &[UInt8],
|
||||
r: &Self::RandomnessGadget,
|
||||
) -> Result<Self::OutputGadget, SynthesisError>;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
use algebra::{Field, PrimeField};
|
||||
|
||||
use crate::commitment::{
|
||||
injective_map::{InjectiveMap, PedersenCommCompressor},
|
||||
pedersen::PedersenWindow,
|
||||
pedersen::constraints::{
|
||||
PedersenCommitmentGadget, PedersenCommitmentGadgetParameters, PedersenRandomnessGadget,
|
||||
},
|
||||
CommitmentGadget,
|
||||
};
|
||||
|
||||
pub use crate::crh::injective_map::constraints::InjectiveMapGadget;
|
||||
use algebra::groups::Group;
|
||||
use r1cs_core::{ConstraintSystem, SynthesisError};
|
||||
use r1cs_std::{groups::GroupGadget, uint8::UInt8};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct PedersenCommitmentCompressorGadget<
|
||||
G: Group,
|
||||
I: InjectiveMap<G>,
|
||||
ConstraintF: Field,
|
||||
GG: GroupGadget<G, ConstraintF>,
|
||||
IG: InjectiveMapGadget<G, I, ConstraintF, GG>,
|
||||
> {
|
||||
_compressor: PhantomData<I>,
|
||||
_compressor_gadget: PhantomData<IG>,
|
||||
_crh: PedersenCommitmentGadget<G, ConstraintF, GG>,
|
||||
}
|
||||
|
||||
impl<G, I, ConstraintF, GG, IG, W> CommitmentGadget<PedersenCommCompressor<G, I, W>, ConstraintF>
|
||||
for PedersenCommitmentCompressorGadget<G, I, ConstraintF, GG, IG>
|
||||
where
|
||||
G: Group,
|
||||
I: InjectiveMap<G>,
|
||||
ConstraintF: PrimeField,
|
||||
GG: GroupGadget<G, ConstraintF>,
|
||||
IG: InjectiveMapGadget<G, I, ConstraintF, GG>,
|
||||
W: PedersenWindow,
|
||||
{
|
||||
type OutputGadget = IG::OutputGadget;
|
||||
type ParametersGadget = PedersenCommitmentGadgetParameters<G, W, ConstraintF>;
|
||||
type RandomnessGadget = PedersenRandomnessGadget;
|
||||
|
||||
fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
parameters: &Self::ParametersGadget,
|
||||
input: &[UInt8],
|
||||
r: &Self::RandomnessGadget,
|
||||
) -> Result<Self::OutputGadget, SynthesisError> {
|
||||
let result = PedersenCommitmentGadget::<G, ConstraintF, GG>::check_commitment_gadget(
|
||||
cs.ns(|| "PedersenComm"),
|
||||
parameters,
|
||||
input,
|
||||
r,
|
||||
)?;
|
||||
IG::evaluate_map(cs.ns(|| "InjectiveMap"), &result)
|
||||
}
|
||||
}
|
||||
47
crypto-primitives/src/commitment/injective_map/mod.rs
Normal file
47
crypto-primitives/src/commitment/injective_map/mod.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
use crate::Error;
|
||||
use rand::Rng;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::{
|
||||
pedersen::{PedersenCommitment, PedersenParameters, PedersenRandomness, PedersenWindow},
|
||||
CommitmentScheme,
|
||||
};
|
||||
pub use crate::crh::injective_map::InjectiveMap;
|
||||
use algebra::groups::Group;
|
||||
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub mod constraints;
|
||||
|
||||
pub struct PedersenCommCompressor<G: Group, I: InjectiveMap<G>, W: PedersenWindow> {
|
||||
_group: PhantomData<G>,
|
||||
_compressor: PhantomData<I>,
|
||||
_comm: PedersenCommitment<G, W>,
|
||||
}
|
||||
|
||||
impl<G: Group, I: InjectiveMap<G>, W: PedersenWindow> CommitmentScheme
|
||||
for PedersenCommCompressor<G, I, W>
|
||||
{
|
||||
type Output = I::Output;
|
||||
type Parameters = PedersenParameters<G>;
|
||||
type Randomness = PedersenRandomness<G>;
|
||||
|
||||
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
|
||||
let time = start_timer!(|| format!("PedersenCompressor::Setup"));
|
||||
let params = PedersenCommitment::<G, W>::setup(rng);
|
||||
end_timer!(time);
|
||||
params
|
||||
}
|
||||
|
||||
fn commit(
|
||||
parameters: &Self::Parameters,
|
||||
input: &[u8],
|
||||
randomness: &Self::Randomness,
|
||||
) -> Result<Self::Output, Error> {
|
||||
let eval_time = start_timer!(|| "PedersenCompressor::Eval");
|
||||
let result = I::injective_map(&PedersenCommitment::<G, W>::commit(
|
||||
parameters, input, randomness,
|
||||
)?)?;
|
||||
end_timer!(eval_time);
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
30
crypto-primitives/src/commitment/mod.rs
Normal file
30
crypto-primitives/src/commitment/mod.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
use rand::Rng;
|
||||
use algebra::UniformRand;
|
||||
use std::{fmt::Debug, hash::Hash};
|
||||
|
||||
use algebra::bytes::ToBytes;
|
||||
|
||||
pub mod blake2s;
|
||||
pub mod injective_map;
|
||||
pub mod pedersen;
|
||||
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub mod constraints;
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub use constraints::*;
|
||||
|
||||
use crate::Error;
|
||||
|
||||
pub trait CommitmentScheme {
|
||||
type Output: ToBytes + Clone + Default + Eq + Hash + Debug;
|
||||
type Parameters: Clone;
|
||||
type Randomness: Clone + ToBytes + Default + Eq + UniformRand + Debug;
|
||||
|
||||
fn setup<R: Rng>(r: &mut R) -> Result<Self::Parameters, Error>;
|
||||
|
||||
fn commit(
|
||||
parameters: &Self::Parameters,
|
||||
input: &[u8],
|
||||
r: &Self::Randomness,
|
||||
) -> Result<Self::Output, Error>;
|
||||
}
|
||||
244
crypto-primitives/src/commitment/pedersen/constraints.rs
Normal file
244
crypto-primitives/src/commitment/pedersen/constraints.rs
Normal file
@@ -0,0 +1,244 @@
|
||||
use crate::{
|
||||
commitment::pedersen::{PedersenCommitment, PedersenParameters, PedersenRandomness},
|
||||
crh::pedersen::PedersenWindow,
|
||||
};
|
||||
use algebra::{to_bytes, Group, ToBytes};
|
||||
use r1cs_core::{ConstraintSystem, SynthesisError};
|
||||
|
||||
use crate::commitment::CommitmentGadget;
|
||||
use algebra::fields::{Field, PrimeField};
|
||||
use r1cs_std::prelude::*;
|
||||
use std::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(Clone(bound = "G: Group, W: PedersenWindow, ConstraintF: Field"))]
|
||||
pub struct PedersenCommitmentGadgetParameters<G: Group, W: PedersenWindow, ConstraintF: Field> {
|
||||
params: PedersenParameters<G>,
|
||||
#[doc(hidden)]
|
||||
_group: PhantomData<G>,
|
||||
#[doc(hidden)]
|
||||
_engine: PhantomData<ConstraintF>,
|
||||
#[doc(hidden)]
|
||||
_window: PhantomData<W>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PedersenRandomnessGadget(Vec<UInt8>);
|
||||
|
||||
pub struct PedersenCommitmentGadget<G: Group, ConstraintF: Field, GG: GroupGadget<G, ConstraintF>>(
|
||||
#[doc(hidden)]
|
||||
PhantomData<*const G>,
|
||||
#[doc(hidden)]
|
||||
PhantomData<*const GG>,
|
||||
PhantomData<ConstraintF>,
|
||||
);
|
||||
|
||||
impl<ConstraintF, G, GG, W> CommitmentGadget<PedersenCommitment<G, W>, ConstraintF>
|
||||
for PedersenCommitmentGadget<G, ConstraintF, GG>
|
||||
where
|
||||
ConstraintF: PrimeField,
|
||||
G: Group,
|
||||
GG: GroupGadget<G, ConstraintF>,
|
||||
W: PedersenWindow,
|
||||
{
|
||||
type OutputGadget = GG;
|
||||
type ParametersGadget = PedersenCommitmentGadgetParameters<G, W, ConstraintF>;
|
||||
type RandomnessGadget = PedersenRandomnessGadget;
|
||||
|
||||
fn check_commitment_gadget<CS: ConstraintSystem<ConstraintF>>(
|
||||
mut cs: CS,
|
||||
parameters: &Self::ParametersGadget,
|
||||
input: &[UInt8],
|
||||
r: &Self::RandomnessGadget,
|
||||
) -> Result<Self::OutputGadget, SynthesisError> {
|
||||
assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS));
|
||||
|
||||
let mut padded_input = input.to_vec();
|
||||
// Pad if input length is less than `W::WINDOW_SIZE * W::NUM_WINDOWS`.
|
||||
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 commitment output.
|
||||
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 mut result = GG::precomputed_base_multiscalar_mul(
|
||||
cs.ns(|| "multiexp"),
|
||||
¶meters.params.generators,
|
||||
input_in_bits,
|
||||
)?;
|
||||
|
||||
// Compute h^r
|
||||
let rand_bits: Vec<_> = r.0.iter().flat_map(|byte| byte.into_bits_le()).collect();
|
||||
result.precomputed_base_scalar_mul(
|
||||
cs.ns(|| "Randomizer"),
|
||||
rand_bits
|
||||
.iter()
|
||||
.zip(¶meters.params.randomness_generator),
|
||||
)?;
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, W, ConstraintF> AllocGadget<PedersenParameters<G>, ConstraintF> for PedersenCommitmentGadgetParameters<G, W, ConstraintF>
|
||||
where
|
||||
G: Group,
|
||||
W: PedersenWindow,
|
||||
ConstraintF: PrimeField,
|
||||
{
|
||||
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 temp = value_gen()?;
|
||||
let parameters = temp.borrow().clone();
|
||||
|
||||
Ok(PedersenCommitmentGadgetParameters {
|
||||
params: parameters,
|
||||
_group: 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 temp = value_gen()?;
|
||||
let parameters = temp.borrow().clone();
|
||||
|
||||
Ok(PedersenCommitmentGadgetParameters {
|
||||
params: parameters,
|
||||
_group: PhantomData,
|
||||
_engine: PhantomData,
|
||||
_window: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<G, ConstraintF> AllocGadget<PedersenRandomness<G>, ConstraintF> for PedersenRandomnessGadget
|
||||
where
|
||||
G: Group,
|
||||
ConstraintF: PrimeField,
|
||||
{
|
||||
fn alloc<F, T, CS: ConstraintSystem<ConstraintF>>(cs: CS, value_gen: F) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<PedersenRandomness<G>>,
|
||||
{
|
||||
let temp = value_gen()?;
|
||||
let randomness = to_bytes![temp.borrow().0].unwrap();
|
||||
Ok(PedersenRandomnessGadget(UInt8::alloc_vec(cs, &randomness)?))
|
||||
}
|
||||
|
||||
fn alloc_input<F, T, CS: ConstraintSystem<ConstraintF>>(
|
||||
cs: CS,
|
||||
value_gen: F,
|
||||
) -> Result<Self, SynthesisError>
|
||||
where
|
||||
F: FnOnce() -> Result<T, SynthesisError>,
|
||||
T: Borrow<PedersenRandomness<G>>,
|
||||
{
|
||||
let temp = value_gen()?;
|
||||
let randomness = to_bytes![temp.borrow().0].unwrap();
|
||||
Ok(PedersenRandomnessGadget(UInt8::alloc_input_vec(
|
||||
cs,
|
||||
&randomness,
|
||||
)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use algebra::{fields::jubjub::{fq::Fq, fr::Fr}};
|
||||
use rand::thread_rng;
|
||||
use algebra::UniformRand;
|
||||
|
||||
use crate::{
|
||||
commitment::{
|
||||
pedersen::{PedersenCommitment, PedersenRandomness, constraints::PedersenCommitmentGadget},
|
||||
CommitmentScheme,
|
||||
CommitmentGadget,
|
||||
},
|
||||
crh::pedersen::PedersenWindow,
|
||||
};
|
||||
use algebra::curves::{jubjub::JubJubProjective as JubJub, ProjectiveCurve};
|
||||
use r1cs_core::ConstraintSystem;
|
||||
use r1cs_std::{
|
||||
groups::jubjub::JubJubGadget, test_constraint_system::TestConstraintSystem, prelude::*,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn commitment_gadget_test() {
|
||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub(super) struct Window;
|
||||
|
||||
impl PedersenWindow for Window {
|
||||
const WINDOW_SIZE: usize = 4;
|
||||
const NUM_WINDOWS: usize = 8;
|
||||
}
|
||||
|
||||
let input = [1u8; 4];
|
||||
|
||||
let rng = &mut thread_rng();
|
||||
|
||||
type TestCOMM = PedersenCommitment<JubJub, Window>;
|
||||
type TestCOMMGadget = PedersenCommitmentGadget<JubJub, Fq, JubJubGadget>;
|
||||
|
||||
let randomness = PedersenRandomness(Fr::rand(rng));
|
||||
|
||||
let parameters = PedersenCommitment::<JubJub, Window>::setup(rng).unwrap();
|
||||
let primitive_result =
|
||||
PedersenCommitment::<JubJub, Window>::commit(¶meters, &input, &randomness).unwrap();
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
let randomness =
|
||||
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessGadget::alloc(
|
||||
&mut cs.ns(|| "gadget_randomness"),
|
||||
|| Ok(&randomness),
|
||||
)
|
||||
.unwrap();
|
||||
let gadget_parameters =
|
||||
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersGadget::alloc(
|
||||
&mut cs.ns(|| "gadget_parameters"),
|
||||
|| Ok(¶meters),
|
||||
)
|
||||
.unwrap();
|
||||
let gadget_result =
|
||||
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::check_commitment_gadget(
|
||||
&mut cs.ns(|| "gadget_evaluation"),
|
||||
&gadget_parameters,
|
||||
&input_bytes,
|
||||
&randomness,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
123
crypto-primitives/src/commitment/pedersen/mod.rs
Normal file
123
crypto-primitives/src/commitment/pedersen/mod.rs
Normal file
@@ -0,0 +1,123 @@
|
||||
use crate::Error;
|
||||
use algebra::UniformRand;
|
||||
use rand::Rng;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::CommitmentScheme;
|
||||
use algebra::{bytes::ToBytes, groups::Group, BitIterator, FpParameters, PrimeField};
|
||||
use std::io::{Result as IoResult, Write};
|
||||
|
||||
pub use crate::crh::pedersen::PedersenWindow;
|
||||
use crate::crh::{
|
||||
pedersen::{PedersenCRH, PedersenParameters as PedersenCRHParameters},
|
||||
FixedLengthCRH,
|
||||
};
|
||||
|
||||
#[cfg(feature = "r1cs")]
|
||||
pub mod constraints;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PedersenParameters<G: Group> {
|
||||
pub randomness_generator: Vec<G>,
|
||||
pub generators: Vec<Vec<G>>,
|
||||
}
|
||||
|
||||
pub struct PedersenCommitment<G: Group, W: PedersenWindow> {
|
||||
group: PhantomData<G>,
|
||||
window: PhantomData<W>,
|
||||
}
|
||||
|
||||
#[derive(Derivative)]
|
||||
#[derivative(
|
||||
Clone(bound = "G: Group"),
|
||||
PartialEq(bound = "G: Group"),
|
||||
Debug(bound = "G: Group"),
|
||||
Eq(bound = "G: Group"),
|
||||
Default(bound = "G: Group")
|
||||
)]
|
||||
pub struct PedersenRandomness<G: Group>(pub G::ScalarField);
|
||||
|
||||
impl<G: Group> UniformRand for PedersenRandomness<G> {
|
||||
#[inline]
|
||||
fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self {
|
||||
PedersenRandomness(UniformRand::rand(rng))
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> ToBytes for PedersenRandomness<G> {
|
||||
fn write<W: Write>(&self, writer: W) -> IoResult<()> {
|
||||
self.0.write(writer)
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group, W: PedersenWindow> CommitmentScheme for PedersenCommitment<G, W> {
|
||||
type Parameters = PedersenParameters<G>;
|
||||
type Randomness = PedersenRandomness<G>;
|
||||
type Output = G;
|
||||
|
||||
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
|
||||
let time = start_timer!(|| format!(
|
||||
"PedersenCOMM::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> G",
|
||||
W::NUM_WINDOWS,
|
||||
W::WINDOW_SIZE,
|
||||
W::NUM_WINDOWS * W::WINDOW_SIZE
|
||||
));
|
||||
let num_powers = <G::ScalarField as PrimeField>::Params::MODULUS_BITS as usize;
|
||||
let randomness_generator = PedersenCRH::<_, W>::generator_powers(num_powers, rng);
|
||||
let generators = PedersenCRH::<_, W>::create_generators(rng);
|
||||
end_timer!(time);
|
||||
|
||||
Ok(Self::Parameters {
|
||||
randomness_generator,
|
||||
generators,
|
||||
})
|
||||
}
|
||||
|
||||
fn commit(
|
||||
parameters: &Self::Parameters,
|
||||
input: &[u8],
|
||||
randomness: &Self::Randomness,
|
||||
) -> Result<Self::Output, Error> {
|
||||
let commit_time = start_timer!(|| "PedersenCOMM::Commit");
|
||||
// If the input is too long, return an error.
|
||||
if input.len() > W::WINDOW_SIZE * W::NUM_WINDOWS {
|
||||
panic!("incorrect input length: {:?}", input.len());
|
||||
}
|
||||
// Pad the input to the necessary length.
|
||||
let mut padded_input = Vec::with_capacity(input.len());
|
||||
let mut input = input;
|
||||
if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
|
||||
let current_length = input.len();
|
||||
padded_input.extend_from_slice(input);
|
||||
for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
|
||||
padded_input.push(0u8);
|
||||
}
|
||||
input = padded_input.as_slice();
|
||||
}
|
||||
assert_eq!(parameters.generators.len(), W::NUM_WINDOWS);
|
||||
|
||||
// Invoke Pedersen CRH here, to prevent code duplication.
|
||||
|
||||
let crh_parameters = PedersenCRHParameters {
|
||||
generators: parameters.generators.clone(),
|
||||
};
|
||||
let mut result = PedersenCRH::<_, W>::evaluate(&crh_parameters, &input)?;
|
||||
let randomize_time = start_timer!(|| "Randomize");
|
||||
|
||||
// Compute h^r.
|
||||
let mut scalar_bits = BitIterator::new(randomness.0.into_repr()).collect::<Vec<_>>();
|
||||
scalar_bits.reverse();
|
||||
for (bit, power) in scalar_bits
|
||||
.into_iter()
|
||||
.zip(¶meters.randomness_generator)
|
||||
{
|
||||
if bit {
|
||||
result += power
|
||||
}
|
||||
}
|
||||
end_timer!(randomize_time);
|
||||
end_timer!(commit_time);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user