Skip to main content

dkls23_core/utilities/
commits.rs

1//! Commit and decommit protocols.
2//!
3//! This file implements the commitment functionality needed for `DKLs23`.
4//! We follow the approach suggested on page 7 of their paper
5//! (<https://eprint.iacr.org/2023/765.pdf>).
6
7use crate::utilities::hashes::{point_to_bytes, tagged_hash, HashOutput};
8use crate::utilities::oracle_tags::TAG_COMMITMENT;
9use crate::utilities::rng;
10use elliptic_curve::CurveArithmetic;
11use rand::RngExt;
12use rustcrypto_group::GroupEncoding;
13use subtle::ConstantTimeEq;
14
15// Computational security parameter lambda_c from DKLs23 (divided by 8)
16use crate::SECURITY;
17
18/// Commits to a given message.
19///
20/// Given a message, this function generates a random salt of size `2*lambda_c`
21/// and computes the corresponding commitment.
22///
23/// The sender should first communicate the commitment. When he wants to decommit,
24/// he sends the message together with the salt.
25#[must_use]
26pub fn commit(msg: &[u8]) -> (HashOutput, Vec<u8>) {
27    //The paper instructs the salt to have 2*lambda_c bits.
28    let mut salt = [0u8; 2 * SECURITY as usize];
29    rng::get_rng().fill(&mut salt[..]);
30
31    let commitment = tagged_hash(TAG_COMMITMENT, &[&salt, msg]);
32
33    (commitment, salt.to_vec())
34}
35
36/// Verifies a commitment for a message.
37///
38/// After having received the commitment and later the message and the salt, the receiver
39/// verifies if these data are compatible.
40#[must_use]
41pub fn verify_commitment(msg: &[u8], commitment: &HashOutput, salt: &[u8]) -> bool {
42    let expected_commitment = tagged_hash(TAG_COMMITMENT, &[salt, msg]);
43    commitment.ct_eq(&expected_commitment).into()
44}
45
46/// Commits to a given point.
47///
48///  This is the same as [`commit`], but it receives a point on the elliptic curve instead.
49#[must_use]
50pub fn commit_point<C: CurveArithmetic>(point: &C::AffinePoint) -> (HashOutput, Vec<u8>)
51where
52    C::AffinePoint: GroupEncoding,
53{
54    let point_as_bytes = point_to_bytes::<C>(point);
55    commit(&point_as_bytes)
56}
57
58/// Verifies a commitment for a point.
59///
60/// This is the same as [`verify_commitment`], but it receives a point on the elliptic curve instead.
61#[must_use]
62pub fn verify_commitment_point<C: CurveArithmetic>(
63    point: &C::AffinePoint,
64    commitment: &HashOutput,
65    salt: &[u8],
66) -> bool
67where
68    C::AffinePoint: GroupEncoding,
69{
70    let point_as_bytes = point_to_bytes::<C>(point);
71    verify_commitment(&point_as_bytes, commitment, salt)
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77
78    /// Tests if committing and de-committing work.
79    #[test]
80    fn test_commit_decommit() {
81        let msg = rng::get_rng().random::<[u8; 32]>();
82        let (commitment, salt) = commit(&msg);
83        assert!(verify_commitment(&msg, &commitment, &salt));
84    }
85
86    /// Commits to a message and changes it on purpose
87    /// to check that if [`verify_commitment`] returns `false`.
88    #[test]
89    fn test_commit_decommit_fail_msg() {
90        let msg = rng::get_rng().random::<[u8; 32]>();
91        let (commitment, salt) = commit(&msg);
92        let msg = rng::get_rng().random::<[u8; 32]>(); //We change the message
93        assert!(!(verify_commitment(&msg, &commitment, &salt))); //The test can fail but with very low probability
94    }
95
96    /// Commits to a message and changes the commitment on purpose
97    /// to check that if [`verify_commitment`] returns `false`.
98    #[test]
99    fn test_commit_decommit_fail_commitment() {
100        let msg = rng::get_rng().random::<[u8; 32]>();
101        let (_, salt) = commit(&msg);
102        let commitment = rng::get_rng().random::<HashOutput>(); //We change the commitment
103        assert!(!(verify_commitment(&msg, &commitment, &salt))); //The test can fail but with very low probability
104    }
105
106    /// Commits to a message and changes the salt on purpose
107    /// to check that if [`verify_commitment`] returns `false`.
108    #[test]
109    fn test_commit_decommit_fail_salt() {
110        let msg = rng::get_rng().random::<[u8; 32]>();
111        let (commitment, _) = commit(&msg);
112        let mut salt = [0u8; 2 * SECURITY as usize];
113        rng::get_rng().fill(&mut salt[..]);
114        assert!(!(verify_commitment(&msg, &commitment, &salt))); //The test can fail but with very low probability
115    }
116}