umbral_pre/
key_frag.rs

1#[cfg(feature = "serde")]
2use alloc::string::String;
3
4use alloc::boxed::Box;
5use alloc::vec::Vec;
6use core::fmt;
7
8use generic_array::{typenum::U32, GenericArray};
9use rand_core::{CryptoRng, RngCore};
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14use crate::curve::{CurvePoint, CurveScalar, NonZeroCurveScalar};
15use crate::hashing_ds::{hash_to_polynomial_arg, hash_to_shared_secret, kfrag_signature_message};
16use crate::keys::{PublicKey, SecretKey, Signature, Signer};
17use crate::params::Parameters;
18use crate::secret_box::SecretBox;
19use crate::traits::fmt_public;
20
21#[cfg(feature = "default-serialization")]
22use crate::{DefaultDeserialize, DefaultSerialize};
23
24#[cfg(feature = "serde")]
25use crate::serde_bytes::{
26    deserialize_with_encoding, serialize_with_encoding, Encoding, TryFromBytes,
27};
28
29#[allow(clippy::upper_case_acronyms)]
30type KeyFragIDSize = U32;
31
32#[allow(clippy::upper_case_acronyms)]
33#[derive(Clone, Copy, Debug, PartialEq)]
34pub(crate) struct KeyFragID(GenericArray<u8, KeyFragIDSize>);
35
36impl KeyFragID {
37    fn random(rng: &mut impl RngCore) -> Self {
38        let mut bytes = GenericArray::<u8, KeyFragIDSize>::default();
39        rng.fill_bytes(&mut bytes);
40        Self(bytes)
41    }
42}
43
44impl AsRef<[u8]> for KeyFragID {
45    fn as_ref(&self) -> &[u8] {
46        self.0.as_ref()
47    }
48}
49
50#[cfg(feature = "serde")]
51impl Serialize for KeyFragID {
52    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
53    where
54        S: Serializer,
55    {
56        serialize_with_encoding(&self.0, serializer, Encoding::Hex)
57    }
58}
59
60#[cfg(feature = "serde")]
61impl<'de> Deserialize<'de> for KeyFragID {
62    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
63    where
64        D: Deserializer<'de>,
65    {
66        deserialize_with_encoding(deserializer, Encoding::Hex)
67    }
68}
69
70#[cfg(feature = "serde")]
71impl TryFromBytes for KeyFragID {
72    type Error = String;
73
74    fn try_from_bytes(bytes: &[u8]) -> Result<Self, Self::Error> {
75        let arr = GenericArray::<u8, KeyFragIDSize>::from_exact_iter(bytes.iter().cloned())
76            .ok_or("Invalid length of a key frag ID")?;
77        Ok(Self(arr))
78    }
79}
80
81#[derive(Clone, Debug, PartialEq)]
82#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
83pub(crate) struct KeyFragProof {
84    pub(crate) commitment: CurvePoint,
85    signature_for_proxy: Signature,
86    pub(crate) signature_for_receiver: Signature,
87    delegating_key_signed: bool,
88    receiving_key_signed: bool,
89}
90
91fn none_unless<T>(x: Option<T>, predicate: bool) -> Option<T> {
92    if predicate {
93        x
94    } else {
95        None
96    }
97}
98
99impl KeyFragProof {
100    fn from_base(
101        rng: &mut (impl CryptoRng + RngCore),
102        base: &KeyFragBase<'_>,
103        kfrag_id: &KeyFragID,
104        kfrag_key: &CurveScalar,
105        sign_delegating_key: bool,
106        sign_receiving_key: bool,
107    ) -> Self {
108        let commitment = &base.params.u * kfrag_key;
109
110        let maybe_delegating_pk = Some(&base.delegating_pk);
111        let maybe_receiving_pk = Some(&base.receiving_pk);
112
113        let signature_for_receiver = base.signer.sign_with_rng(
114            rng,
115            kfrag_signature_message(
116                kfrag_id,
117                &commitment,
118                &base.precursor,
119                maybe_delegating_pk,
120                maybe_receiving_pk,
121            )
122            .as_ref(),
123        );
124
125        let signature_for_proxy = base.signer.sign_with_rng(
126            rng,
127            kfrag_signature_message(
128                kfrag_id,
129                &commitment,
130                &base.precursor,
131                none_unless(maybe_delegating_pk, sign_delegating_key),
132                none_unless(maybe_receiving_pk, sign_receiving_key),
133            )
134            .as_ref(),
135        );
136
137        Self {
138            commitment,
139            signature_for_proxy,
140            signature_for_receiver,
141            delegating_key_signed: sign_delegating_key,
142            receiving_key_signed: sign_receiving_key,
143        }
144    }
145}
146
147/// A fragment of the encrypting party's key used to create a [`CapsuleFrag`](`crate::CapsuleFrag`).
148#[derive(Clone, Debug, PartialEq)]
149#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
150pub struct KeyFrag {
151    params: Parameters,
152    pub(crate) id: KeyFragID,
153    pub(crate) key: CurveScalar,
154    pub(crate) precursor: CurvePoint,
155    pub(crate) proof: KeyFragProof,
156}
157
158impl fmt::Display for KeyFrag {
159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160        fmt_public("KeyFrag", &self.id, f)
161    }
162}
163
164/// Possible errors that can be returned by [`KeyFrag::verify`].
165#[derive(Debug, PartialEq, Eq)]
166pub enum KeyFragVerificationError {
167    /// Inconsistent internal state leading to commitment verification failure.
168    IncorrectCommitment,
169    /// A delegating key was included in the signature when [`KeyFrag`] was created,
170    /// but no delegating key was provided during verification.
171    DelegatingKeyNotProvided,
172    /// A receiving key was included in the signature when [`KeyFrag`] was created,
173    /// but no receiving key was provided during verification.
174    ReceivingKeyNotProvided,
175    /// Inconsistent internal state leading to signature verification failure.
176    IncorrectSignature,
177}
178
179impl fmt::Display for KeyFragVerificationError {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        match self {
182            Self::IncorrectCommitment => write!(f, "Invalid kfrag commitment"),
183            Self::DelegatingKeyNotProvided => write!(f, "A signature of a delegating key was included in this kfrag but the key is not provided"),
184            Self::ReceivingKeyNotProvided => write!(f, "A signature of a receiving key was included in this kfrag, but the key is not provided"),
185            Self::IncorrectSignature => write!(f, "Failed to verify the kfrag signature"),
186        }
187    }
188}
189
190impl KeyFrag {
191    fn from_base(
192        rng: &mut (impl CryptoRng + RngCore),
193        base: &KeyFragBase<'_>,
194        sign_delegating_key: bool,
195        sign_receiving_key: bool,
196    ) -> Self {
197        let kfrag_id = KeyFragID::random(rng);
198
199        // The index of the re-encryption key share (which in Shamir's Secret
200        // Sharing corresponds to x in the tuple (x, f(x)), with f being the
201        // generating polynomial), is used to prevent reconstruction of the
202        // re-encryption key without Bob's intervention
203        let share_index = hash_to_polynomial_arg(
204            &base.precursor,
205            &base.receiving_pk.to_point(),
206            &base.dh_point,
207            &kfrag_id,
208        );
209
210        // The re-encryption key share is the result of evaluating the generating
211        // polynomial for the index value
212        let rk = poly_eval(&base.coefficients, &share_index);
213
214        let proof = KeyFragProof::from_base(
215            rng,
216            base,
217            &kfrag_id,
218            &rk,
219            sign_delegating_key,
220            sign_receiving_key,
221        );
222
223        Self {
224            params: base.params,
225            id: kfrag_id,
226            key: rk,
227            precursor: base.precursor,
228            proof,
229        }
230    }
231
232    /// Verifies the integrity of the key fragment, given the signing key,
233    /// and (optionally) the encrypting party's and decrypting party's keys.
234    ///
235    /// If [`generate_kfrags()`](`crate::generate_kfrags()`) was called with `true`
236    /// for `sign_delegating_key` or `sign_receiving_key`, and the respective key
237    /// is not provided, the verification fails.
238    #[allow(clippy::result_large_err)]
239    pub fn verify(
240        self,
241        verifying_pk: &PublicKey,
242        maybe_delegating_pk: Option<&PublicKey>,
243        maybe_receiving_pk: Option<&PublicKey>,
244    ) -> Result<VerifiedKeyFrag, (KeyFragVerificationError, Self)> {
245        let u = self.params.u;
246
247        let kfrag_id = self.id;
248        let key = self.key;
249        let commitment = self.proof.commitment;
250        let precursor = self.precursor;
251
252        // We check that the commitment is well-formed
253        if commitment != &u * &key {
254            return Err((KeyFragVerificationError::IncorrectCommitment, self));
255        }
256
257        // A shortcut, perhaps not necessary
258
259        if maybe_delegating_pk.is_none() && self.proof.delegating_key_signed {
260            return Err((KeyFragVerificationError::DelegatingKeyNotProvided, self));
261        }
262
263        if maybe_receiving_pk.is_none() && self.proof.receiving_key_signed {
264            return Err((KeyFragVerificationError::ReceivingKeyNotProvided, self));
265        }
266
267        // Check the signature
268
269        if !self.proof.signature_for_proxy.verify(
270            verifying_pk,
271            kfrag_signature_message(
272                &kfrag_id,
273                &commitment,
274                &precursor,
275                none_unless(maybe_delegating_pk, self.proof.delegating_key_signed),
276                none_unless(maybe_receiving_pk, self.proof.receiving_key_signed),
277            )
278            .as_ref(),
279        ) {
280            return Err((KeyFragVerificationError::IncorrectSignature, self));
281        }
282
283        Ok(VerifiedKeyFrag { kfrag: self })
284    }
285
286    /// Explicitly skips [`KeyFrag::verify`] call.
287    /// Useful in cases when the verifying keys are impossible to obtain independently,
288    /// or when this capsule frag came from a trusted storage.
289    ///
290    /// **Warning:** make sure you considered the implications of not enforcing verification.
291    pub fn skip_verification(self) -> VerifiedKeyFrag {
292        VerifiedKeyFrag { kfrag: self }
293    }
294}
295
296#[cfg(feature = "default-serialization")]
297impl DefaultSerialize for KeyFrag {}
298
299#[cfg(feature = "default-serialization")]
300impl<'de> DefaultDeserialize<'de> for KeyFrag {}
301
302/// Verified key fragment, good for reencryption.
303/// Can be serialized, but cannot be deserialized directly.
304/// It can only be obtained from [`KeyFrag::verify`] or [`KeyFrag::skip_verification`].
305#[derive(Debug, Clone, PartialEq)]
306#[cfg_attr(feature = "serde", derive(Serialize))]
307#[cfg_attr(feature = "serde", serde(transparent))]
308pub struct VerifiedKeyFrag {
309    kfrag: KeyFrag,
310}
311
312impl fmt::Display for VerifiedKeyFrag {
313    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314        fmt_public("VerifiedKeyFrag", &self.kfrag.id, f)
315    }
316}
317
318impl VerifiedKeyFrag {
319    pub(crate) fn from_base(
320        rng: &mut (impl CryptoRng + RngCore),
321        base: &KeyFragBase<'_>,
322        sign_delegating_key: bool,
323        sign_receiving_key: bool,
324    ) -> Self {
325        Self {
326            kfrag: KeyFrag::from_base(rng, base, sign_delegating_key, sign_receiving_key),
327        }
328    }
329
330    /// Clears the verification status from the keyfrag.
331    /// Useful for the cases where it needs to be put in the protocol structure
332    /// containing [`KeyFrag`] types (since those are the ones
333    /// that can be serialized/deserialized freely).
334    pub fn unverify(self) -> KeyFrag {
335        self.kfrag
336    }
337}
338
339#[cfg(feature = "default-serialization")]
340impl DefaultSerialize for VerifiedKeyFrag {}
341
342pub(crate) struct KeyFragBase<'a> {
343    signer: &'a Signer,
344    precursor: CurvePoint,
345    dh_point: CurvePoint,
346    params: Parameters,
347    delegating_pk: PublicKey,
348    receiving_pk: PublicKey,
349    coefficients: Box<[SecretBox<NonZeroCurveScalar>]>,
350}
351
352impl<'a> KeyFragBase<'a> {
353    pub fn new(
354        rng: &mut (impl CryptoRng + RngCore),
355        delegating_sk: &SecretKey,
356        receiving_pk: &PublicKey,
357        signer: &'a Signer,
358        threshold: usize,
359    ) -> Self {
360        let g = CurvePoint::generator();
361        let params = Parameters::new();
362
363        let delegating_pk = delegating_sk.public_key();
364
365        let receiving_pk_point = receiving_pk.to_point();
366
367        // The precursor point is used as an ephemeral public key in a DH key exchange,
368        // and the resulting shared secret 'dh_point' is used to derive other secret values
369        let private_precursor = SecretBox::new(NonZeroCurveScalar::random(rng));
370        let precursor = &g * private_precursor.as_secret();
371
372        let dh_point = &receiving_pk_point * private_precursor.as_secret();
373
374        // Secret value 'd' allows to make Umbral non-interactive
375        let d = hash_to_shared_secret(&precursor, &receiving_pk_point, &dh_point);
376
377        // Coefficients of the generating polynomial
378        let coefficient0 =
379            SecretBox::new(delegating_sk.to_secret_scalar().as_secret() * &(d.invert()));
380
381        let mut coefficients = Vec::<SecretBox<NonZeroCurveScalar>>::with_capacity(threshold);
382        coefficients.push(coefficient0);
383        for _i in 1..threshold {
384            coefficients.push(SecretBox::new(NonZeroCurveScalar::random(rng)));
385        }
386
387        Self {
388            signer,
389            precursor,
390            dh_point,
391            params,
392            delegating_pk,
393            receiving_pk: *receiving_pk,
394            coefficients: coefficients.into_boxed_slice(),
395        }
396    }
397}
398
399// Coefficients of the generating polynomial
400fn poly_eval(coeffs: &[SecretBox<NonZeroCurveScalar>], x: &NonZeroCurveScalar) -> CurveScalar {
401    let mut result: SecretBox<CurveScalar> =
402        SecretBox::new(coeffs[coeffs.len() - 1].as_secret().into());
403    for i in (0..coeffs.len() - 1).rev() {
404        // Keeping the intermediate results zeroized as well
405        let temp = SecretBox::new(result.as_secret() * x);
406        *result.as_mut_secret() = temp.as_secret() + coeffs[i].as_secret();
407    }
408    // This is not a secret anymore
409    *result.as_secret()
410}
411
412#[cfg(test)]
413mod tests {
414
415    use alloc::boxed::Box;
416
417    use rand_core::OsRng;
418
419    use super::{KeyFragBase, KeyFragVerificationError, VerifiedKeyFrag};
420
421    use crate::{PublicKey, SecretKey, Signer};
422
423    #[cfg(feature = "serde")]
424    use crate::serde_bytes::tests::check_serialization_roundtrip;
425
426    fn prepare_kfrags(
427        sign_delegating_key: bool,
428        sign_receiving_key: bool,
429    ) -> (PublicKey, PublicKey, PublicKey, Box<[VerifiedKeyFrag]>) {
430        let delegating_sk = SecretKey::random();
431        let delegating_pk = delegating_sk.public_key();
432
433        let signer = Signer::new(SecretKey::random());
434        let verifying_pk = signer.verifying_key();
435
436        let receiving_sk = SecretKey::random();
437        let receiving_pk = receiving_sk.public_key();
438
439        let base = KeyFragBase::new(&mut OsRng, &delegating_sk, &receiving_pk, &signer, 2);
440        let vkfrags = [
441            VerifiedKeyFrag::from_base(&mut OsRng, &base, sign_delegating_key, sign_receiving_key),
442            VerifiedKeyFrag::from_base(&mut OsRng, &base, sign_delegating_key, sign_receiving_key),
443            VerifiedKeyFrag::from_base(&mut OsRng, &base, sign_delegating_key, sign_receiving_key),
444        ];
445
446        (delegating_pk, receiving_pk, verifying_pk, Box::new(vkfrags))
447    }
448
449    #[test]
450    fn test_verify() {
451        for sign_dk in [false, true].iter().copied() {
452            for sign_rk in [false, true].iter().copied() {
453                let (delegating_pk, receiving_pk, verifying_pk, vkfrags) =
454                    prepare_kfrags(sign_dk, sign_rk);
455
456                let kfrag = vkfrags[0].clone().unverify();
457
458                for supply_dk in [false, true].iter().copied() {
459                    for supply_rk in [false, true].iter().copied() {
460                        let maybe_dk = if supply_dk {
461                            Some(&delegating_pk)
462                        } else {
463                            None
464                        };
465                        let maybe_rk = if supply_rk { Some(&receiving_pk) } else { None };
466                        let res = kfrag.clone().verify(&verifying_pk, maybe_dk, maybe_rk);
467
468                        let sufficient_dk = !sign_dk || (supply_dk == sign_dk);
469                        let sufficient_rk = !sign_rk || (supply_rk == sign_rk);
470
471                        if sufficient_dk && sufficient_rk {
472                            assert!(res.is_ok());
473                            assert_eq!(res.unwrap().kfrag, kfrag);
474                        } else if !sufficient_dk {
475                            assert_eq!(
476                                res,
477                                Err((
478                                    KeyFragVerificationError::DelegatingKeyNotProvided,
479                                    kfrag.clone()
480                                ))
481                            );
482                        } else if !sufficient_rk {
483                            assert_eq!(
484                                res,
485                                Err((
486                                    KeyFragVerificationError::ReceivingKeyNotProvided,
487                                    kfrag.clone()
488                                ))
489                            );
490                        }
491                    }
492                }
493            }
494        }
495    }
496
497    #[cfg(feature = "serde")]
498    #[test]
499    fn test_serde_serialization() {
500        let (_delegating_pk, _receiving_pk, _verifying_pk, verified_kfrags) =
501            prepare_kfrags(true, true);
502
503        let kfrag = verified_kfrags[0].clone().unverify();
504
505        // Check that the kfrag serializes to the same thing as the verified kfrag
506        let kfrag_bytes = rmp_serde::to_vec(&kfrag).unwrap();
507        let vkfrag_bytes = rmp_serde::to_vec(&verified_kfrags[0]).unwrap();
508        assert_eq!(vkfrag_bytes, kfrag_bytes);
509
510        check_serialization_roundtrip(&kfrag);
511    }
512}