• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari-crypto / 9019555140

09 May 2024 03:24PM UTC coverage: 91.041%. Remained the same
9019555140

push

github

web-flow
chore: new version 0.20.1 (#228)

Release a new version

3516 of 3862 relevant lines covered (91.04%)

58.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.13
/src/commitment.rs
1
// Copyright 2019 The Tari Project
2
// SPDX-License-Identifier: BSD-3-Clause
3

4
//! A commitment is like a sealed envelope. You put some information inside the envelope, and then seal (commit) it.
5
//! You can't change what you've said, but also, no-one knows what you've said until you're ready to open (open) the
6
//! envelope and reveal its contents. Also it's a special envelope that can only be opened by a special opener that
7
//! you keep safe in your drawer.
8

9
use core::{
10
    cmp::Ordering,
11
    convert::TryFrom,
12
    hash::{Hash, Hasher},
13
    ops::{Add, Mul, Sub},
14
};
15

16
use tari_utilities::{ByteArray, ByteArrayError};
17

18
use crate::{
19
    alloc::string::ToString,
20
    errors::CommitmentError,
21
    keys::{PublicKey, SecretKey},
22
};
23

24
/// There are also different types of commitments that vary in their security guarantees, but all of them are
25
/// represented by binary data; so [HomomorphicCommitment](trait.HomomorphicCommitment.html) implements
26
/// [ByteArray](trait.ByteArray.html).
27
///
28
/// The Homomorphic part means, more or less, that commitments follow some of the standard rules of
29
/// arithmetic. Adding two commitments is the same as committing to the sum of their parts:
30
/// $$ \begin{aligned}
31
///   C_1 &= v_1.H + k_1.G \\\\
32
///   C_2 &= v_2.H + k_2.G \\\\
33
///   \therefore C_1 + C_2 &= (v_1 + v_2)H + (k_1 + k_2)G
34
/// \end{aligned} $$
35
#[derive(Debug, Clone, Default)]
36
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16✔
37
pub struct HomomorphicCommitment<P>(pub(crate) P);
38

39
#[cfg(feature = "borsh")]
40
impl<P: borsh::BorshDeserialize> borsh::BorshDeserialize for HomomorphicCommitment<P> {
41
    fn deserialize_reader<R>(reader: &mut R) -> Result<Self, borsh::io::Error>
×
42
    where R: borsh::io::Read {
×
43
        Ok(Self(P::deserialize_reader(reader)?))
×
44
    }
×
45
}
46

47
#[cfg(feature = "borsh")]
48
impl<P: borsh::BorshSerialize> borsh::BorshSerialize for HomomorphicCommitment<P> {
49
    fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
×
50
        self.0.serialize(writer)
×
51
    }
×
52
}
53

54
impl<P> HomomorphicCommitment<P>
55
where P: PublicKey
56
{
57
    /// Get this commitment as a public key point
58
    pub fn as_public_key(&self) -> &P {
3,492✔
59
        &self.0
3,492✔
60
    }
3,492✔
61

62
    /// Converts a public key into a commitment
63
    pub fn from_public_key(p: &P) -> HomomorphicCommitment<P> {
17✔
64
        HomomorphicCommitment(p.clone())
17✔
65
    }
17✔
66
}
67

68
impl<P> ByteArray for HomomorphicCommitment<P>
69
where P: PublicKey
70
{
71
    fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, ByteArrayError> {
1✔
72
        let p = P::from_canonical_bytes(bytes)?;
1✔
73
        Ok(Self(p))
1✔
74
    }
1✔
75

76
    fn as_bytes(&self) -> &[u8] {
45✔
77
        self.0.as_bytes()
45✔
78
    }
45✔
79
}
80

81
impl<P> PartialOrd for HomomorphicCommitment<P>
82
where P: PublicKey
83
{
84
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
168✔
85
        Some(self.cmp(other))
168✔
86
    }
168✔
87
}
88

89
impl<P> Ord for HomomorphicCommitment<P>
90
where P: PublicKey
91
{
92
    fn cmp(&self, other: &Self) -> Ordering {
392✔
93
        self.0.cmp(&other.0)
392✔
94
    }
392✔
95
}
96

97
/// Add two commitments together. Note! There is no check that the bases are equal.
98
impl<'b, P> Add for &'b HomomorphicCommitment<P>
99
where
100
    P: PublicKey,
101
    &'b P: Add<&'b P, Output = P>,
102
{
103
    type Output = HomomorphicCommitment<P>;
104

105
    fn add(self, rhs: &'b HomomorphicCommitment<P>) -> Self::Output {
635✔
106
        HomomorphicCommitment(&self.0 + &rhs.0)
635✔
107
    }
635✔
108
}
109

110
/// Add a public key to a commitment. Note! There is no check that the bases are equal.
111
impl<'b, P> Add<&'b P> for &'b HomomorphicCommitment<P>
112
where
113
    P: PublicKey,
114
    &'b P: Add<&'b P, Output = P>,
115
{
116
    type Output = HomomorphicCommitment<P>;
117

118
    fn add(self, rhs: &'b P) -> Self::Output {
2✔
119
        HomomorphicCommitment(&self.0 + rhs)
2✔
120
    }
2✔
121
}
122

123
/// Subtracts the left commitment from the right commitment. Note! There is no check that the bases are equal.
124
impl<'b, P> Sub for &'b HomomorphicCommitment<P>
125
where
126
    P: PublicKey,
127
    &'b P: Sub<&'b P, Output = P>,
128
{
129
    type Output = HomomorphicCommitment<P>;
130

131
    fn sub(self, rhs: &'b HomomorphicCommitment<P>) -> Self::Output {
1✔
132
        HomomorphicCommitment(&self.0 - &rhs.0)
1✔
133
    }
1✔
134
}
135

136
/// Multiply the commitment with a private key
137
impl<'a, 'b, P, K> Mul<&'b K> for &'a HomomorphicCommitment<P>
138
where
139
    P: PublicKey<K = K>,
140
    K: SecretKey,
141
    &'b K: Mul<&'a P, Output = P>,
142
{
143
    type Output = HomomorphicCommitment<P>;
144

145
    fn mul(self, rhs: &'b K) -> HomomorphicCommitment<P> {
12✔
146
        let p = rhs * &self.0;
12✔
147
        HomomorphicCommitment::<P>::from_public_key(&p)
12✔
148
    }
12✔
149
}
150

151
impl<P: PublicKey> Hash for HomomorphicCommitment<P> {
152
    fn hash<H: Hasher>(&self, state: &mut H) {
32✔
153
        state.write(self.as_bytes())
32✔
154
    }
32✔
155
}
156

157
impl<P: PublicKey> PartialEq for HomomorphicCommitment<P> {
158
    fn eq(&self, other: &Self) -> bool {
1,601✔
159
        self.as_public_key() == other.as_public_key()
1,601✔
160
    }
1,601✔
161
}
162

163
impl<P: PublicKey> Eq for HomomorphicCommitment<P> {}
164

165
/// A trait for creating commitments
166
pub trait HomomorphicCommitmentFactory {
167
    /// The type of public key that the underlying commitment will be based on
168
    type P: PublicKey;
169

170
    /// Create a new commitment with the blinding factor _k_ and value _v_ provided. The implementing type will provide
171
    /// the base values
172
    fn commit(&self, k: &<Self::P as PublicKey>::K, v: &<Self::P as PublicKey>::K) -> HomomorphicCommitment<Self::P>;
173
    /// Return an identity point for addition using the specified base point. This is a commitment to zero with a zero
174
    /// blinding factor on the base point
175
    fn zero(&self) -> HomomorphicCommitment<Self::P>;
176
    /// Test whether the given blinding factor _k_ and value _v_ open the given commitment
177
    fn open(
178
        &self,
179
        k: &<Self::P as PublicKey>::K,
180
        v: &<Self::P as PublicKey>::K,
181
        commitment: &HomomorphicCommitment<Self::P>,
182
    ) -> bool;
183
    /// Create a commitment from a blinding factor _k_ and an integer value
184
    fn commit_value(&self, k: &<Self::P as PublicKey>::K, value: u64) -> HomomorphicCommitment<Self::P>;
185
    /// Test whether the given private key and value open the given commitment
186
    fn open_value(&self, k: &<Self::P as PublicKey>::K, v: u64, commitment: &HomomorphicCommitment<Self::P>) -> bool;
187
}
188

189
/// A trait for creating extended commitments that are based on a public key
190
pub trait ExtendedHomomorphicCommitmentFactory {
191
    /// The type of public key that the underlying commitment will be based on
192
    type P: PublicKey;
193

194
    /// Create a new commitment with the blinding factor vector **k** and value _v_ provided. The implementing type will
195
    /// provide the base values
196
    fn commit_extended(
197
        &self,
198
        k_vec: &[<Self::P as PublicKey>::K],
199
        v: &<Self::P as PublicKey>::K,
200
    ) -> Result<HomomorphicCommitment<Self::P>, CommitmentError>;
201
    /// Return an identity point for addition using the specified base points. This is a commitment to zero with a zero
202
    /// blinding factor vector on the base points
203
    fn zero_extended(&self) -> HomomorphicCommitment<Self::P>;
204
    /// Test whether the given blinding factor vector **k** and value _v_ open the given commitment
205
    fn open_extended(
206
        &self,
207
        k_vec: &[<Self::P as PublicKey>::K],
208
        v: &<Self::P as PublicKey>::K,
209
        commitment: &HomomorphicCommitment<Self::P>,
210
    ) -> Result<bool, CommitmentError>;
211
    /// Create a commitment from a blinding factor vector **k** and an integer value
212
    fn commit_value_extended(
213
        &self,
214
        k_vec: &[<Self::P as PublicKey>::K],
215
        value: u64,
216
    ) -> Result<HomomorphicCommitment<Self::P>, CommitmentError>;
217
    /// Test whether the given private keys and value open the given commitment
218
    fn open_value_extended(
219
        &self,
220
        k_vec: &[<Self::P as PublicKey>::K],
221
        v: u64,
222
        commitment: &HomomorphicCommitment<Self::P>,
223
    ) -> Result<bool, CommitmentError>;
224
}
225

226
/// The extension degree for extended Pedersen commitments. Currently this is limited to adding 5 base points to the
227
/// default Pedersen commitment, but in theory it could be arbitrarily long, although practically, very few if any
228
/// test cases will need to add more than 2 base points.
229
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
230
pub enum ExtensionDegree {
231
    /// Default Pedersen commitment (`C = v.H + sum(k_i.G_i)|i=1`)
232
    DefaultPedersen = 1,
233
    /// Pedersen commitment extended with one degree (`C = v.H + sum(k_i.G_i)|i=1..2`)
234
    AddOneBasePoint = 2,
235
    /// Pedersen commitment extended with two degrees (`C = v.H + sum(k_i.G_i)|i=1..3`)
236
    AddTwoBasePoints = 3,
237
    /// Pedersen commitment extended with three degrees (`C = v.H + sum(k_i.G_i)|i=1..4`)
238
    AddThreeBasePoints = 4,
239
    /// Pedersen commitment extended with four degrees (`C = v.H + sum(k_i.G_i)|i=1..5`)
240
    AddFourBasePoints = 5,
241
    /// Pedersen commitment extended with five degrees (`C = v.H + sum(k_i.G_i)|i=1..6`)
242
    AddFiveBasePoints = 6,
243
}
244

245
impl ExtensionDegree {
246
    /// Helper function to convert a size into an extension degree
247
    pub fn try_from_size(size: usize) -> Result<ExtensionDegree, CommitmentError> {
11✔
248
        match size {
11✔
249
            1 => Ok(ExtensionDegree::DefaultPedersen),
7✔
250
            2 => Ok(ExtensionDegree::AddOneBasePoint),
×
251
            3 => Ok(ExtensionDegree::AddTwoBasePoints),
×
252
            4 => Ok(ExtensionDegree::AddThreeBasePoints),
×
253
            5 => Ok(ExtensionDegree::AddFourBasePoints),
×
254
            6 => Ok(ExtensionDegree::AddFiveBasePoints),
4✔
255
            _ => Err(CommitmentError::CommitmentExtensionDegree {
×
256
                reason: "Extension degree not valid".to_string(),
×
257
            }),
×
258
        }
259
    }
11✔
260
}
261

262
impl TryFrom<usize> for ExtensionDegree {
263
    type Error = CommitmentError;
264

265
    fn try_from(value: usize) -> Result<Self, Self::Error> {
×
266
        Self::try_from_size(value)
×
267
    }
×
268
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc