rgbstd/containers/
seal.rs

1// RGB standard library for working with smart contracts on Bitcoin & Lightning
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Written in 2019-2023 by
6//     Dr Maxim Orlovsky <orlovsky@lnp-bp.org>
7//
8// Copyright (C) 2019-2023 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#![doc = include_str!("seals.md")]
23
24use std::fmt::{self, Display, Formatter};
25use std::str::FromStr;
26
27use bp::seals::txout::blind::ParseError;
28use bp::seals::txout::{CloseMethod, TxPtr};
29use bp::secp256k1::rand::{thread_rng, RngCore};
30use bp::Vout;
31use commit_verify::Conceal;
32use rgb::{ExposedSeal, GenesisSeal, GraphSeal, SecretSeal};
33
34use crate::{Outpoint, LIB_NAME_RGB_STD};
35
36/// Seal definition which re-uses witness transaction id of some other seal,
37/// which is not known at the moment of seal construction. Thus, the definition
38/// has only information about output number.
39#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)]
40#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
41#[strict_type(lib = LIB_NAME_RGB_STD)]
42#[cfg_attr(
43    feature = "serde",
44    derive(Serialize, Deserialize),
45    serde(crate = "serde_crate", rename_all = "camelCase")
46)]
47pub struct VoutSeal {
48    /// Commitment to the specific seal close method [`CloseMethod`] which must
49    /// be used to close this seal.
50    pub method: CloseMethod,
51
52    /// Tx output number, which should be always known.
53    pub vout: Vout,
54
55    /// Blinding factor providing confidentiality of the seal definition.
56    /// Prevents rainbow table bruteforce attack based on the existing
57    /// blockchain txid set.
58    pub blinding: u64,
59}
60
61impl VoutSeal {
62    /// Creates new seal definition for the provided output number and seal
63    /// closing method. Uses `thread_rng` to initialize blinding factor.
64    #[inline]
65    pub fn new(method: CloseMethod, vout: impl Into<Vout>) -> Self {
66        VoutSeal::with(method, vout, thread_rng().next_u64())
67    }
68
69    /// Creates new opret-seal seal definition for the provided output number
70    /// and seal closing method. Uses `thread_rng` to initialize blinding
71    /// factor.
72    #[inline]
73    pub fn new_opret(vout: impl Into<Vout>) -> Self { VoutSeal::new(CloseMethod::OpretFirst, vout) }
74
75    /// Creates new tapret-seal seal definition for the provided output number
76    /// and seal closing method. Uses `thread_rng` to initialize blinding
77    /// factor.
78    #[inline]
79    pub fn new_tapret(vout: impl Into<Vout>) -> Self {
80        VoutSeal::new(CloseMethod::TapretFirst, vout)
81    }
82
83    /// Reconstructs previously defined opret seal given an output number and a
84    /// previously generated blinding factor.
85    #[inline]
86    pub fn with_opret(vout: impl Into<Vout>, blinding: u64) -> Self {
87        VoutSeal::with(CloseMethod::OpretFirst, vout, blinding)
88    }
89
90    /// Reconstructs previously defined tapret seal given an output number and a
91    /// previously generated blinding factor.
92    #[inline]
93    pub fn with_tapret(vout: impl Into<Vout>, blinding: u64) -> Self {
94        VoutSeal::with(CloseMethod::TapretFirst, vout, blinding)
95    }
96
97    /// Reconstructs previously defined seal given method, an output number and
98    /// a previously generated blinding factor.
99    #[inline]
100    pub fn with(method: CloseMethod, vout: impl Into<Vout>, blinding: u64) -> Self {
101        VoutSeal {
102            method,
103            vout: vout.into(),
104            blinding,
105        }
106    }
107}
108
109impl From<VoutSeal> for GraphSeal {
110    fn from(seal: VoutSeal) -> Self { Self::with_vout(seal.method, seal.vout, seal.blinding) }
111}
112
113/// Seal endpoint is a confidential seal which may be linked to the witness
114/// transaction, but does not contain information about its id.
115///
116/// Seal endpoint can be either a pointer to the output in the witness
117/// transaction, plus blinding factor value, or a confidential seal
118/// [`SecretSeal`] value pointing some external unknown transaction
119/// output
120///
121/// Seal endpoint is required in situations where sender assigns state to the
122/// witness transaction output on behalf of receiver
123#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)]
124#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
125#[strict_type(lib = LIB_NAME_RGB_STD, tags = custom, dumb = Self::ConcealedUtxo(strict_dumb!()))]
126#[cfg_attr(
127    feature = "serde",
128    derive(Serialize, Deserialize),
129    serde(crate = "serde_crate", rename_all = "camelCase")
130)]
131pub enum TerminalSeal {
132    /// External transaction output in concealed form (see [`SecretSeal`])
133    #[from]
134    #[strict_type(tag = 0)]
135    ConcealedUtxo(SecretSeal),
136
137    /// Seal contained within the witness transaction
138    #[strict_type(tag = 1)]
139    WitnessVout(VoutSeal),
140}
141
142impl From<GraphSeal> for TerminalSeal {
143    fn from(seal: GraphSeal) -> Self {
144        match seal.txid {
145            TxPtr::WitnessTx => {
146                TerminalSeal::WitnessVout(VoutSeal::with(seal.method, seal.vout, seal.blinding))
147            }
148            TxPtr::Txid(_) => TerminalSeal::ConcealedUtxo(seal.conceal()),
149        }
150    }
151}
152
153impl TerminalSeal {
154    /// Constructs [`TerminalSeal`] for the witness transaction. Uses
155    /// `thread_rng` to initialize blinding factor.
156    pub fn new_vout(method: CloseMethod, vout: impl Into<Vout>) -> TerminalSeal {
157        TerminalSeal::WitnessVout(VoutSeal::new(method, vout))
158    }
159
160    pub fn secret_seal(&self) -> Option<SecretSeal> {
161        match self {
162            TerminalSeal::ConcealedUtxo(seal) => Some(*seal),
163            TerminalSeal::WitnessVout(_) => None,
164        }
165    }
166}
167
168impl Conceal for TerminalSeal {
169    type Concealed = SecretSeal;
170
171    fn conceal(&self) -> Self::Concealed {
172        match *self {
173            TerminalSeal::ConcealedUtxo(hash) => hash,
174            TerminalSeal::WitnessVout(seal) => GraphSeal::from(seal).conceal(),
175        }
176    }
177}
178
179impl Display for TerminalSeal {
180    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
181        match *self {
182            TerminalSeal::ConcealedUtxo(ref seal) => Display::fmt(seal, f),
183            TerminalSeal::WitnessVout(seal) => Display::fmt(&GraphSeal::from(seal), f),
184        }
185    }
186}
187
188impl FromStr for TerminalSeal {
189    type Err = ParseError;
190
191    fn from_str(s: &str) -> Result<Self, Self::Err> {
192        SecretSeal::from_str(s)
193            .map(TerminalSeal::from)
194            .or_else(|_| GraphSeal::from_str(s).map(TerminalSeal::from))
195    }
196}
197
198/// Seal used by operation builder which can be either revealed or concealed.
199#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From)]
200pub enum BuilderSeal<Seal: ExposedSeal> {
201    Revealed(Seal),
202    #[from]
203    Concealed(SecretSeal),
204}
205
206impl<Seal: ExposedSeal> From<Outpoint> for BuilderSeal<Seal>
207where Seal: From<Outpoint>
208{
209    fn from(seal: Outpoint) -> Self { BuilderSeal::Revealed(seal.into()) }
210}
211
212impl<Seal: ExposedSeal> From<GraphSeal> for BuilderSeal<Seal>
213where Seal: From<GraphSeal>
214{
215    fn from(seal: GraphSeal) -> Self { BuilderSeal::Revealed(seal.into()) }
216}
217
218impl<Seal: ExposedSeal> From<GenesisSeal> for BuilderSeal<Seal>
219where Seal: From<GenesisSeal>
220{
221    fn from(seal: GenesisSeal) -> Self { BuilderSeal::Revealed(seal.into()) }
222}