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