commit_verify/convolve.rs
1// Client-side-validation foundation libraries.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Designed in 2019-2025 by Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
6// Written in 2024-2025 by Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2024 LNP/BP Standards Association, Switzerland.
9// Copyright (C) 2024-2025 LNP/BP Laboratories,
10// Institute for Distributed and Cognitive Systems
11// (InDCS), Switzerland. Copyright (C) 2019-2025 Dr Maxim Orlovsky.
12// All rights under the above copyrights are reserved.
13//
14// Licensed under the Apache License, Version 2.0 (the "License"); you may not
15// use this file except in compliance with the License. You may obtain a copy of
16// the License at
17//
18// http://www.apache.org/licenses/LICENSE-2.0
19//
20// Unless required by applicable law or agreed to in writing, software
21// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
22// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
23// License for the specific language governing permissions and limitations under
24// the License.
25
26//! Convolved commitments (convolve-commit-verify scheme).
27
28use crate::{CommitmentProtocol, VerifyEq};
29
30/// Error during commitment verification
31#[derive(Copy, Clone, Eq, PartialEq, Debug, Display, Error)]
32#[display(doc_comments)]
33#[cfg_attr(feature = "serde", derive(Serialize, Deserialize), serde(rename_all = "camelCase"))]
34pub enum ConvolveVerifyError {
35 /// commitment doesn't match the message.
36 CommitmentMismatch,
37
38 /// the message is invalid since a valid commitment to it can't be created.
39 ImpossibleMessage,
40
41 /// the proof is invalid and the commitment can't be verified.
42 InvalidProof,
43}
44
45/// Proof type used by [`ConvolveCommit`] protocol.
46pub trait ConvolveCommitProof<Msg, Source, Protocol>
47where
48 Self: Sized + VerifyEq,
49 Source: ConvolveCommit<Msg, Self, Protocol>,
50 Protocol: CommitmentProtocol,
51{
52 /// Supplement is a part of the proof data provided during commitment
53 /// procedure.
54 type Suppl;
55
56 /// Restores the original source before the commitment from the supplement
57 /// (the `self`) and commitment.
58 fn restore_original(&self, commitment: &Source::Commitment) -> Source;
59
60 /// Extract supplement from the proof.
61 fn extract_supplement(&self) -> &Self::Suppl;
62
63 /// Verifies commitment using proof (the `self`) against the message.
64 ///
65 /// Default implementation repeats [`ConvolveCommit::convolve_commit`]
66 /// procedure, restoring the original value out of proof data, checking
67 /// that the resulting commitment matches the provided one in the
68 /// `commitment` parameter.
69 ///
70 /// # Errors
71 ///
72 /// Errors if the commitment doesn't pass the validation (see
73 /// [`ConvolveVerifyError`] variants for the cases when this may happen).
74 fn verify(
75 &self,
76 msg: &Msg,
77 commitment: &Source::Commitment,
78 ) -> Result<(), ConvolveVerifyError>
79 where
80 Self: VerifyEq,
81 {
82 let original = self.restore_original(commitment);
83 let suppl = self.extract_supplement();
84 let (commitment_prime, proof) = original
85 .convolve_commit(suppl, msg)
86 .map_err(|_| ConvolveVerifyError::ImpossibleMessage)?;
87 if !self.verify_eq(&proof) {
88 return Err(ConvolveVerifyError::InvalidProof);
89 }
90 if !commitment.verify_eq(&commitment_prime) {
91 return Err(ConvolveVerifyError::CommitmentMismatch);
92 }
93 Ok(())
94 }
95}
96
97/// Trait for *convolve-commit-verify scheme*, where some data structure (named
98/// *container*) may commit to existing *message* using *supplement* and
99/// producing final *commitment* value. The commitment can't be used to restore
100/// original message, however the fact of the commitment may be
101/// deterministically *verified* when the message and the supplement (now acting
102/// as a *proof*) proof are *revealed*.
103///
104/// In other words, *convolve-commit* takes an object (`self`), a *supplement*,
105/// convolves them in certain way together and than uses the result to produce a
106/// commitment to a *message* and a *proof*:
107/// - `self + supplement -> internal_repr`;
108/// - `internal_repr + msg -> (commitment, proof)`.
109///
110/// Later on, a verifier presented with a message and the proof may do the
111/// commitment verification in the following way: `msg, proof, commitment ->
112/// bool`.
113///
114/// To use *convolve-commit-verify scheme* one needs to implement this trait for
115/// a data structure acting as a container for a specific commitment under
116/// certain protocol, specified as generic parameters. The container type must
117/// specify commitment types as associated type [`Self::Commitment`]. The
118/// commitment type in certain cases may be equal to the original container
119/// type; when the commitment represents internally modified container.
120///
121/// The difference between *convolve-commit-verify* and *embed-commit-verify*
122/// schemes is in the fact that unlike embed-commit, convolve-commit does not
123/// produce a proof external to the commitment, but instead requires additional
124/// immutable supplement information which is not a part of the container
125/// converted into the commitment. As an example one may consider procedures of
126/// homomorphic public key tweaking with the hash of the message, which is
127/// a case of embed-commit procedure, producing original public key as a proof
128/// and tweaked public key as a commitment -- and procedure of pay-to-contract
129/// commitment in scriptPubkey of a transaction output, which requires
130/// additional information about the public key or scripts present in the
131/// scriptPubkey only in hashed form (this is *supplement*), and producing just
132/// a modified version of the scriptPubkey (commitment) without any additional
133/// proof data.
134///
135/// Operations with *convolve-commit-verify scheme* may be represented in form
136/// of `ConvolveCommit: (Container, Supplement, Message) -> Commitment` (see
137/// [`Self::convolve_commit`] and
138/// `Verify: (Container', Supplement, Message) -> bool` (see
139/// [`ConvolveCommitProof::verify`]).
140///
141/// This trait is heavily used in **deterministic bitcoin commitments**.
142///
143/// # Protocol definition
144///
145/// Generic parameter `Protocol` provides context & configuration for commitment
146/// scheme protocol used for this container type.
147///
148/// Introduction of this generic allows to:
149/// - implement trait for foreign data types;
150/// - add multiple implementations under different commitment protocols to the
151/// combination of the same message and container type (each of each will have
152/// its own `Proof` type defined as an associated generic).
153///
154/// Usually represents an uninstantiable type, but may be a structure
155/// containing commitment protocol configuration or context objects.
156///
157/// ```
158/// # use commit_verify::CommitmentProtocol;
159///
160/// // Uninstantiable type
161/// pub enum Lnpbp6 {}
162///
163/// impl CommitmentProtocol for Lnpbp6 {}
164///
165/// // Protocol definition
166/// pub enum Lnpbp1 {}
167/// // ...
168/// ```
169pub trait ConvolveCommit<Msg, Proof, Protocol>
170where
171 Self: Sized,
172 Proof: ConvolveCommitProof<Msg, Self, Protocol>,
173 Protocol: CommitmentProtocol,
174{
175 /// Commitment type produced as a result of [`Self::convolve_commit`]
176 /// procedure.
177 type Commitment: Sized + VerifyEq;
178
179 /// Error type that may be reported during [`Self::convolve_commit`]
180 /// procedure. It may also be returned from [`ConvolveCommitProof::verify`]
181 /// in case the proof data are invalid and the commitment can't be
182 /// re-created.
183 type CommitError: std::error::Error;
184
185 /// Takes the `supplement` to unparse the content of this container (`self`)
186 /// ("convolves" these two data together) and uses them to produce a final
187 /// [`Self::Commitment`] to the message `msg`.
188 ///
189 /// Implementations must error with a dedicated error type enumerating
190 /// commitment procedure mistakes.
191 fn convolve_commit(
192 &self,
193 supplement: &Proof::Suppl,
194 msg: &Msg,
195 ) -> Result<(Self::Commitment, Proof), Self::CommitError>;
196
197 /// Phantom method used to add `Protocol` generic parameter to the trait.
198 ///
199 /// # Panics
200 ///
201 /// Always panics when called.
202 #[doc(hidden)]
203 fn _phantom(_: Protocol) {
204 unimplemented!("EmbedCommitVerify::_phantom is a marker method which must not be used")
205 }
206}