arnaucube
arnaucube/ark-r1cs-stdPublic Self-hosted repository
ark-r1cs-std/crypto-primitives/src/commitment/pedersen/mod.rs
crypto-primitives/src/commitment/pedersen/mod.rsRaw
  1use crate::Error;
  2use algebra::UniformRand;
  3use rand::Rng;
  4use std::marker::PhantomData;
  5
  6use super::CommitmentScheme;
  7use algebra::{bytes::ToBytes, groups::Group, BitIterator, FpParameters, PrimeField};
  8use std::io::{Result as IoResult, Write};
  9
 10pub use crate::crh::pedersen::PedersenWindow;
 11use crate::crh::{
 12    pedersen::{PedersenCRH, PedersenParameters as PedersenCRHParameters},
 13    FixedLengthCRH,
 14};
 15
 16#[cfg(feature = "r1cs")]
 17pub mod constraints;
 18
 19#[derive(Clone)]
 20pub struct PedersenParameters<G: Group> {
 21    pub randomness_generator: Vec<G>,
 22    pub generators:           Vec<Vec<G>>,
 23}
 24
 25pub struct PedersenCommitment<G: Group, W: PedersenWindow> {
 26    group:  PhantomData<G>,
 27    window: PhantomData<W>,
 28}
 29
 30#[derive(Derivative)]
 31#[derivative(
 32    Clone(bound = "G: Group"),
 33    PartialEq(bound = "G: Group"),
 34    Debug(bound = "G: Group"),
 35    Eq(bound = "G: Group"),
 36    Default(bound = "G: Group")
 37)]
 38pub struct PedersenRandomness<G: Group>(pub G::ScalarField);
 39
 40impl<G: Group> UniformRand for PedersenRandomness<G> {
 41    #[inline]
 42    fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self {
 43        PedersenRandomness(UniformRand::rand(rng))
 44    }
 45}
 46
 47impl<G: Group> ToBytes for PedersenRandomness<G> {
 48    fn write<W: Write>(&self, writer: W) -> IoResult<()> {
 49        self.0.write(writer)
 50    }
 51}
 52
 53impl<G: Group, W: PedersenWindow> CommitmentScheme for PedersenCommitment<G, W> {
 54    type Parameters = PedersenParameters<G>;
 55    type Randomness = PedersenRandomness<G>;
 56    type Output = G;
 57
 58    fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
 59        let time = start_timer!(|| format!(
 60            "PedersenCOMM::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> G",
 61            W::NUM_WINDOWS,
 62            W::WINDOW_SIZE,
 63            W::NUM_WINDOWS * W::WINDOW_SIZE
 64        ));
 65        let num_powers = <G::ScalarField as PrimeField>::Params::MODULUS_BITS as usize;
 66        let randomness_generator = PedersenCRH::<_, W>::generator_powers(num_powers, rng);
 67        let generators = PedersenCRH::<_, W>::create_generators(rng);
 68        end_timer!(time);
 69
 70        Ok(Self::Parameters {
 71            randomness_generator,
 72            generators,
 73        })
 74    }
 75
 76    fn commit(
 77        parameters: &Self::Parameters,
 78        input: &[u8],
 79        randomness: &Self::Randomness,
 80    ) -> Result<Self::Output, Error> {
 81        let commit_time = start_timer!(|| "PedersenCOMM::Commit");
 82        // If the input is too long, return an error.
 83        if input.len() > W::WINDOW_SIZE * W::NUM_WINDOWS {
 84            panic!("incorrect input length: {:?}", input.len());
 85        }
 86        // Pad the input to the necessary length.
 87        let mut padded_input = Vec::with_capacity(input.len());
 88        let mut input = input;
 89        if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
 90            let current_length = input.len();
 91            padded_input.extend_from_slice(input);
 92            for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
 93                padded_input.push(0u8);
 94            }
 95            input = padded_input.as_slice();
 96        }
 97        assert_eq!(parameters.generators.len(), W::NUM_WINDOWS);
 98
 99        // Invoke Pedersen CRH here, to prevent code duplication.
100
101        let crh_parameters = PedersenCRHParameters {
102            generators: parameters.generators.clone(),
103        };
104        let mut result = PedersenCRH::<_, W>::evaluate(&crh_parameters, &input)?;
105        let randomize_time = start_timer!(|| "Randomize");
106
107        // Compute h^r.
108        let mut scalar_bits = BitIterator::new(randomness.0.into_repr()).collect::<Vec<_>>();
109        scalar_bits.reverse();
110        for (bit, power) in scalar_bits
111            .into_iter()
112            .zip(&parameters.randomness_generator)
113        {
114            if bit {
115                result += power
116            }
117        }
118        end_timer!(randomize_time);
119        end_timer!(commit_time);
120
121        Ok(result)
122    }
123}