1use alloc::boxed::Box;
2use alloc::string::String;
3use alloc::vec::Vec;
4
5use serde::{Deserialize, Serialize};
6use umbral_pre::{Capsule, CapsuleFrag, PublicKey, Signature, Signer, VerifiedCapsuleFrag};
7
8use crate::conditions::{Conditions, Context};
9use crate::hrac::HRAC;
10use crate::key_frag::EncryptedKeyFrag;
11use crate::versioning::{
12 messagepack_deserialize, messagepack_serialize, ProtocolObject, ProtocolObjectInner,
13};
14use crate::VerificationError;
15
16#[derive(PartialEq, Debug, Serialize, Deserialize)]
18pub struct ReencryptionRequest {
19 pub capsules: Box<[Capsule]>,
21 pub hrac: HRAC,
23 pub encrypted_kfrag: EncryptedKeyFrag,
25 pub publisher_verifying_key: PublicKey,
27 pub bob_verifying_key: PublicKey,
29 pub conditions: Option<Conditions>,
31 pub context: Option<Context>,
33}
34
35impl ReencryptionRequest {
36 pub fn new(
38 capsules: &[Capsule],
39 hrac: &HRAC,
40 encrypted_kfrag: &EncryptedKeyFrag,
41 publisher_verifying_key: &PublicKey,
42 bob_verifying_key: &PublicKey,
43 conditions: Option<&Conditions>,
44 context: Option<&Context>,
45 ) -> Self {
46 Self {
47 capsules: capsules.to_vec().into(),
48 hrac: *hrac,
49 encrypted_kfrag: encrypted_kfrag.clone(),
50 publisher_verifying_key: *publisher_verifying_key,
51 bob_verifying_key: *bob_verifying_key,
52 conditions: conditions.cloned(),
53 context: context.cloned(),
54 }
55 }
56}
57
58impl<'a> ProtocolObjectInner<'a> for ReencryptionRequest {
59 fn brand() -> [u8; 4] {
60 *b"ReRq"
61 }
62
63 fn version() -> (u16, u16) {
64 (3, 0)
65 }
66
67 fn unversioned_to_bytes(&self) -> Box<[u8]> {
68 messagepack_serialize(&self)
69 }
70
71 fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
72 if minor_version == 0 {
73 Some(messagepack_deserialize(bytes))
74 } else {
75 None
76 }
77 }
78}
79
80impl<'a> ProtocolObject<'a> for ReencryptionRequest {}
81
82#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
84pub struct ReencryptionResponse {
85 cfrags: Box<[CapsuleFrag]>,
86 signature: Signature,
87}
88
89fn message_to_sign(capsules: &[Capsule], cfrags: &[CapsuleFrag]) -> Vec<u8> {
90 let capsule_bytes = capsules.iter().fold(Vec::<u8>::new(), |mut acc, capsule| {
91 acc.extend(messagepack_serialize(capsule).as_ref());
92 acc
93 });
94
95 let cfrag_bytes = cfrags.iter().fold(Vec::<u8>::new(), |mut acc, cfrag| {
96 acc.extend(messagepack_serialize(cfrag).as_ref());
97 acc
98 });
99
100 [capsule_bytes, cfrag_bytes].concat()
101}
102
103impl ReencryptionResponse {
104 pub fn new<'a>(
106 signer: &Signer,
107 capsules_and_vcfrags: impl IntoIterator<Item = (&'a Capsule, VerifiedCapsuleFrag)>,
108 ) -> Self {
109 let (capsules, vcfrags): (Vec<_>, Vec<_>) = capsules_and_vcfrags.into_iter().unzip();
110
111 let cfrags: Vec<_> = vcfrags
113 .into_iter()
114 .map(|vcfrag| vcfrag.unverify())
115 .collect();
116
117 let capsules: Vec<_> = capsules.into_iter().cloned().collect();
118
119 let signature = signer.sign(&message_to_sign(&capsules, &cfrags));
120
121 ReencryptionResponse {
122 cfrags: cfrags.into_boxed_slice(),
123 signature,
124 }
125 }
126
127 #[allow(clippy::result_large_err)]
129 pub fn verify(
130 self,
131 capsules: &[Capsule],
132 alice_verifying_key: &PublicKey,
133 ursula_verifying_key: &PublicKey,
134 policy_encrypting_key: &PublicKey,
135 bob_encrypting_key: &PublicKey,
136 ) -> Result<Box<[VerifiedCapsuleFrag]>, VerificationError> {
137 if capsules.len() != self.cfrags.len() {
138 return Err(VerificationError);
140 }
141
142 if !self.signature.verify(
144 ursula_verifying_key,
145 &message_to_sign(capsules, &self.cfrags),
146 ) {
147 return Err(VerificationError);
148 }
149
150 let vcfrags = self
151 .cfrags
152 .into_vec()
153 .into_iter()
154 .zip(capsules.iter())
155 .map(|(cfrag, capsule)| {
156 cfrag.verify(
157 capsule,
158 alice_verifying_key,
159 policy_encrypting_key,
160 bob_encrypting_key,
161 )
162 })
163 .collect::<Result<Vec<_>, _>>();
164
165 vcfrags
168 .map(|vcfrags| vcfrags.into_boxed_slice())
169 .map_err(|_err| VerificationError)
170 }
171}
172
173impl<'a> ProtocolObjectInner<'a> for ReencryptionResponse {
174 fn brand() -> [u8; 4] {
175 *b"ReRs"
176 }
177
178 fn version() -> (u16, u16) {
179 (3, 0)
180 }
181
182 fn unversioned_to_bytes(&self) -> Box<[u8]> {
183 messagepack_serialize(&self)
184 }
185
186 fn unversioned_from_bytes(minor_version: u16, bytes: &[u8]) -> Option<Result<Self, String>> {
187 if minor_version == 0 {
188 Some(messagepack_deserialize(bytes))
189 } else {
190 None
191 }
192 }
193}
194
195impl<'a> ProtocolObject<'a> for ReencryptionResponse {}
196
197#[cfg(test)]
198mod tests {
199 use umbral_pre::SecretKey;
200 use umbral_pre::{encrypt, generate_kfrags, Signer};
201
202 use crate::{Conditions, Context, EncryptedKeyFrag, HRAC};
203
204 use super::ReencryptionRequest;
205
206 #[test]
207 fn conditions_and_context_are_different() {
208 let some_secret = SecretKey::random();
209 let some_trinket = some_secret.public_key();
210
211 let _another_secret = SecretKey::random();
212 let another_trinket = some_secret.public_key();
213
214 let encryption_result = encrypt(&some_trinket, b"peace at dawn");
215
216 let (capsule, _ciphertext) = encryption_result.unwrap();
217
218 let hrac = HRAC::new(&some_trinket, &another_trinket, &[42]);
219
220 let signer = Signer::new(SecretKey::random());
221
222 let verified_kfrags =
223 generate_kfrags(&some_secret, &another_trinket, &signer, 5, 8, true, true);
224 let verified_kfrags_vector = verified_kfrags.into_vec();
225 let one_verified_krag_in_particular = verified_kfrags_vector[0].clone();
226 let encrypted_kfrag = EncryptedKeyFrag::new(
227 &signer,
228 &another_trinket,
229 &hrac,
230 one_verified_krag_in_particular,
231 );
232
233 let request = ReencryptionRequest::new(
234 &[capsule],
235 &hrac,
236 &encrypted_kfrag,
237 &some_trinket,
238 &another_trinket,
239 Some(&Conditions::new("abcd")),
240 Some(&Context::new("efgh")),
241 );
242 let conditions = request.conditions.unwrap();
243 assert_eq!(conditions.as_ref(), "abcd");
244
245 let context = request.context.unwrap();
246 assert_eq!(context.as_ref(), "efgh");
247 }
248}