grin_core/core/
committed.rs1use keychain::BlindingFactor;
18use util::secp::key::SecretKey;
19use util::secp::pedersen::Commitment;
20use util::{secp, secp_static, static_secp_instance};
21
22#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)]
24pub enum Error {
25 #[error("Keychain error {0}")]
27 Keychain(keychain::Error),
28 #[error("Secp error {0}")]
30 Secp(secp::Error),
31 #[error("Kernel sum mismatch")]
33 KernelSumMismatch,
34 #[error("Invalid value")]
36 InvalidValue,
37}
38
39impl From<secp::Error> for Error {
40 fn from(e: secp::Error) -> Error {
41 Error::Secp(e)
42 }
43}
44
45impl From<keychain::Error> for Error {
46 fn from(e: keychain::Error) -> Error {
47 Error::Keychain(e)
48 }
49}
50
51pub trait Committed {
56 fn sum_kernel_excesses(
58 &self,
59 offset: &BlindingFactor,
60 ) -> Result<(Commitment, Commitment), Error> {
61 let kernel_commits = self.kernels_committed();
63
64 let kernel_sum = sum_commits(kernel_commits, vec![])?;
66
67 let kernel_sum_plus_offset = {
70 let secp = static_secp_instance();
71 let secp = secp.lock();
72 let mut commits = vec![kernel_sum];
73 if *offset != BlindingFactor::zero() {
74 let key = offset.secret_key(&secp)?;
75 let offset_commit = secp.commit(0, key)?;
76 commits.push(offset_commit);
77 }
78 secp.commit_sum(commits, vec![])?
79 };
80
81 Ok((kernel_sum, kernel_sum_plus_offset))
82 }
83
84 fn sum_commitments(&self, overage: i64) -> Result<Commitment, Error> {
86 let mut input_commits = self.inputs_committed();
88 let mut output_commits = self.outputs_committed();
89
90 if overage != 0 {
93 let over_commit = {
94 let secp = static_secp_instance();
95 let secp = secp.lock();
96 let overage_abs = overage.checked_abs().ok_or_else(|| Error::InvalidValue)? as u64;
97 secp.commit_value(overage_abs).unwrap()
98 };
99 if overage < 0 {
100 input_commits.push(over_commit);
101 } else {
102 output_commits.push(over_commit);
103 }
104 }
105
106 sum_commits(output_commits, input_commits)
107 }
108
109 fn inputs_committed(&self) -> Vec<Commitment>;
111
112 fn outputs_committed(&self) -> Vec<Commitment>;
114
115 fn kernels_committed(&self) -> Vec<Commitment>;
117
118 fn verify_kernel_sums(
122 &self,
123 overage: i64,
124 kernel_offset: BlindingFactor,
125 ) -> Result<(Commitment, Commitment), Error> {
126 let utxo_sum = self.sum_commitments(overage)?;
128
129 let (kernel_sum, kernel_sum_plus_offset) = self.sum_kernel_excesses(&kernel_offset)?;
131
132 if utxo_sum != kernel_sum_plus_offset {
133 return Err(Error::KernelSumMismatch);
134 }
135
136 Ok((utxo_sum, kernel_sum))
137 }
138}
139
140pub fn sum_commits(
142 mut positive: Vec<Commitment>,
143 mut negative: Vec<Commitment>,
144) -> Result<Commitment, Error> {
145 let zero_commit = secp_static::commit_to_zero_value();
146 positive.retain(|x| *x != zero_commit);
147 negative.retain(|x| *x != zero_commit);
148 let secp = static_secp_instance();
149 let secp = secp.lock();
150 Ok(secp.commit_sum(positive, negative)?)
151}
152
153pub fn sum_kernel_offsets(
157 positive: Vec<BlindingFactor>,
158 negative: Vec<BlindingFactor>,
159) -> Result<BlindingFactor, Error> {
160 let secp = static_secp_instance();
161 let secp = secp.lock();
162 let positive = to_secrets(positive, &secp);
163 let negative = to_secrets(negative, &secp);
164
165 if positive.is_empty() {
166 Ok(BlindingFactor::zero())
167 } else {
168 let sum = secp.blind_sum(positive, negative)?;
169 Ok(BlindingFactor::from_secret_key(sum))
170 }
171}
172
173fn to_secrets(bf: Vec<BlindingFactor>, secp: &secp::Secp256k1) -> Vec<SecretKey> {
174 bf.into_iter()
175 .filter(|x| *x != BlindingFactor::zero())
176 .filter_map(|x| x.secret_key(&secp).ok())
177 .collect::<Vec<_>>()
178}