Skip to content

Commit 52b8593

Browse files
committed
seal: rewrite crate
1 parent 58e2f8a commit 52b8593

File tree

1 file changed

+133
-38
lines changed

1 file changed

+133
-38
lines changed

single_use_seals/src/lib.rs

Lines changed: 133 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,6 @@
1919
// See the License for the specific language governing permissions and
2020
// limitations under the License.
2121

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-
missing_docs
31-
)]
3222
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3323

3424
//! # Single-use-seals
@@ -113,6 +103,10 @@
113103
//! <https://petertodd.org/2017/scalable-single-use-seal-asset-transfer>
114104
115105
use core::borrow::Borrow;
106+
use core::convert::Infallible;
107+
use core::error::Error;
108+
use core::fmt::{self, Debug, Display, Formatter};
109+
use core::marker::PhantomData;
116110

117111
/// Trait for proof-of-publication medium on which the seals are defined,
118112
/// closed, verified and which can be used for convenience operations related to
@@ -132,52 +126,153 @@ use core::borrow::Borrow;
132126
///
133127
/// To read more on proof-of-publication please check
134128
/// <https://petertodd.org/2014/setting-the-record-proof-of-publication>
135-
pub trait Seal: Sized {
129+
pub trait SingleUseSeal: Clone + Debug + Display {
136130
/// Single-use seal parameters, which allow to differentiate alternative
137131
/// forms of single-use seals from each other.
138132
type Params;
139133

140134
/// Seal parameters which the type commits to.
141135
const PARAMS: Self::Params;
142136

143-
/// Associated type for the witness produced by the single-use-seal close
144-
/// procedure
145-
type Witness: SealWitness<Self>;
137+
/// Message type that is supported by the current single-use-seal.
138+
type Message: Copy;
146139

147-
/// Message type that is supported by the current single-use-seal
148-
type Message;
140+
type PubWitness: PublishedWitness<Self>;
141+
type CliWitness: ClientSideWitness<Seal = Self>;
142+
}
143+
144+
pub trait ClientSideWitness {
145+
type Seal: SingleUseSeal;
146+
type Error: Clone + Error;
147+
148+
fn includes_seal(&self, seal: impl Borrow<Self::Seal>) -> bool;
149+
fn convolve_commit(
150+
&self,
151+
msg: <Self::Seal as SingleUseSeal>::Message,
152+
) -> Result<<Self::Seal as SingleUseSeal>::Message, Self::Error>;
153+
}
154+
155+
#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Default)]
156+
pub struct NoWitness<Seal: SingleUseSeal>(PhantomData<Seal>);
157+
impl<Seal: SingleUseSeal> ClientSideWitness for NoWitness<Seal> {
158+
type Seal = Seal;
159+
type Error = Infallible;
160+
161+
fn includes_seal(&self, _: impl Borrow<Self::Seal>) -> bool { false }
162+
163+
fn convolve_commit(
164+
&self,
165+
msg: <Self::Seal as SingleUseSeal>::Message,
166+
) -> Result<<Self::Seal as SingleUseSeal>::Message, Self::Error> {
167+
Ok(msg)
168+
}
169+
}
149170

171+
pub trait PublishedWitness<Seal: SingleUseSeal> {
150172
/// Publication id that may be used for referencing publication of
151173
/// witness data in the medium. By default, set `()`, so [`SealProtocol`]
152-
/// may not implement publication id and related functions
153-
type PublicationId;
174+
/// may not implement publication id and related functions.
175+
type PubId: Copy + Ord + Debug + Display;
176+
177+
type Error: Clone + Error;
178+
179+
fn pub_id(&self) -> Self::PubId;
180+
fn includes_seal(&self, seal: impl Borrow<Seal>) -> bool;
181+
fn verify_commitment(&self, msg: Seal::Message) -> Result<(), Self::Error>;
154182
}
155183

156-
/// Seal witness which can verify seal or multiple seals.
157-
pub trait SealWitness<S: Seal<Witness = Self>> {
158-
/// Message type that is supported by the current single-use-seal
159-
type Message;
184+
/// Seal closing witness.
185+
#[derive(Clone, Copy)]
186+
pub struct SealWitness<Seal>
187+
where Seal: SingleUseSeal
188+
{
189+
pub published: Seal::PubWitness,
190+
pub client: Seal::CliWitness,
191+
_phantom: PhantomData<Seal>,
192+
}
160193

161-
/// Error type that contains reasons of medium access failure
162-
type Error: std::error::Error;
194+
impl<Seal> SealWitness<Seal>
195+
where Seal: SingleUseSeal
196+
{
197+
pub fn includes_seal(&self, seal: impl Borrow<Seal>) -> bool {
198+
self.published.borrow().includes_seal(seal.borrow()) ||
199+
self.client.borrow().includes_seal(seal)
200+
}
163201

164-
/// Verifies that the seal was indeed closed over the message with the
165-
/// provided seal closure witness.
166-
fn verify_seal(&self, seal: impl Borrow<S>, msg: &Self::Message) -> Result<(), Self::Error>;
202+
pub fn verify_seal_closing(
203+
&self,
204+
seal: impl Borrow<Seal>,
205+
message: Seal::Message,
206+
) -> Result<(), SealError<Seal>> {
207+
self.verify_seals_closing([seal], message)
208+
}
167209

168-
/// Performs batch verification of the seals.
169-
///
170-
/// Default implementation iterates through the seals and calls
171-
/// [`Self::verify_seal`] for each of them, returning `false` on first
172-
/// failure (not verifying the rest of seals).
173-
fn verify_many_seals(
210+
pub fn verify_seals_closing(
174211
&self,
175-
seals: impl IntoIterator<Item = impl Borrow<S>>,
176-
msg: &Self::Message,
177-
) -> Result<(), Self::Error> {
212+
seals: impl IntoIterator<Item = impl Borrow<Seal>>,
213+
message: Seal::Message,
214+
) -> Result<(), SealError<Seal>> {
215+
// ensure that witness includes all seals
178216
for seal in seals {
179-
self.verify_seal(seal, msg)?;
217+
self.includes_seal(seal.borrow())
218+
.then_some(())
219+
.ok_or(SealError::NotIncluded(seal.borrow().clone(), self.published.pub_id()))?;
220+
}
221+
// ensure that published witness contains the commitment to the
222+
// f(message), where `f` is defined in the client-side witness
223+
let f_msg = self
224+
.client
225+
.convolve_commit(message)
226+
.map_err(SealError::Client)?;
227+
self.published
228+
.verify_commitment(f_msg)
229+
.map_err(SealError::Published)
230+
}
231+
}
232+
233+
#[derive(Clone)]
234+
pub enum SealError<Seal: SingleUseSeal> {
235+
NotIncluded(Seal, <Seal::PubWitness as PublishedWitness<Seal>>::PubId),
236+
Published(<Seal::PubWitness as PublishedWitness<Seal>>::Error),
237+
Client(<Seal::CliWitness as ClientSideWitness>::Error),
238+
}
239+
240+
impl<Seal: SingleUseSeal> Debug for SealError<Seal> {
241+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
242+
match self {
243+
SealError::NotIncluded(seal, pub_id) => f
244+
.debug_tuple("SealError::NotIncluded")
245+
.field(seal)
246+
.field(pub_id)
247+
.finish(),
248+
SealError::Published(err) => f.debug_tuple("SealError::Published").field(err).finish(),
249+
SealError::Client(err) => f.debug_tuple("SealError::Client(err").field(err).finish(),
250+
}
251+
}
252+
}
253+
254+
impl<Seal: SingleUseSeal> Display for SealError<Seal> {
255+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
256+
match self {
257+
SealError::NotIncluded(seal, pub_id) => {
258+
write!(f, "seal {seal} is not included in the witness {pub_id}")
259+
}
260+
SealError::Published(err) => Display::fmt(err, f),
261+
SealError::Client(err) => Display::fmt(err, f),
262+
}
263+
}
264+
}
265+
266+
impl<Seal: SingleUseSeal> Error for SealError<Seal>
267+
where
268+
<<Seal as SingleUseSeal>::PubWitness as PublishedWitness<Seal>>::Error: 'static,
269+
<<Seal as SingleUseSeal>::CliWitness as ClientSideWitness>::Error: 'static,
270+
{
271+
fn source(&self) -> Option<&(dyn Error + 'static)> {
272+
match self {
273+
SealError::NotIncluded(..) => None,
274+
SealError::Published(e) => Some(e),
275+
SealError::Client(e) => Some(e),
180276
}
181-
Ok(())
182277
}
183278
}

0 commit comments

Comments
 (0)