cosmian_abe_gpsw/core/
engine.rs

1use sha3::{
2    digest::{ExtendableOutput, Update, XofReader},
3    Shake256,
4};
5
6use crate::{
7    core::gpsw::{AbeScheme, AsBytes},
8    error::FormatErr,
9};
10
11use abe_policy::{AccessPolicy, Attribute, Policy};
12
13use super::msp::policy_to_msp;
14
15/// The engine is the main entry point for the core ABE functionalities.
16///
17/// It supplies a simple API that lets generate keys, encrypt and decrypt
18/// messages.
19///
20/// In addition, two methods are supplied to generate random symmetric keys and
21/// their corresponding cipher texts which are suitable for use in a hybrid
22/// encryption scheme.
23#[derive(Clone)]
24pub struct Engine<S: AbeScheme> {
25    sch: S,
26}
27
28impl<S: AbeScheme> Engine<S> {
29    /// Instantiate a new ABE engine for the given Policy
30    #[must_use]
31    pub fn new() -> Self {
32        Self { sch: S::default() }
33    }
34
35    /// Generate the master authority keys for supplied Policy
36    pub fn generate_master_key(
37        &self,
38        policy: &Policy,
39    ) -> Result<
40        (
41            S::MasterPrivateKey,
42            S::MasterPublicKey,
43            S::MasterPublicDelegationKey,
44        ),
45        FormatErr,
46    > {
47        self.sch
48            .generate_master_key(policy.max_attribute_creations as usize)
49    }
50
51    /// Generate a user decryption key
52    /// from the supplied Master Private Key and Access Policy
53    pub fn generate_user_key(
54        &self,
55        policy: &Policy,
56        priv_key: &S::MasterPrivateKey,
57        access_policy: &AccessPolicy,
58    ) -> Result<S::UserDecryptionKey, FormatErr> {
59        let msp = policy_to_msp(policy, access_policy)?;
60        self.sch.key_generation(&msp, priv_key)
61    }
62
63    /// Allows a user to generate a new key for a more restrictive policy
64    ///
65    /// A more restrictive policy is a policy that must always satisfy
66    /// the original policy when satisfied. In other words, we can only modify a
67    /// policy by changing an `Or` node by either an `And` or replace it by
68    /// one of its child.
69    ///
70    /// Remark: It is also possible to merge 2 keys by `Or` node, this latter
71    /// functionality is not yet supported
72    pub fn delegate_user_key(
73        &self,
74        policy: &Policy,
75        del_key: &S::MasterPublicDelegationKey,
76        user_key: &S::UserDecryptionKey,
77        access_policy: &AccessPolicy,
78    ) -> Result<S::UserDecryptionKey, FormatErr> {
79        let msp = match access_policy {
80            AccessPolicy::All => None,
81            _ => Some(policy_to_msp(policy, access_policy)?),
82        };
83        self.sch.key_delegation(&msp, user_key, del_key)
84    }
85
86    /// Generate a random point on GT
87    pub fn random_message(&self) -> Result<S::PlainText, FormatErr> {
88        self.sch.generate_random_plaintext()
89    }
90
91    /// Encrypt a plain text (a point on GT)
92    /// with the given list of policy attributes
93    pub fn encrypt(
94        &self,
95        policy: &Policy,
96        public_key: &S::MasterPublicKey,
97        attributes: &[Attribute],
98        plain_text: &S::PlainText,
99    ) -> Result<S::CipherText, FormatErr> {
100        let int_attributes = policy.attributes_values(attributes)?;
101        self.sch.encrypt(plain_text, &int_attributes, public_key)
102    }
103
104    /// Decrypt a cipher text returning the point on GT
105    pub fn decrypt(
106        &self,
107        enc: &S::CipherText,
108        key: &S::UserDecryptionKey,
109    ) -> Result<Option<S::PlainText>, FormatErr> {
110        self.sch.decrypt(enc, key)
111    }
112
113    /// Generate a random symmetric key of `symmetric_key_len` to be used in an
114    /// hybrid encryption scheme and generate its ABE encrypted version with the
115    /// supplied policy `attributes`
116    pub fn generate_symmetric_key(
117        &self,
118        policy: &Policy,
119        public_key: &S::MasterPublicKey,
120        attrs: &[Attribute],
121        symmetric_key_len: usize,
122    ) -> Result<(Vec<u8>, Vec<u8>), FormatErr> {
123        let random = self.random_message()?;
124        let enc_sym_key = self
125            .encrypt(policy, public_key, attrs, &random)?
126            .try_into_bytes()?;
127        // Use a hash of the plaintext bytes as the symmetric key
128        let sym_key = Shake256::default()
129            .chain(&random.try_into_bytes()?)
130            .finalize_xof()
131            .read_boxed(symmetric_key_len)
132            .into_vec();
133        Ok((sym_key, enc_sym_key))
134    }
135
136    /// Decrypt a symmetric key generated with `generate_symmetric_key()`
137    pub fn decrypt_symmetric_key(
138        &self,
139        decryption_key: &S::UserDecryptionKey,
140        encrypted_symmetric_key: &[u8],
141        symmetric_key_len: usize,
142    ) -> Result<Vec<u8>, FormatErr> {
143        let random = self
144            .decrypt(
145                &S::CipherText::try_from_bytes(encrypted_symmetric_key)?,
146                decryption_key,
147            )?
148            .ok_or(FormatErr::InvalidEncryptedData)?;
149        // Use a hash of the plaintext bytes as the symmetric key
150        Ok(Shake256::default()
151            .chain(&random.try_into_bytes()?)
152            .finalize_xof()
153            .read_boxed(symmetric_key_len)
154            .into_vec())
155    }
156}
157
158impl<S: AbeScheme> Default for Engine<S> {
159    fn default() -> Self {
160        Self::new()
161    }
162}