commit_verify/
lib.rs

1// Client-side-validation foundation libraries.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2024 by
6//     Dr. Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved.
9//
10// Licensed under the Apache License, Version 2.0 (the "License");
11// you may not use this file except in compliance with the License.
12// You may obtain a copy of the License at
13//
14//     http://www.apache.org/licenses/LICENSE-2.0
15//
16// Unless required by applicable law or agreed to in writing, software
17// distributed under the License is distributed on an "AS IS" BASIS,
18// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19// See the License for the specific language governing permissions and
20// limitations under the License.
21
22// Coding conventions
23#![deny(
24    non_upper_case_globals,
25    non_camel_case_types,
26    non_snake_case,
27    unused_mut,
28    unused_imports,
29    dead_code,
30    // TODO: uncomment missing_docs
31)]
32#![cfg_attr(docsrs, feature(doc_auto_cfg))]
33
34#[macro_use]
35extern crate amplify;
36#[macro_use]
37extern crate strict_encoding;
38#[macro_use]
39extern crate commit_encoding_derive;
40#[cfg(feature = "serde")]
41#[macro_use]
42extern crate serde_crate as serde;
43extern crate core;
44
45#[cfg(feature = "derive")]
46pub use commit_encoding_derive::CommitEncode;
47
48mod commit;
49mod conceal;
50mod convolve;
51mod embed;
52mod id;
53#[cfg(feature = "stl")]
54pub mod stl;
55
56pub mod merkle;
57pub mod mpc;
58mod digest;
59pub mod vesper;
60
61pub use commit::{CommitVerify, TryCommitVerify, VerifyError};
62pub use conceal::Conceal;
63pub use convolve::{ConvolveCommit, ConvolveCommitProof, ConvolveVerifyError};
64pub use digest::{Digest, DigestExt, Ripemd160, Sha256};
65pub use embed::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError, VerifyEq};
66pub use id::{
67    CommitColType, CommitEncode, CommitEngine, CommitId, CommitLayout, CommitStep, CommitmentId,
68    CommitmentLayout, StrictHash,
69};
70pub use merkle::{MerkleBuoy, MerkleHash, MerkleLeaves, MerkleNode, NodeBranching};
71
72pub const LIB_NAME_COMMIT_VERIFY: &str = "CommitVerify";
73
74/// Marker trait for specific commitment protocols.
75///
76/// Generic parameter `Protocol` used in commitment scheme traits provides a
77/// context & configuration for the concrete implementations.
78///
79/// Introduction of such generic allows to:
80/// - implement trait for foreign data types;
81/// - add multiple implementations under different commitment protocols to the
82///   combination of the same message and container type (each of each will have
83///   its own `Proof` type defined as an associated generic).
84pub trait CommitmentProtocol {}
85
86/// Protocol defining commits created by using externally created hash value
87/// *optionally pre-tagged*.
88pub struct UntaggedProtocol;
89impl CommitmentProtocol for UntaggedProtocol {}
90
91/// Reserved bytes.
92#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
93#[display("reserved")]
94#[derive(StrictType, StrictEncode)]
95#[strict_type(lib = LIB_NAME_COMMIT_VERIFY)]
96pub struct ReservedBytes<const LEN: usize, const VAL: u8 = 0>([u8; LEN]);
97
98impl<const LEN: usize, const VAL: u8> Default for ReservedBytes<LEN, VAL> {
99    fn default() -> Self { Self([VAL; LEN]) }
100}
101
102impl<const LEN: usize, const VAL: u8> From<[u8; LEN]> for ReservedBytes<LEN, VAL> {
103    fn from(value: [u8; LEN]) -> Self {
104        assert_eq!(value, [VAL; LEN]);
105        Self(value)
106    }
107}
108
109mod _reserved {
110    use strict_encoding::{DecodeError, ReadTuple, StrictDecode, TypedRead};
111
112    use crate::{CommitEncode, CommitEngine, ReservedBytes, StrictHash};
113
114    impl<const LEN: usize, const VAL: u8> CommitEncode for ReservedBytes<LEN, VAL> {
115        type CommitmentId = StrictHash;
116
117        fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(self) }
118    }
119
120    impl<const LEN: usize, const VAL: u8> StrictDecode for ReservedBytes<LEN, VAL> {
121        fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
122            let reserved = reader.read_tuple(|r| r.read_field().map(Self))?;
123            if reserved != ReservedBytes::<LEN, VAL>::default() {
124                Err(DecodeError::DataIntegrityError(format!(
125                    "unsupported reserved byte value indicating a future RGB version. Please \
126                     update your software, or, if the problem persists, contact your vendor \
127                     providing the following version information: {reserved}"
128                )))
129            } else {
130                Ok(reserved)
131            }
132        }
133    }
134
135    #[cfg(feature = "serde")]
136    mod _serde {
137        use std::fmt;
138
139        use serde_crate::de::Visitor;
140        use serde_crate::{de, Deserialize, Deserializer, Serialize, Serializer};
141
142        use super::*;
143
144        impl<const LEN: usize, const VAL: u8> Serialize for ReservedBytes<LEN, VAL> {
145            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
146            where S: Serializer {
147                // Doing nothing
148                serializer.serialize_unit()
149            }
150        }
151
152        impl<'de, const LEN: usize, const VAL: u8> Deserialize<'de> for ReservedBytes<LEN, VAL> {
153            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
154            where D: Deserializer<'de> {
155                #[derive(Default)]
156                pub struct UntaggedUnitVisitor;
157
158                impl Visitor<'_> for UntaggedUnitVisitor {
159                    type Value = ();
160
161                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
162                        write!(formatter, "reserved unit")
163                    }
164
165                    fn visit_none<E>(self) -> Result<(), E>
166                    where E: de::Error {
167                        Ok(())
168                    }
169
170                    fn visit_unit<E>(self) -> Result<(), E>
171                    where E: de::Error {
172                        Ok(())
173                    }
174                }
175
176                deserializer.deserialize_unit(UntaggedUnitVisitor)?;
177                Ok(default!())
178            }
179        }
180    }
181}
182
183/// Helpers for writing test functions working with commit schemes
184#[cfg(test)]
185pub mod test_helpers {
186    use amplify::confinement::SmallVec;
187    use amplify::hex::FromHex;
188
189    pub use super::commit::test_helpers::*;
190    pub use super::embed::test_helpers::*;
191    use super::*;
192
193    /// Generates a set of messages for testing purposes
194    ///
195    /// All of these messages MUST produce different commitments, otherwise the
196    /// commitment algorithm is not collision-resistant
197    pub fn gen_messages() -> Vec<SmallVec<u8>> {
198        vec![
199            // empty message
200            b"".to_vec(),
201            // zero byte message
202            b"\x00".to_vec(),
203            // text message
204            b"test".to_vec(),
205            // text length-extended message
206            b"test*".to_vec(),
207            // short binary message
208            Vec::from_hex("deadbeef").unwrap(),
209            // length-extended version
210            Vec::from_hex("deadbeef00").unwrap(),
211            // prefixed version
212            Vec::from_hex("00deadbeef").unwrap(),
213            // serialized public key as text
214            b"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798".to_vec(),
215            // the same public key binary data
216            Vec::from_hex("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")
217                .unwrap(),
218            // different public key
219            Vec::from_hex("02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")
220                .unwrap(),
221        ]
222        .into_iter()
223        .map(|v| SmallVec::try_from(v).unwrap())
224        .collect()
225    }
226}