Skip to main content

sonobe_primitives/commitments/
mod.rs

1//! Abstract traits and implementations for commitment schemes.
2
3use ark_ff::UniformRand;
4use ark_r1cs_std::{GR1CSVar, alloc::AllocVar, fields::fp::FpVar, select::CondSelectGadget};
5use ark_relations::gr1cs::SynthesisError;
6use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
7use ark_std::{
8    fmt::Debug,
9    iter::Sum,
10    ops::{Add, Mul},
11    rand::RngCore,
12};
13use thiserror::Error;
14
15use crate::{
16    algebra::{
17        Val,
18        field::{TwoStageFieldVar, emulated::EmulatedFieldVar},
19        group::emulated::EmulatedAffineVar,
20        ops::bits::FromBitsGadget,
21    },
22    traits::{CF1, CF2, SonobeCurve, SonobeField},
23    transcripts::{Absorbable, AbsorbableVar},
24};
25
26pub mod pedersen;
27// TODO: add back other commitment schemes
28
29/// [`enum@Error`] enumerates possible errors during commitment operations.
30#[derive(Debug, Error)]
31pub enum Error {
32    /// [`Error::MessageTooLong`] indicates that the message being committed to
33    /// is longer than the maximum supported length.
34    #[error(
35        "The message being committed to has length {1}, exceeding the maximum supported length ({0})"
36    )]
37    MessageTooLong(usize, usize),
38    /// [`Error::CommitmentVerificationFail`] indicates that the provided
39    /// opening does not verify against the commitment.
40    #[error("Commitment verification failed")]
41    CommitmentVerificationFail,
42}
43
44/// [`CommitmentKey`] represents a commitment key (e.g., a vector of group
45/// generators for many group-based commitment schemes).
46pub trait CommitmentKey: Clone + Send + Sync + CanonicalSerialize + CanonicalDeserialize {
47    /// [`CommitmentKey::max_scalars_len`] returns the maximum number of scalars
48    /// that can be committed to with this key.
49    fn max_scalars_len(&self) -> usize;
50}
51
52/// [`CommitmentDef`] provides the core type definitions of a commitment scheme,
53/// defining the types of relevant cryptographic objects such as the commitment
54/// key, scalars, commitments, and randomness.
55pub trait CommitmentDef: 'static + Clone + Debug + PartialEq + Eq {
56    /// [`CommitmentDef::IS_HIDING`] indicates whether the commitment scheme has
57    /// the hiding property.
58    const IS_HIDING: bool;
59
60    /// [`CommitmentDef::Key`] is the type of the commitment key.
61    type Key: CommitmentKey;
62    /// [`CommitmentDef::Scalar`] is the type of the scalars being committed to.
63    ///
64    /// For generality, we do not restrict this to field elements and instead
65    /// only bound it by necessary traits.
66    type Scalar: Clone + Copy + Default + Debug + PartialEq + Eq + Sync + Absorbable + UniformRand;
67    /// [`CommitmentDef::Commitment`] is the type of the commitment.
68    ///
69    /// In the future we may introduce other commitment schemes such as those
70    /// based on hash functions or lattices, so we do not restrict this to be
71    /// group elements.
72    type Commitment: Clone + Default + Debug + PartialEq + Eq + Sync + Absorbable;
73    /// [`CommitmentDef::Randomness`] is the type of the randomness used in
74    /// the commitment.
75    ///
76    /// Hiding commitment schemes and non-hiding schemes may have different
77    /// randomness types, e.g., the former holds real data, while the latter
78    /// is just a placeholder type.
79    ///
80    /// In this way, we can leverage the compiler to reject misuse, e.g., using
81    /// randomness where it is not needed, or vice versa, with a unified API.
82    type Randomness: Clone
83        + Copy
84        + Default
85        + Debug
86        + PartialEq
87        + Eq
88        + Sync
89        + Add<Self::Scalar, Output = Self::Randomness>
90        + Mul<Self::Scalar, Output = Self::Randomness>
91        + for<'a> Add<&'a Self::Scalar, Output = Self::Randomness>
92        + for<'a> Mul<&'a Self::Scalar, Output = Self::Randomness>
93        + Add<Output = Self::Randomness>
94        + Mul<Output = Self::Randomness>
95        + Sum;
96}
97
98/// [`CommitmentOps`] defines algorithms for commitment schemes.
99pub trait CommitmentOps: CommitmentDef {
100    /// [`CommitmentOps::generate_key`] defines the key generation algorithm,
101    /// which is a randomized algorithm that takes as input the maximum length
102    /// `len` of supported messages, and a randomness source `rng`, and outputs
103    /// the commitment key.
104    fn generate_key(len: usize, rng: impl RngCore) -> Result<Self::Key, Error>;
105
106    /// [`CommitmentOps::commit`] defines the commitment generation algorithm,
107    /// which is a (probably) randomized algorithm that takes as input
108    /// commitment key `ck`, a vector of scalars `v` to be committed to, and a
109    /// randomness source `rng`, and outputs the commitment and the randomness.
110    fn commit(
111        ck: &Self::Key,
112        v: &[Self::Scalar],
113        rng: impl RngCore,
114    ) -> Result<(Self::Commitment, Self::Randomness), Error>;
115
116    /// [`CommitmentOps::open`] defines the commitment opening algorithm, which
117    /// is a deterministic algorithm that takes as input commitment key `ck`,
118    /// a vector of scalars `v`, the randomness `r`, and a commitment `cm`, and
119    /// outputs `Ok(())` if the opening verifies, or an error otherwise.
120    fn open(
121        ck: &Self::Key,
122        v: &[Self::Scalar],
123        r: &Self::Randomness,
124        cm: &Self::Commitment,
125    ) -> Result<(), Error>;
126}
127
128/// [`CommitmentDefGadget`] specifies the in-circuit associated types for a
129/// commitment scheme gadget.
130pub trait CommitmentDefGadget: Clone {
131    /// [`CommitmentDefGadget::ConstraintField`] is the field over which the
132    /// circuit running the commitment scheme is defined.
133    type ConstraintField: SonobeField;
134
135    /// [`CommitmentDefGadget::KeyVar`] is the in-circuit variable type for the
136    /// commitment key.
137    type KeyVar: AllocVar<<Self::Widget as CommitmentDef>::Key, Self::ConstraintField>;
138    /// [`CommitmentDefGadget::ScalarVar`] is the in-circuit variable type for
139    /// the scalars being committed to.
140    type ScalarVar: AbsorbableVar<Self::ConstraintField>
141        + CondSelectGadget<Self::ConstraintField>
142        + FromBitsGadget<Self::ConstraintField>
143        + AllocVar<<Self::Widget as CommitmentDef>::Scalar, Self::ConstraintField>
144        + GR1CSVar<Self::ConstraintField, Value = <Self::Widget as CommitmentDef>::Scalar>
145        + TwoStageFieldVar;
146    /// [`CommitmentDefGadget::CommitmentVar`] is the in-circuit variable type
147    /// for the commitment.
148    type CommitmentVar: Clone
149        + AbsorbableVar<Self::ConstraintField>
150        + CondSelectGadget<Self::ConstraintField>
151        + AllocVar<<Self::Widget as CommitmentDef>::Commitment, Self::ConstraintField>
152        + GR1CSVar<Self::ConstraintField, Value = <Self::Widget as CommitmentDef>::Commitment>;
153    /// [`CommitmentDefGadget::RandomnessVar`] is the in-circuit variable type
154    /// for the randomness used in the commitment.
155    type RandomnessVar: AllocVar<<Self::Widget as CommitmentDef>::Randomness, Self::ConstraintField>
156        + GR1CSVar<Self::ConstraintField, Value = <Self::Widget as CommitmentDef>::Randomness>;
157
158    /// [`CommitmentDefGadget::Widget`] points to the out-of-circuit commitment
159    /// scheme widget.
160    type Widget: CommitmentDef;
161}
162
163/// [`CommitmentOpsGadget`] defines algorithms (majorly the opening algorithm)
164/// for commitment schemes in-circuit.
165pub trait CommitmentOpsGadget: CommitmentDefGadget<Widget: CommitmentOps> {
166    /// [`CommitmentOpsGadget::open`] defines the commitment opening gadget
167    /// that matches its out-of-circuit widget [`CommitmentOps::open`].
168    fn open(
169        ck: &Self::KeyVar,
170        v: &[Self::ScalarVar],
171        r: &Self::RandomnessVar,
172        cm: &Self::CommitmentVar,
173    ) -> Result<(), SynthesisError>;
174}
175
176/// [`GroupBasedCommitment`] is a variant of commitment schemes built on groups
177/// (elliptic curves).
178pub trait GroupBasedCommitment:
179    CommitmentDef<Commitment: SonobeCurve, Scalar = CF1<<Self as CommitmentDef>::Commitment>>
180    + CommitmentOps
181{
182    /// [`GroupBasedCommitment::Gadget1`] points to the in-circuit gadget for
183    /// the group-based commitment scheme over the curve's base field.
184    type Gadget1: CommitmentOpsGadget
185        + CommitmentDefGadget<
186            ConstraintField = CF2<Self::Commitment>,
187            ScalarVar = EmulatedFieldVar<CF2<Self::Commitment>, Self::Scalar>,
188            CommitmentVar = <Self::Commitment as Val>::Var,
189            Widget = Self,
190        >;
191    /// [`GroupBasedCommitment::Gadget2`] points to the in-circuit gadget for
192    /// the group-based commitment scheme over the curve's scalar field.
193    type Gadget2: CommitmentDefGadget<
194            ConstraintField = Self::Scalar,
195            ScalarVar = FpVar<Self::Scalar>,
196            CommitmentVar = EmulatedAffineVar<Self::Scalar, Self::Commitment>,
197            Widget = Self,
198        >;
199}
200
201#[cfg(test)]
202mod tests {
203    use ark_ff::UniformRand;
204    use ark_relations::gr1cs::ConstraintSystem;
205    use ark_std::error::Error;
206
207    use super::*;
208
209    pub fn test_commitment_correctness<CM: CommitmentOps>(
210        mut rng: impl RngCore,
211        len: usize,
212    ) -> Result<(), Box<dyn Error>> {
213        let v = (0..len)
214            .map(|_| CM::Scalar::rand(&mut rng))
215            .collect::<Vec<_>>();
216
217        let ck = CM::generate_key(len, &mut rng)?;
218        let (cm, r) = CM::commit(&ck, &v, &mut rng)?;
219        CM::open(&ck, &v, &r, &cm)?;
220        Ok(())
221    }
222
223    pub fn test_commitment_gadget_correctness<CM: CommitmentOpsGadget>(
224        mut rng: impl RngCore,
225        len: usize,
226    ) -> Result<(), Box<dyn Error>> {
227        let v = (0..len)
228            .map(|_| UniformRand::rand(&mut rng))
229            .collect::<Vec<_>>();
230
231        let ck = CM::Widget::generate_key(len, &mut rng)?;
232        let (cm, r) = CM::Widget::commit(&ck, &v, &mut rng)?;
233
234        let cs = ConstraintSystem::new_ref();
235
236        let v_var = Vec::new_witness(cs.clone(), || Ok(v))?;
237        let r_var = AllocVar::new_witness(cs.clone(), || Ok(r))?;
238        let ck_var = AllocVar::new_constant(cs.clone(), ck)?;
239        let cm_var = AllocVar::new_witness(cs.clone(), || Ok(cm))?;
240
241        CM::open(&ck_var, &v_var, &r_var, &cm_var)?;
242
243        assert!(cs.is_satisfied()?);
244
245        Ok(())
246    }
247}