@@ -3,14 +3,33 @@ use crate::curve::{CurvePoint, CurveScalar};
3
3
use crate :: hashing_ds:: { hash_capsule_points, hash_to_polynomial_arg, hash_to_shared_secret} ;
4
4
use crate :: keys:: { PublicKey , SecretKey } ;
5
5
use crate :: params:: Parameters ;
6
- use crate :: traits:: SerializableToArray ;
6
+ use crate :: traits:: { DeserializationError , SerializableToArray } ;
7
7
8
8
use alloc:: vec:: Vec ;
9
9
10
10
use generic_array:: sequence:: Concat ;
11
11
use generic_array:: GenericArray ;
12
12
use typenum:: op;
13
13
14
+ /// Errors that can happen when opening a `Capsule` using reencrypted `CapsuleFrag` objects.
15
+ #[ derive( Debug , PartialEq ) ]
16
+ pub enum OpenReencryptedError {
17
+ /// An empty capsule fragment list is given.
18
+ NoCapsuleFrags ,
19
+ /// Capsule fragments are mismatched (originated from [`KeyFrag`](crate::KeyFrag) objects
20
+ /// generated by different [`generate_kfrags`](crate::generate_kfrags) calls).
21
+ MismatchedCapsuleFrags ,
22
+ /// Some of the given capsule fragments are repeated.
23
+ RepeatingCapsuleFrags ,
24
+ /// An internally hashed value is zero.
25
+ /// See [rust-umbral#39](https://github.com/nucypher/rust-umbral/issues/39).
26
+ ZeroHash ,
27
+ /// Internal validation of the result has failed.
28
+ /// Can be caused by an incorrect (possibly modified) capsule
29
+ /// or some of the capsule fragments.
30
+ ValidationFailed ,
31
+ }
32
+
14
33
/// Encapsulated symmetric key used to encrypt the plaintext.
15
34
#[ derive( Clone , Copy , Debug , PartialEq ) ]
16
35
pub struct Capsule {
@@ -34,11 +53,12 @@ impl SerializableToArray for Capsule {
34
53
. concat ( self . signature . to_array ( ) )
35
54
}
36
55
37
- fn from_array ( arr : & GenericArray < u8 , Self :: Size > ) -> Option < Self > {
56
+ fn from_array ( arr : & GenericArray < u8 , Self :: Size > ) -> Result < Self , DeserializationError > {
38
57
let ( point_e, rest) = CurvePoint :: take ( * arr) ?;
39
58
let ( point_v, rest) = CurvePoint :: take ( rest) ?;
40
59
let signature = CurveScalar :: take_last ( rest) ?;
41
60
Self :: new_verified ( point_e, point_v, signature)
61
+ . ok_or ( DeserializationError :: ConstructionFailure )
42
62
}
43
63
}
44
64
@@ -104,15 +124,15 @@ impl Capsule {
104
124
receiving_sk : & SecretKey ,
105
125
delegating_pk : & PublicKey ,
106
126
cfrags : & [ CapsuleFrag ] ,
107
- ) -> Option < CurvePoint > {
127
+ ) -> Result < CurvePoint , OpenReencryptedError > {
108
128
if cfrags. is_empty ( ) {
109
- return None ;
129
+ return Err ( OpenReencryptedError :: NoCapsuleFrags ) ;
110
130
}
111
131
112
132
let precursor = cfrags[ 0 ] . precursor ;
113
133
114
134
if !cfrags. iter ( ) . all ( |cfrag| cfrag. precursor == precursor) {
115
- return None ;
135
+ return Err ( OpenReencryptedError :: MismatchedCapsuleFrags ) ;
116
136
}
117
137
118
138
let pub_key = PublicKey :: from_secret_key ( receiving_sk) . to_point ( ) ;
@@ -128,9 +148,10 @@ impl Capsule {
128
148
let mut e_prime = CurvePoint :: identity ( ) ;
129
149
let mut v_prime = CurvePoint :: identity ( ) ;
130
150
for ( i, cfrag) in ( & cfrags) . iter ( ) . enumerate ( ) {
131
- // There is a minuscule probability that two elements of `lc` are equal,
151
+ // There is a minuscule probability that coefficients for two different frags are equal,
132
152
// in which case we'd rather fail gracefully.
133
- let lambda_i = lambda_coeff ( & lc, i) ?;
153
+ let lambda_i =
154
+ lambda_coeff ( & lc, i) . ok_or ( OpenReencryptedError :: RepeatingCapsuleFrags ) ?;
134
155
e_prime = & e_prime + & ( & cfrag. point_e1 * & lambda_i) ;
135
156
v_prime = & v_prime + & ( & cfrag. point_v1 * & lambda_i) ;
136
157
}
@@ -149,14 +170,14 @@ impl Capsule {
149
170
// Technically, it is supposed to be non-zero by the choice of `precursor`,
150
171
// but if is was somehow replaced by an incorrect value,
151
172
// we'd rather fail gracefully than panic.
152
- let inv_d = inv_d_opt?;
173
+ let inv_d = inv_d_opt. ok_or ( OpenReencryptedError :: ZeroHash ) ?;
153
174
154
175
if & orig_pub_key * & ( & s * & inv_d) != & ( & e_prime * & h) + & v_prime {
155
- return None ;
176
+ return Err ( OpenReencryptedError :: ValidationFailed ) ;
156
177
}
157
178
158
179
let shared_key = & ( & e_prime + & v_prime) * & d;
159
- Some ( shared_key)
180
+ Ok ( shared_key)
160
181
}
161
182
}
162
183
@@ -177,7 +198,7 @@ mod tests {
177
198
178
199
use alloc:: vec:: Vec ;
179
200
180
- use super :: Capsule ;
201
+ use super :: { Capsule , OpenReencryptedError } ;
181
202
use crate :: {
182
203
encrypt, generate_kfrags, reencrypt, CapsuleFrag , PublicKey , SecretKey , SerializableToArray ,
183
204
} ;
@@ -220,9 +241,10 @@ mod tests {
220
241
assert_eq ! ( key_seed, key_seed_reenc) ;
221
242
222
243
// Empty cfrag vector
223
- assert ! ( capsule
224
- . open_reencrypted( & receiving_sk, & delegating_pk, & [ ] )
225
- . is_none( ) ) ;
244
+ assert_eq ! (
245
+ capsule. open_reencrypted( & receiving_sk, & delegating_pk, & [ ] ) ,
246
+ Err ( OpenReencryptedError :: NoCapsuleFrags )
247
+ ) ;
226
248
227
249
// Mismatched cfrags - each `generate_kfrags()` uses new randoms.
228
250
let kfrags2 = generate_kfrags ( & delegating_sk, & receiving_pk, & signing_sk, 2 , 3 , true , true ) ;
@@ -237,14 +259,16 @@ mod tests {
237
259
. cloned ( )
238
260
. chain ( cfrags2[ 1 ..2 ] . iter ( ) . cloned ( ) )
239
261
. collect ( ) ;
240
- assert ! ( capsule
241
- . open_reencrypted( & receiving_sk, & delegating_pk, & mismatched_cfrags)
242
- . is_none( ) ) ;
262
+ assert_eq ! (
263
+ capsule. open_reencrypted( & receiving_sk, & delegating_pk, & mismatched_cfrags) ,
264
+ Err ( OpenReencryptedError :: MismatchedCapsuleFrags )
265
+ ) ;
243
266
244
267
// Mismatched capsule
245
268
let ( capsule2, _key_seed) = Capsule :: from_public_key ( & delegating_pk) ;
246
- assert ! ( capsule2
247
- . open_reencrypted( & receiving_sk, & delegating_pk, & cfrags)
248
- . is_none( ) ) ;
269
+ assert_eq ! (
270
+ capsule2. open_reencrypted( & receiving_sk, & delegating_pk, & cfrags) ,
271
+ Err ( OpenReencryptedError :: ValidationFailed )
272
+ ) ;
249
273
}
250
274
}
0 commit comments