1use alloc::boxed::Box;
2use core::fmt;
3
4use rand_core::{CryptoRng, RngCore};
5
6#[cfg(feature = "serde")]
7use serde::{Deserialize, Serialize};
8
9use crate::capsule::Capsule;
10use crate::curve::{CurvePoint, CurveScalar, NonZeroCurveScalar};
11use crate::hashing_ds::{hash_to_cfrag_verification, kfrag_signature_message};
12use crate::key_frag::{KeyFrag, KeyFragID};
13use crate::keys::{PublicKey, Signature};
14use crate::secret_box::SecretBox;
15use crate::traits::fmt_public;
16
17#[cfg(feature = "default-serialization")]
18use crate::{DefaultDeserialize, DefaultSerialize};
19
20#[derive(Clone, Debug, PartialEq)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub(crate) struct CapsuleFragProof {
23 pub(crate) point_e2: CurvePoint,
24 pub(crate) point_v2: CurvePoint,
25 pub(crate) kfrag_commitment: CurvePoint,
26 pub(crate) kfrag_pok: CurvePoint,
27 pub(crate) signature: CurveScalar,
28 pub(crate) kfrag_signature: Signature,
29}
30
31impl CapsuleFragProof {
32 #[allow(clippy::many_single_char_names)]
33 fn from_kfrag_and_cfrag(
34 rng: &mut (impl CryptoRng + RngCore),
35 capsule: &Capsule,
36 kfrag: KeyFrag,
37 cfrag_e1: &CurvePoint,
38 cfrag_v1: &CurvePoint,
39 ) -> Self {
40 let params = capsule.params;
41
42 let rk = kfrag.key;
43 let t = SecretBox::new(NonZeroCurveScalar::random(rng));
44
45 let e = capsule.point_e;
48 let v = capsule.point_v;
49
50 let e1 = cfrag_e1;
51 let v1 = cfrag_v1;
52
53 let u = params.u;
54 let u1 = kfrag.proof.commitment;
55
56 let e2 = &e * t.as_secret();
57 let v2 = &v * t.as_secret();
58 let u2 = &u * t.as_secret();
59
60 let h = hash_to_cfrag_verification(&e, e1, &e2, &v, v1, &v2, &u, &u1, &u2);
61
62 let z3 = &(&rk * &h) + t.as_secret();
65
66 Self {
67 point_e2: e2,
68 point_v2: v2,
69 kfrag_commitment: u1,
70 kfrag_pok: u2,
71 signature: z3,
72 kfrag_signature: kfrag.proof.signature_for_receiver,
73 }
74 }
75}
76
77#[derive(Clone, Debug, PartialEq)]
79#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
80pub struct CapsuleFrag {
81 pub(crate) point_e1: CurvePoint,
82 pub(crate) point_v1: CurvePoint,
83 pub(crate) kfrag_id: KeyFragID,
84 pub(crate) precursor: CurvePoint,
85 pub(crate) proof: CapsuleFragProof,
86}
87
88impl fmt::Display for CapsuleFrag {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 fmt_public("CapsuleFrag", &self.kfrag_id, f)
91 }
92}
93
94#[derive(Debug, Copy, Clone, PartialEq, Eq)]
96pub enum CapsuleFragVerificationError {
97 IncorrectKeyFragSignature,
99 IncorrectReencryption,
101}
102
103impl fmt::Display for CapsuleFragVerificationError {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 match self {
106 Self::IncorrectKeyFragSignature => write!(f, "Invalid CapsuleFrag signature"),
107 Self::IncorrectReencryption => write!(f, "Failed to verify reencryption proof"),
108 }
109 }
110}
111
112impl CapsuleFrag {
113 fn reencrypted(
114 rng: &mut (impl CryptoRng + RngCore),
115 capsule: &Capsule,
116 kfrag: KeyFrag,
117 ) -> Self {
118 let rk = kfrag.key;
119 let e1 = &capsule.point_e * &rk;
120 let v1 = &capsule.point_v * &rk;
121 let id = kfrag.id;
122 let precursor = kfrag.precursor;
123 let proof = CapsuleFragProof::from_kfrag_and_cfrag(rng, capsule, kfrag, &e1, &v1);
124
125 Self {
126 point_e1: e1,
127 point_v1: v1,
128 kfrag_id: id,
129 precursor,
130 proof,
131 }
132 }
133
134 pub fn to_bytes_simple(&self) -> Box<[u8]> {
147 let e1 = self.point_e1.to_compressed_array();
148 let v1 = self.point_v1.to_compressed_array();
149 let precursor = self.precursor.to_compressed_array();
150
151 let e2 = self.proof.point_e2.to_compressed_array();
152 let v2 = self.proof.point_v2.to_compressed_array();
153 let commitment = self.proof.kfrag_commitment.to_compressed_array();
154 let pok = self.proof.kfrag_pok.to_compressed_array();
155 let sig = self.proof.signature.to_array();
156 let kfrag_sig = self.proof.kfrag_signature.to_be_bytes();
157
158 let v: &[&[u8]] = &[
159 &e1,
160 &v1,
161 self.kfrag_id.as_ref(),
162 &precursor,
163 &e2,
164 &v2,
165 &commitment,
166 &pok,
167 &sig,
168 &kfrag_sig,
169 ];
170 v.concat().into()
171 }
172
173 #[allow(clippy::many_single_char_names)]
176 #[allow(clippy::result_large_err)]
177 pub fn verify(
178 self,
179 capsule: &Capsule,
180 verifying_pk: &PublicKey,
181 delegating_pk: &PublicKey,
182 receiving_pk: &PublicKey,
183 ) -> Result<VerifiedCapsuleFrag, (CapsuleFragVerificationError, Self)> {
184 let params = capsule.params;
185
186 let e = capsule.point_e;
190 let v = capsule.point_v;
191
192 let e1 = self.point_e1;
193 let v1 = self.point_v1;
194
195 let u = params.u;
196 let u1 = self.proof.kfrag_commitment;
197
198 let e2 = self.proof.point_e2;
199 let v2 = self.proof.point_v2;
200 let u2 = self.proof.kfrag_pok;
201
202 let h = hash_to_cfrag_verification(&e, &e1, &e2, &v, &v1, &v2, &u, &u1, &u2);
203
204 let precursor = self.precursor;
207 let kfrag_id = self.kfrag_id;
208
209 if !self.proof.kfrag_signature.verify(
210 verifying_pk,
211 kfrag_signature_message(
212 &kfrag_id,
213 &u1,
214 &precursor,
215 Some(delegating_pk),
216 Some(receiving_pk),
217 )
218 .as_ref(),
219 ) {
220 return Err((
221 CapsuleFragVerificationError::IncorrectKeyFragSignature,
222 self,
223 ));
224 }
225
226 let z = self.proof.signature;
230 let correct_reencryption_of_e = &e * &z == &e2 + &(&e1 * &h);
231 let correct_reencryption_of_v = &v * &z == &v2 + &(&v1 * &h);
232 let correct_rk_commitment = &u * &z == &u2 + &(&u1 * &h);
233
234 if !(correct_reencryption_of_e & correct_reencryption_of_v & correct_rk_commitment) {
235 return Err((CapsuleFragVerificationError::IncorrectReencryption, self));
236 }
237
238 Ok(VerifiedCapsuleFrag { cfrag: self })
239 }
240
241 pub fn skip_verification(self) -> VerifiedCapsuleFrag {
247 VerifiedCapsuleFrag { cfrag: self }
248 }
249}
250
251#[cfg(feature = "default-serialization")]
252impl DefaultSerialize for CapsuleFrag {}
253
254#[cfg(feature = "default-serialization")]
255impl<'de> DefaultDeserialize<'de> for CapsuleFrag {}
256
257#[derive(Debug, Clone, PartialEq)]
261#[cfg_attr(feature = "serde", derive(Serialize))]
262#[cfg_attr(feature = "serde", serde(transparent))]
263pub struct VerifiedCapsuleFrag {
264 cfrag: CapsuleFrag,
265}
266
267impl fmt::Display for VerifiedCapsuleFrag {
268 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
269 fmt_public("VerifiedCapsuleFrag", &self.cfrag.kfrag_id, f)
270 }
271}
272
273impl VerifiedCapsuleFrag {
274 pub(crate) fn reencrypted(
275 rng: &mut (impl CryptoRng + RngCore),
276 capsule: &Capsule,
277 kfrag: KeyFrag,
278 ) -> Self {
279 VerifiedCapsuleFrag {
280 cfrag: CapsuleFrag::reencrypted(rng, capsule, kfrag),
281 }
282 }
283
284 pub fn unverify(self) -> CapsuleFrag {
289 self.cfrag
290 }
291
292 pub fn to_bytes_simple(&self) -> Box<[u8]> {
294 self.cfrag.to_bytes_simple()
295 }
296}
297
298#[cfg(feature = "default-serialization")]
299impl DefaultSerialize for VerifiedCapsuleFrag {}
300
301#[cfg(test)]
302mod tests {
303
304 use alloc::boxed::Box;
305 use alloc::vec::Vec;
306
307 use super::VerifiedCapsuleFrag;
308
309 use crate::{encrypt, generate_kfrags, reencrypt, Capsule, PublicKey, SecretKey, Signer};
310
311 #[cfg(feature = "serde")]
312 use crate::serde_bytes::tests::check_serialization_roundtrip;
313
314 fn prepare_cfrags() -> (
315 PublicKey,
316 PublicKey,
317 PublicKey,
318 Capsule,
319 Box<[VerifiedCapsuleFrag]>,
320 ) {
321 let delegating_sk = SecretKey::random();
322 let delegating_pk = delegating_sk.public_key();
323
324 let signer = Signer::new(SecretKey::random());
325 let verifying_pk = signer.verifying_key();
326
327 let receiving_sk = SecretKey::random();
328 let receiving_pk = receiving_sk.public_key();
329
330 let plaintext = b"peace at dawn";
331 let (capsule, _ciphertext) = encrypt(&delegating_pk, plaintext).unwrap();
332
333 let kfrags = generate_kfrags(&delegating_sk, &receiving_pk, &signer, 2, 3, true, true);
334
335 let verified_cfrags: Vec<_> = kfrags
336 .iter()
337 .map(|kfrag| reencrypt(&capsule, kfrag.clone()))
338 .collect();
339
340 (
341 delegating_pk,
342 receiving_pk,
343 verifying_pk,
344 capsule,
345 verified_cfrags.into_boxed_slice(),
346 )
347 }
348
349 #[test]
350 fn test_verify() {
351 let (delegating_pk, receiving_pk, verifying_pk, capsule, verified_cfrags) =
352 prepare_cfrags();
353
354 for verified_cfrag in verified_cfrags.iter() {
355 let cfrag = verified_cfrag.clone().unverify();
356 let verified_cfrag_back = cfrag
357 .verify(&capsule, &verifying_pk, &delegating_pk, &receiving_pk)
358 .unwrap();
359
360 assert_eq!(&verified_cfrag_back, verified_cfrag);
361 }
362 }
363
364 #[cfg(feature = "serde")]
365 #[test]
366 fn test_serde_serialization() {
367 let (_delegating_pk, _receiving_pk, _verifying_pk, _capsule, verified_cfrags) =
368 prepare_cfrags();
369
370 let cfrag = verified_cfrags[0].clone().unverify();
371
372 let cfrag_bytes = rmp_serde::to_vec(&cfrag).unwrap();
374 let vcfrag_bytes = rmp_serde::to_vec(&verified_cfrags[0]).unwrap();
375 assert_eq!(vcfrag_bytes, cfrag_bytes);
376
377 check_serialization_roundtrip(&cfrag);
378 }
379}