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;
43
44#[cfg(feature = "derive")]
45pub use commit_encoding_derive::CommitEncode;
46
47mod commit;
48mod conceal;
49mod convolve;
50mod embed;
51mod id;
52#[cfg(feature = "stl")]
53pub mod stl;
54
55pub mod merkle;
56pub mod mpc;
57mod digest;
58pub mod vesper;
59
60pub use commit::{CommitVerify, TryCommitVerify, VerifyError};
61pub use conceal::Conceal;
62pub use convolve::{ConvolveCommit, ConvolveCommitProof, ConvolveVerifyError};
63pub use digest::{Digest, DigestExt, Ripemd160, Sha256};
64pub use embed::{EmbedCommitProof, EmbedCommitVerify, EmbedVerifyError, VerifyEq};
65pub use id::{
66    CommitColType, CommitEncode, CommitEngine, CommitId, CommitLayout, CommitStep, CommitmentId,
67    CommitmentLayout, StrictHash,
68};
69pub use merkle::{MerkleBuoy, MerkleHash, MerkleLeaves, MerkleNode, NodeBranching};
70
71pub const LIB_NAME_COMMIT_VERIFY: &str = "CommitVerify";
72
73/// Marker trait for specific commitment protocols.
74///
75/// Generic parameter `Protocol` used in commitment scheme traits provides a
76/// context & configuration for the concrete implementations.
77///
78/// Introduction of such generic allows to:
79/// - implement trait for foreign data types;
80/// - add multiple implementations under different commitment protocols to the
81///   combination of the same message and container type (each of each will have
82///   its own `Proof` type defined as an associated generic).
83pub trait CommitmentProtocol {}
84
85/// Protocol defining commits created by using externally created hash value
86/// *optionally pre-tagged*.
87pub struct UntaggedProtocol;
88impl CommitmentProtocol for UntaggedProtocol {}
89
90/// Reserved bytes.
91#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display)]
92#[display("reserved")]
93#[derive(StrictType, StrictEncode)]
94#[strict_type(lib = LIB_NAME_COMMIT_VERIFY)]
95pub struct ReservedBytes<const LEN: usize, const VAL: u8 = 0>([u8; LEN]);
96
97impl<const LEN: usize, const VAL: u8> Default for ReservedBytes<LEN, VAL> {
98    fn default() -> Self { Self([VAL; LEN]) }
99}
100
101impl<const LEN: usize, const VAL: u8> From<[u8; LEN]> for ReservedBytes<LEN, VAL> {
102    fn from(value: [u8; LEN]) -> Self {
103        assert_eq!(value, [VAL; LEN]);
104        Self(value)
105    }
106}
107
108mod _reserved {
109    use strict_encoding::{DecodeError, ReadTuple, StrictDecode, TypedRead};
110
111    use crate::{CommitEncode, CommitEngine, ReservedBytes, StrictHash};
112
113    impl<const LEN: usize, const VAL: u8> CommitEncode for ReservedBytes<LEN, VAL> {
114        type CommitmentId = StrictHash;
115
116        fn commit_encode(&self, e: &mut CommitEngine) { e.commit_to_serialized(self) }
117    }
118
119    impl<const LEN: usize, const VAL: u8> StrictDecode for ReservedBytes<LEN, VAL> {
120        fn strict_decode(reader: &mut impl TypedRead) -> Result<Self, DecodeError> {
121            let reserved = reader.read_tuple(|r| r.read_field().map(Self))?;
122            if reserved != ReservedBytes::<LEN, VAL>::default() {
123                Err(DecodeError::DataIntegrityError(format!(
124                    "unsupported reserved byte value indicating a future RGB version. Please \
125                     update your software, or, if the problem persists, contact your vendor \
126                     providing the following version information: {reserved}"
127                )))
128            } else {
129                Ok(reserved)
130            }
131        }
132    }
133
134    #[cfg(feature = "serde")]
135    mod _serde {
136        use std::fmt;
137
138        use serde::de::Visitor;
139        use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
140
141        use super::*;
142
143        impl<const LEN: usize, const VAL: u8> Serialize for ReservedBytes<LEN, VAL> {
144            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
145            where S: Serializer {
146                // Doing nothing
147                serializer.serialize_unit()
148            }
149        }
150
151        impl<'de, const LEN: usize, const VAL: u8> Deserialize<'de> for ReservedBytes<LEN, VAL> {
152            fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
153            where D: Deserializer<'de> {
154                #[derive(Default)]
155                pub struct UntaggedUnitVisitor;
156
157                impl Visitor<'_> for UntaggedUnitVisitor {
158                    type Value = ();
159
160                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
161                        write!(formatter, "reserved unit")
162                    }
163
164                    fn visit_none<E>(self) -> Result<(), E>
165                    where E: de::Error {
166                        Ok(())
167                    }
168
169                    fn visit_unit<E>(self) -> Result<(), E>
170                    where E: de::Error {
171                        Ok(())
172                    }
173                }
174
175                deserializer.deserialize_unit(UntaggedUnitVisitor)?;
176                Ok(default!())
177            }
178        }
179    }
180}
181
182/// Helpers for writing test functions working with commit schemes
183#[cfg(test)]
184pub mod test_helpers {
185    use amplify::confinement::SmallVec;
186    use amplify::hex::FromHex;
187
188    pub use super::commit::test_helpers::*;
189    pub use super::embed::test_helpers::*;
190    use super::*;
191
192    /// Generates a set of messages for testing purposes
193    ///
194    /// All of these messages MUST produce different commitments, otherwise the
195    /// commitment algorithm is not collision-resistant
196    pub fn gen_messages() -> Vec<SmallVec<u8>> {
197        vec![
198            // empty message
199            b"".to_vec(),
200            // zero byte message
201            b"\x00".to_vec(),
202            // text message
203            b"test".to_vec(),
204            // text length-extended message
205            b"test*".to_vec(),
206            // short binary message
207            Vec::from_hex("deadbeef").unwrap(),
208            // length-extended version
209            Vec::from_hex("deadbeef00").unwrap(),
210            // prefixed version
211            Vec::from_hex("00deadbeef").unwrap(),
212            // serialized public key as text
213            b"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798".to_vec(),
214            // the same public key binary data
215            Vec::from_hex("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798")
216                .unwrap(),
217            // different public key
218            Vec::from_hex("02f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9")
219                .unwrap(),
220        ]
221        .into_iter()
222        .map(|v| SmallVec::try_from(v).unwrap())
223        .collect()
224    }
225}