1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
use bc_components::Error as ComponentsError;
use thiserror::Error;
/// Error types returned when operating on Gordian Envelopes.
///
/// These errors capture various conditions that can occur when working with
/// envelopes, including structure validation, operation constraints, and
/// extension-specific errors.
///
/// The errors are organized by category, reflecting the base envelope
/// specification and various extensions defined in the Gordian Envelope
/// Internet Draft and Blockchain Commons Research (BCR) documents.
#[derive(Debug, Error)]
pub enum Error {
//
// Base Specification
/// Returned when attempting to compress or encrypt an envelope that has
/// already been elided.
///
/// This error occurs because an elided envelope only contains a digest
/// reference and no longer has a subject that can be compressed or
/// encrypted.
#[error("envelope was elided, so it cannot be compressed or encrypted")]
AlreadyElided,
/// Returned when attempting to retrieve an assertion by predicate, but
/// multiple matching assertions exist.
///
/// For queries that expect a single result (like `object_for_predicate`),
/// having multiple matching assertions is ambiguous and requires more
/// specific targeting.
#[error("more than one assertion matches the predicate")]
AmbiguousPredicate,
/// Returned when a digest validation fails.
///
/// This can occur when unwrapping an envelope, verifying signatures, or
/// other operations that rely on the integrity of envelope digests.
#[error("digest did not match")]
InvalidDigest,
/// Returned when an envelope's format is invalid.
///
/// This typically occurs during parsing or decoding of an envelope from
/// CBOR.
#[error("invalid format")]
InvalidFormat,
/// Returned when a digest is expected but not found.
///
/// This can occur when working with envelope structures that require digest
/// information, such as when working with elided envelopes.
#[error("a digest was expected but not found")]
MissingDigest,
/// Returned when attempting to retrieve an assertion by predicate, but no
/// matching assertion exists.
///
/// This error occurs with functions like `object_for_predicate` when the
/// specified predicate doesn't match any assertion in the envelope.
#[error("no assertion matches the predicate")]
NonexistentPredicate,
/// Returned when attempting to unwrap an envelope that wasn't wrapped.
///
/// This error occurs when calling `Envelope::try_unwrap` on an
/// envelope that doesn't have the wrapped format.
#[error("cannot unwrap an envelope that was not wrapped")]
NotWrapped,
/// Returned when expecting an envelope's subject to be a leaf, but it
/// isn't.
///
/// This error occurs when calling methods that require access to a leaf
/// value but the envelope's subject is an assertion, node, or elided.
#[error("the envelope's subject is not a leaf")]
NotLeaf,
/// Returned when expecting an envelope's subject to be an assertion, but it
/// isn't.
///
/// This error occurs when calling methods that require an assertion
/// structure but the envelope's subject has a different format.
#[error("the envelope's subject is not an assertion")]
NotAssertion,
/// Returned
#[error("assertion must be a map with exactly one element")]
InvalidAssertion,
//
// Attachments Extension
/// Returned when an attachment's format is invalid.
///
/// This error occurs when an envelope contains an attachment with an
/// invalid structure according to the Envelope Attachment specification
/// (BCR-2023-006).
#[cfg(feature = "attachment")]
#[error("invalid attachment")]
InvalidAttachment,
/// Returned when an attachment is requested but does not exist.
///
/// This error occurs when attempting to retrieve an attachment by ID that
/// doesn't exist in the envelope.
#[cfg(feature = "attachment")]
#[error("nonexistent attachment")]
NonexistentAttachment,
/// Returned when multiple attachments match a single query.
///
/// This error occurs when multiple attachments have the same ID, making
/// it ambiguous which attachment should be returned.
#[cfg(feature = "attachment")]
#[error("abiguous attachment")]
AmbiguousAttachment,
//
// Edges Extension
/// Returned when an edge is missing the required `'isA'` assertion.
#[cfg(feature = "edge")]
#[error("edge missing 'isA' assertion")]
EdgeMissingIsA,
/// Returned when an edge is missing the required `'source'` assertion.
#[cfg(feature = "edge")]
#[error("edge missing 'source' assertion")]
EdgeMissingSource,
/// Returned when an edge is missing the required `'target'` assertion.
#[cfg(feature = "edge")]
#[error("edge missing 'target' assertion")]
EdgeMissingTarget,
/// Returned when an edge has duplicate `'isA'` assertions.
#[cfg(feature = "edge")]
#[error("edge has duplicate 'isA' assertions")]
EdgeDuplicateIsA,
/// Returned when an edge has duplicate `'source'` assertions.
#[cfg(feature = "edge")]
#[error("edge has duplicate 'source' assertions")]
EdgeDuplicateSource,
/// Returned when an edge has duplicate `'target'` assertions.
#[cfg(feature = "edge")]
#[error("edge has duplicate 'target' assertions")]
EdgeDuplicateTarget,
/// Returned when an edge has an assertion that is not one of the
/// three required predicates (`'isA'`, `'source'`, `'target'`).
#[cfg(feature = "edge")]
#[error("edge has unexpected assertion")]
EdgeUnexpectedAssertion,
/// Returned when an edge is requested but does not exist.
#[cfg(feature = "edge")]
#[error("nonexistent edge")]
NonexistentEdge,
/// Returned when multiple edges match a single query.
#[cfg(feature = "edge")]
#[error("ambiguous edge")]
AmbiguousEdge,
//
// Compression Extension
/// Returned when attempting to compress an envelope that is already
/// compressed.
///
/// This error occurs when calling compression functions on an envelope that
/// already has compressed content, as defined in BCR-2023-005.
#[cfg(feature = "compress")]
#[error("envelope was already compressed")]
AlreadyCompressed,
/// Returned when attempting to decompress an envelope that is not
/// compressed.
///
/// This error occurs when calling decompression functions on an envelope
/// that doesn't contain compressed content.
#[cfg(feature = "compress")]
#[error("cannot decompress an envelope that was not compressed")]
NotCompressed,
//
// Symmetric Encryption Extension
/// Returned when attempting to encrypt an envelope that is already
/// encrypted or compressed.
///
/// This error occurs to prevent multiple layers of encryption or encryption
/// of compressed data, which could reduce security, as defined in
/// BCR-2023-004.
#[cfg(feature = "encrypt")]
#[error(
"envelope was already encrypted or compressed, so it cannot be encrypted"
)]
AlreadyEncrypted,
/// Returned when attempting to decrypt an envelope that is not encrypted.
///
/// This error occurs when calling decryption functions on an envelope that
/// doesn't contain encrypted content.
#[cfg(feature = "encrypt")]
#[error("cannot decrypt an envelope that was not encrypted")]
NotEncrypted,
//
// Known Values Extension
/// Returned when expecting an envelope's subject to be a known value, but
/// it isn't.
///
/// This error occurs when calling methods that require a known value (as
/// defined in BCR-2023-003) but the envelope's subject is a different
/// type.
#[cfg(feature = "known_value")]
#[error("the envelope's subject is not a known value")]
NotKnownValue,
//
// Public Key Encryption Extension
/// Returned when attempting to decrypt an envelope with a recipient that
/// doesn't match.
///
/// This error occurs when trying to use a private key to decrypt an
/// envelope that wasn't encrypted for the corresponding public key.
#[cfg(feature = "recipient")]
#[error("unknown recipient")]
UnknownRecipient,
//
// Encrypted Key Extension
/// Returned when attempting to decrypt an envelope with a secret that
/// doesn't match.
///
/// This error occurs when trying to use a secret that does not correspond
/// to the expected recipient, preventing successful decryption.
#[cfg(feature = "secret")]
#[error("secret not found")]
UnknownSecret,
//
// Public Key Signing Extension
/// Returned when a signature verification fails.
///
/// This error occurs when a signature does not validate against its
/// purported public key.
#[cfg(feature = "signature")]
#[error("could not verify a signature")]
UnverifiedSignature,
/// Returned when the outer signature object type is not `Signature`.
#[cfg(feature = "signature")]
#[error("unexpected outer signature object type")]
InvalidOuterSignatureType,
/// Returned when the inner signature object type is not `Signature`.
#[cfg(feature = "signature")]
#[error("unexpected inner signature object type")]
InvalidInnerSignatureType,
/// Returned when the inner signature is not made with the same key as the
/// outer signature.
#[cfg(feature = "signature")]
#[error("inner signature not made with same key as outer signature")]
UnverifiedInnerSignature,
/// Returned when the signature object is not a `Signature`.
#[cfg(feature = "signature")]
#[error("unexpected signature object type")]
InvalidSignatureType,
//
// SSKR Extension
/// Returned when SSKR shares are invalid or insufficient for
/// reconstruction.
///
/// This error occurs when attempting to join SSKR shares that are
/// malformed, from different splits, or insufficient to meet the
/// recovery threshold.
#[cfg(feature = "sskr")]
#[error("invalid SSKR shares")]
InvalidShares,
//
// Types Extension
/// Returned when an envelope contains an invalid type.
///
/// This error occurs when an envelope's type information doesn't match
/// the expected format or value.
#[cfg(feature = "types")]
#[error("invalid type")]
InvalidType,
/// Returned when an envelope contains ambiguous type information.
///
/// This error occurs when multiple type assertions exist that conflict
/// with each other or create ambiguity about the envelope's type.
#[cfg(feature = "types")]
#[error("ambiguous type")]
AmbiguousType,
/// Returned when the subject of the envelope is not the unit value.
#[cfg(feature = "known_value")]
#[error("the subject of the envelope is not the unit value")]
SubjectNotUnit,
//
// Expressions Extension
/// Returned when a response envelope has an unexpected ID.
///
/// This error occurs when processing a response envelope and the ID doesn't
/// match the expected request ID, as defined in BCR-2023-012.
#[cfg(feature = "expression")]
#[error("unexpected response ID")]
UnexpectedResponseID,
/// Returned when a response envelope is invalid.
#[cfg(feature = "expression")]
#[error("invalid response")]
InvalidResponse,
/// SSKR error
#[cfg(feature = "sskr")]
#[error("sskr error: {0}")]
SSKR(#[from] bc_components::SSKRError),
/// dcbor error
#[error("dcbor error: {0}")]
Cbor(#[from] dcbor::Error),
/// Components error
#[error("components error: {0}")]
Components(#[from] ComponentsError),
/// General error
#[error("general error: {0}")]
General(String),
}
impl Error {
pub fn msg(msg: impl Into<String>) -> Self { Error::General(msg.into()) }
}
impl From<Error> for dcbor::Error {
fn from(error: Error) -> dcbor::Error {
match error {
Error::Cbor(err) => err,
_ => dcbor::Error::Custom(error.to_string()),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;