curv/cryptographic_primitives/commitments/
hash_commitment.rs

1/*
2    This file is part of Curv library
3    Copyright 2018 by Kzen Networks
4    (https://github.com/KZen-networks/curv)
5    License MIT: https://github.com/KZen-networks/curv/blob/master/LICENSE
6*/
7
8use std::marker::PhantomData;
9
10use digest::Digest;
11
12use crate::arithmetic::traits::*;
13use crate::BigInt;
14
15use super::traits::Commitment;
16use super::SECURITY_BITS;
17
18//TODO: (open issue) use this struct to represent the commitment HashCommitment{comm: BigInt, r: BigInt, m: BigInt}
19/// calculate commitment c = H(m,r) using SHA3 CRHF.
20/// r is 256bit blinding factor, m is the commited value
21pub struct HashCommitment<H: Digest + Clone>(PhantomData<H>);
22
23//TODO:  using the function with BigInt's as input instead of string's makes it impossible to commit to empty message or use empty randomness
24impl<H: Digest + Clone> Commitment<BigInt> for HashCommitment<H> {
25    fn create_commitment_with_user_defined_randomness(
26        message: &BigInt,
27        blinding_factor: &BigInt,
28    ) -> BigInt {
29        let digest_result = H::new()
30            .chain(message.to_bytes())
31            .chain(blinding_factor.to_bytes())
32            .finalize();
33        BigInt::from_bytes(digest_result.as_ref())
34    }
35
36    fn create_commitment(message: &BigInt) -> (BigInt, BigInt) {
37        let blinding_factor = BigInt::sample(SECURITY_BITS);
38        let com = Self::create_commitment_with_user_defined_randomness(message, &blinding_factor);
39        (com, blinding_factor)
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::Commitment;
46    use super::HashCommitment;
47    use super::SECURITY_BITS;
48    use crate::arithmetic::traits::*;
49    use crate::{test_for_all_hashes, BigInt};
50    use digest::Digest;
51
52    test_for_all_hashes!(test_bit_length_create_commitment);
53    fn test_bit_length_create_commitment<H: Digest + Clone>() {
54        let hex_len = H::output_size() * 8;
55        let mut ctr_commit_len = 0;
56        let mut ctr_blind_len = 0;
57        let sample_size = 10_000;
58        for _ in 1..sample_size {
59            let message = BigInt::sample(hex_len);
60            let (commitment, blind_factor) = HashCommitment::<H>::create_commitment(&message);
61            if commitment.bit_length() == hex_len {
62                ctr_commit_len += 1;
63            }
64            // the blinding factor bit length is not related to the hash function.
65            if blind_factor.bit_length() == SECURITY_BITS {
66                ctr_blind_len += 1;
67            }
68        }
69        //test commitment length  - works because SHA256 output length the same as sec_bits
70        // we test that the probability distribution is according to what is expected. ideally = 0.5
71        let ctr_commit_len = ctr_commit_len as f32;
72        let ctr_blind_len = ctr_blind_len as f32;
73        let sample_size = sample_size as f32;
74        assert!(ctr_commit_len / sample_size > 0.3);
75        assert!(ctr_blind_len / sample_size > 0.3);
76    }
77
78    test_for_all_hashes!(test_bit_length_create_commitment_with_user_defined_randomness);
79    fn test_bit_length_create_commitment_with_user_defined_randomness<H: Digest + Clone>() {
80        let sec_bits = H::output_size() * 8;
81        let message = BigInt::sample(sec_bits);
82        let (_commitment, blind_factor) = HashCommitment::<H>::create_commitment(&message);
83        let commitment2 = HashCommitment::<H>::create_commitment_with_user_defined_randomness(
84            &message,
85            &blind_factor,
86        );
87        assert!(commitment2.to_hex().len() / 2 <= sec_bits / 8);
88    }
89
90    test_for_all_hashes!(test_random_num_generation_create_commitment_with_user_defined_randomness);
91    fn test_random_num_generation_create_commitment_with_user_defined_randomness<
92        H: Digest + Clone,
93    >() {
94        let message = BigInt::sample(SECURITY_BITS);
95        let (commitment, blind_factor) = HashCommitment::<H>::create_commitment(&message);
96        let commitment2 = HashCommitment::<H>::create_commitment_with_user_defined_randomness(
97            &message,
98            &blind_factor,
99        );
100        assert_eq!(commitment, commitment2);
101    }
102
103    test_for_all_hashes!(test_hashing_create_commitment_with_user_defined_randomness);
104    fn test_hashing_create_commitment_with_user_defined_randomness<H: Digest + Clone>() {
105        let mut digest = H::new();
106        let message = BigInt::one();
107        let commitment = HashCommitment::<H>::create_commitment_with_user_defined_randomness(
108            &message,
109            &BigInt::zero(),
110        );
111        let message2 = message.to_bytes();
112        digest.update(&message2);
113        let bytes_blinding_factor = &BigInt::zero().to_bytes();
114        digest.update(&bytes_blinding_factor);
115        let hash_result = BigInt::from_bytes(digest.finalize().as_ref());
116        assert_eq!(&commitment, &hash_result);
117    }
118}