ark_mpc/
commitment.rs

1//! Defines Pedersen commitments over the system curve used to commit to a value
2//! before opening it
3
4use ark_ec::CurveGroup;
5use rand::thread_rng;
6use sha3::{Digest, Sha3_256};
7
8use crate::{
9    algebra::{CurvePoint, CurvePointResult, Scalar, ScalarResult},
10    fabric::ResultValue,
11};
12
13/// A handle on the result of a Pedersen commitment, including the committed
14/// secret
15///
16/// Of the form `value * G + blinder * H`
17pub(crate) struct PedersenCommitment<C: CurveGroup> {
18    /// The committed value
19    pub(crate) value: Scalar<C>,
20    /// The commitment blinder
21    pub(crate) blinder: Scalar<C>,
22    /// The value of the commitment
23    pub(crate) commitment: CurvePoint<C>,
24}
25
26impl<C: CurveGroup> PedersenCommitment<C> {
27    /// Verify that the given commitment is valid
28    pub(crate) fn verify(&self) -> bool {
29        let generator = CurvePoint::generator();
30        let commitment = generator * self.value + generator * self.blinder;
31
32        commitment == self.commitment
33    }
34}
35
36/// A Pedersen commitment that has been allocated in an MPC computation graph
37pub(crate) struct PedersenCommitmentResult<C: CurveGroup> {
38    /// The committed value
39    pub(crate) value: ScalarResult<C>,
40    /// The commitment blinder
41    pub(crate) blinder: Scalar<C>,
42    /// The value of the commitment
43    pub(crate) commitment: CurvePointResult<C>,
44}
45
46impl<C: CurveGroup> PedersenCommitmentResult<C> {
47    /// Create a new Pedersen commitment to an underlying value
48    pub(crate) fn commit(value: ScalarResult<C>) -> PedersenCommitmentResult<C> {
49        // Concretely, we use the curve generator for both `G` and `H` as is done
50        // in dalek-cryptography: https://github.com/dalek-cryptography/bulletproofs/blob/main/src/generators.rs#L44-L53
51        let mut rng = thread_rng();
52        let blinder = Scalar::random(&mut rng);
53        let generator = CurvePoint::generator();
54        let commitment = generator * &value + generator * blinder;
55
56        PedersenCommitmentResult {
57            value,
58            blinder,
59            commitment,
60        }
61    }
62}
63
64/// A handle on the result of a salted Sha256 hash commitment, including the
65/// committed secret
66///
67/// Of the form `H(salt || value)`
68///
69/// We use hash commitments to commit to curve points before opening them. There
70/// is no straightforward way to adapt Pedersen commitments to curve points, and
71/// we do not need the homomorphic properties of a Pedersen commitment
72pub(crate) struct HashCommitment<C: CurveGroup> {
73    /// The committed value
74    pub(crate) value: CurvePoint<C>,
75    /// The blinder used in the commitment
76    pub(crate) blinder: Scalar<C>,
77    /// The value of the commitment
78    pub(crate) commitment: Scalar<C>,
79}
80
81impl<C: CurveGroup> HashCommitment<C> {
82    /// Verify that the given commitment is valid
83    pub(crate) fn verify(&self) -> bool {
84        // Create the bytes buffer
85        let mut bytes = self.value.to_bytes();
86        bytes.append(&mut self.blinder.to_bytes_be());
87
88        // Hash the bytes, squeeze an output, verify that it is equal to the commitment
89        let mut hasher = Sha3_256::new();
90        hasher.update(bytes);
91
92        let out_bytes = hasher.finalize();
93        let out = Scalar::from_be_bytes_mod_order(out_bytes.as_slice());
94
95        out == self.commitment
96    }
97}
98
99/// A hash commitment that has been allocated in an MPC computation graph
100pub(crate) struct HashCommitmentResult<C: CurveGroup> {
101    /// The committed value
102    pub(crate) value: CurvePointResult<C>,
103    /// The blinder used in the commitment
104    pub(crate) blinder: Scalar<C>,
105    /// The value of the commitment
106    pub(crate) commitment: ScalarResult<C>,
107}
108
109impl<C: CurveGroup> HashCommitmentResult<C> {
110    /// Create a new hash commitment to an underlying value
111    pub(crate) fn commit(value: CurvePointResult<C>) -> HashCommitmentResult<C> {
112        let mut rng = thread_rng();
113        let blinder = Scalar::random(&mut rng);
114        let comm = value.fabric.new_gate_op(vec![value.id], move |mut args| {
115            let value: CurvePoint<C> = args.remove(0).into();
116
117            // Create the bytes buffer
118            let mut bytes = value.to_bytes();
119            bytes.append(&mut blinder.to_bytes_be());
120
121            // Hash the bytes, squeeze an output, verify that it is equal to the commitment
122            let mut hasher = Sha3_256::new();
123            hasher.update(bytes);
124
125            let out_bytes = hasher.finalize();
126            let out = Scalar::from_be_bytes_mod_order(out_bytes.as_slice());
127
128            ResultValue::Scalar(out)
129        });
130
131        HashCommitmentResult {
132            value,
133            blinder,
134            commitment: comm,
135        }
136    }
137}