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}