xref: /aosp_15_r20/external/tink/cc/primitive_set.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1*e7b1675dSTing-Kang Chang // Copyright 2017 Google Inc.
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang //     http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang 
17*e7b1675dSTing-Kang Chang #ifndef TINK_PRIMITIVE_SET_H_
18*e7b1675dSTing-Kang Chang #define TINK_PRIMITIVE_SET_H_
19*e7b1675dSTing-Kang Chang 
20*e7b1675dSTing-Kang Chang #include <algorithm>
21*e7b1675dSTing-Kang Chang #include <memory>
22*e7b1675dSTing-Kang Chang #include <string>
23*e7b1675dSTing-Kang Chang #include <utility>
24*e7b1675dSTing-Kang Chang #include <vector>
25*e7b1675dSTing-Kang Chang 
26*e7b1675dSTing-Kang Chang #include "absl/base/thread_annotations.h"
27*e7b1675dSTing-Kang Chang #include "absl/container/flat_hash_map.h"
28*e7b1675dSTing-Kang Chang #include "absl/memory/memory.h"
29*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
30*e7b1675dSTing-Kang Chang #include "absl/synchronization/mutex.h"
31*e7b1675dSTing-Kang Chang #include "tink/crypto_format.h"
32*e7b1675dSTing-Kang Chang #include "tink/util/errors.h"
33*e7b1675dSTing-Kang Chang #include "tink/util/statusor.h"
34*e7b1675dSTing-Kang Chang #include "proto/tink.pb.h"
35*e7b1675dSTing-Kang Chang 
36*e7b1675dSTing-Kang Chang namespace crypto {
37*e7b1675dSTing-Kang Chang namespace tink {
38*e7b1675dSTing-Kang Chang 
39*e7b1675dSTing-Kang Chang // A container class for a set of primitives (i.e. implementations of
40*e7b1675dSTing-Kang Chang // cryptographic primitives offered by Tink).  It provides also
41*e7b1675dSTing-Kang Chang // additional properties for the primitives it holds.  In particular,
42*e7b1675dSTing-Kang Chang // one of the primitives in the set can be distinguished as "the
43*e7b1675dSTing-Kang Chang // primary" one.
44*e7b1675dSTing-Kang Chang //
45*e7b1675dSTing-Kang Chang // PrimitiveSet is an auxiliary class used for supporting key rotation:
46*e7b1675dSTing-Kang Chang // primitives in a set correspond to keys in a keyset.  Users will
47*e7b1675dSTing-Kang Chang // usually work with primitive instances, which essentially wrap
48*e7b1675dSTing-Kang Chang // primitive sets.  For example an instance of an Aead-primitive for a
49*e7b1675dSTing-Kang Chang // given keyset holds a set of Aead-primitivies corresponding to the
50*e7b1675dSTing-Kang Chang // keys in the keyset, and uses the set members to do the actual
51*e7b1675dSTing-Kang Chang // crypto operations: to encrypt data the primary Aead-primitive from
52*e7b1675dSTing-Kang Chang // the set is used, and upon decryption the ciphertext's prefix
53*e7b1675dSTing-Kang Chang // determines the identifier of the primitive from the set.
54*e7b1675dSTing-Kang Chang //
55*e7b1675dSTing-Kang Chang // PrimitiveSet is a public class to allow its use in implementations
56*e7b1675dSTing-Kang Chang // of custom primitives.
57*e7b1675dSTing-Kang Chang template <class P>
58*e7b1675dSTing-Kang Chang class PrimitiveSet {
59*e7b1675dSTing-Kang Chang  public:
60*e7b1675dSTing-Kang Chang   // Entry-objects hold individual instances of primitives in the set.
61*e7b1675dSTing-Kang Chang   template <class P2>
62*e7b1675dSTing-Kang Chang   class Entry {
63*e7b1675dSTing-Kang Chang    public:
New(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info)64*e7b1675dSTing-Kang Chang     static crypto::tink::util::StatusOr<std::unique_ptr<Entry<P>>> New(
65*e7b1675dSTing-Kang Chang         std::unique_ptr<P> primitive,
66*e7b1675dSTing-Kang Chang         const google::crypto::tink::KeysetInfo::KeyInfo& key_info) {
67*e7b1675dSTing-Kang Chang       if (key_info.status() != google::crypto::tink::KeyStatusType::ENABLED) {
68*e7b1675dSTing-Kang Chang         return util::Status(absl::StatusCode::kInvalidArgument,
69*e7b1675dSTing-Kang Chang                             "The key must be ENABLED.");
70*e7b1675dSTing-Kang Chang       }
71*e7b1675dSTing-Kang Chang       auto identifier_result = CryptoFormat::GetOutputPrefix(key_info);
72*e7b1675dSTing-Kang Chang       if (!identifier_result.ok()) return identifier_result.status();
73*e7b1675dSTing-Kang Chang       if (primitive == nullptr) {
74*e7b1675dSTing-Kang Chang         return util::Status(absl::StatusCode::kInvalidArgument,
75*e7b1675dSTing-Kang Chang                             "The primitive must be non-null.");
76*e7b1675dSTing-Kang Chang       }
77*e7b1675dSTing-Kang Chang       std::string identifier = identifier_result.value();
78*e7b1675dSTing-Kang Chang       return absl::WrapUnique(new Entry(std::move(primitive), identifier,
79*e7b1675dSTing-Kang Chang                                         key_info.status(), key_info.key_id(),
80*e7b1675dSTing-Kang Chang                                         key_info.output_prefix_type(),
81*e7b1675dSTing-Kang Chang                                         key_info.type_url()));
82*e7b1675dSTing-Kang Chang     }
83*e7b1675dSTing-Kang Chang 
get_primitive()84*e7b1675dSTing-Kang Chang     P2& get_primitive() const { return *primitive_; }
85*e7b1675dSTing-Kang Chang 
get_identifier()86*e7b1675dSTing-Kang Chang     const std::string& get_identifier() const { return identifier_; }
87*e7b1675dSTing-Kang Chang 
get_status()88*e7b1675dSTing-Kang Chang     google::crypto::tink::KeyStatusType get_status() const { return status_; }
89*e7b1675dSTing-Kang Chang 
get_key_id()90*e7b1675dSTing-Kang Chang     uint32_t get_key_id() const { return key_id_; }
91*e7b1675dSTing-Kang Chang 
get_output_prefix_type()92*e7b1675dSTing-Kang Chang     google::crypto::tink::OutputPrefixType get_output_prefix_type() const {
93*e7b1675dSTing-Kang Chang       return output_prefix_type_;
94*e7b1675dSTing-Kang Chang     }
95*e7b1675dSTing-Kang Chang 
get_key_type_url()96*e7b1675dSTing-Kang Chang     absl::string_view get_key_type_url() const { return key_type_url_; }
97*e7b1675dSTing-Kang Chang 
98*e7b1675dSTing-Kang Chang    private:
Entry(std::unique_ptr<P2> primitive,const std::string & identifier,google::crypto::tink::KeyStatusType status,uint32_t key_id,google::crypto::tink::OutputPrefixType output_prefix_type,absl::string_view key_type_url)99*e7b1675dSTing-Kang Chang     Entry(std::unique_ptr<P2> primitive, const std::string& identifier,
100*e7b1675dSTing-Kang Chang           google::crypto::tink::KeyStatusType status, uint32_t key_id,
101*e7b1675dSTing-Kang Chang           google::crypto::tink::OutputPrefixType output_prefix_type,
102*e7b1675dSTing-Kang Chang           absl::string_view key_type_url)
103*e7b1675dSTing-Kang Chang         : primitive_(std::move(primitive)),
104*e7b1675dSTing-Kang Chang           identifier_(identifier),
105*e7b1675dSTing-Kang Chang           status_(status),
106*e7b1675dSTing-Kang Chang           key_id_(key_id),
107*e7b1675dSTing-Kang Chang           output_prefix_type_(output_prefix_type),
108*e7b1675dSTing-Kang Chang           key_type_url_(key_type_url) {}
109*e7b1675dSTing-Kang Chang 
110*e7b1675dSTing-Kang Chang     std::unique_ptr<P> primitive_;
111*e7b1675dSTing-Kang Chang     std::string identifier_;
112*e7b1675dSTing-Kang Chang     google::crypto::tink::KeyStatusType status_;
113*e7b1675dSTing-Kang Chang     uint32_t key_id_;
114*e7b1675dSTing-Kang Chang     google::crypto::tink::OutputPrefixType output_prefix_type_;
115*e7b1675dSTing-Kang Chang     const std::string key_type_url_;
116*e7b1675dSTing-Kang Chang   };
117*e7b1675dSTing-Kang Chang 
118*e7b1675dSTing-Kang Chang   typedef std::vector<std::unique_ptr<Entry<P>>> Primitives;
119*e7b1675dSTing-Kang Chang   typedef absl::flat_hash_map<std::string, Primitives>
120*e7b1675dSTing-Kang Chang       CiphertextPrefixToPrimitivesMap;
121*e7b1675dSTing-Kang Chang 
122*e7b1675dSTing-Kang Chang  private:
123*e7b1675dSTing-Kang Chang   // Helper methods for mutations, used by the Builder and the deprecated
124*e7b1675dSTing-Kang Chang   // mutation methods on PrimitiveSet.
125*e7b1675dSTing-Kang Chang 
SetPrimaryImpl(Entry<P> ** output,Entry<P> * primary,const CiphertextPrefixToPrimitivesMap & primitives)126*e7b1675dSTing-Kang Chang   static crypto::tink::util::Status SetPrimaryImpl(
127*e7b1675dSTing-Kang Chang       Entry<P>** output, Entry<P>* primary,
128*e7b1675dSTing-Kang Chang       const CiphertextPrefixToPrimitivesMap& primitives) {
129*e7b1675dSTing-Kang Chang     if (!primary) {
130*e7b1675dSTing-Kang Chang       return util::Status(absl::StatusCode::kInvalidArgument,
131*e7b1675dSTing-Kang Chang                           "The primary primitive must be non-null.");
132*e7b1675dSTing-Kang Chang     }
133*e7b1675dSTing-Kang Chang     if (primary->get_status() != google::crypto::tink::KeyStatusType::ENABLED) {
134*e7b1675dSTing-Kang Chang       return util::Status(absl::StatusCode::kInvalidArgument,
135*e7b1675dSTing-Kang Chang                           "Primary has to be enabled.");
136*e7b1675dSTing-Kang Chang     }
137*e7b1675dSTing-Kang Chang 
138*e7b1675dSTing-Kang Chang     if (primitives.count(primary->get_identifier()) == 0) {
139*e7b1675dSTing-Kang Chang       return util::Status(absl::StatusCode::kInvalidArgument,
140*e7b1675dSTing-Kang Chang                           "Primary cannot be set to an entry which is "
141*e7b1675dSTing-Kang Chang                           "not held by this primitive set.");
142*e7b1675dSTing-Kang Chang     }
143*e7b1675dSTing-Kang Chang 
144*e7b1675dSTing-Kang Chang     *output = primary;
145*e7b1675dSTing-Kang Chang     return crypto::tink::util::OkStatus();
146*e7b1675dSTing-Kang Chang   }
147*e7b1675dSTing-Kang Chang 
AddPrimitiveImpl(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info,CiphertextPrefixToPrimitivesMap & primitives,std::vector<Entry<P> * > & primitives_in_keyset_order)148*e7b1675dSTing-Kang Chang   static crypto::tink::util::StatusOr<Entry<P>*> AddPrimitiveImpl(
149*e7b1675dSTing-Kang Chang       std::unique_ptr<P> primitive,
150*e7b1675dSTing-Kang Chang       const google::crypto::tink::KeysetInfo::KeyInfo& key_info,
151*e7b1675dSTing-Kang Chang       CiphertextPrefixToPrimitivesMap& primitives,
152*e7b1675dSTing-Kang Chang       std::vector<Entry<P>*>& primitives_in_keyset_order) {
153*e7b1675dSTing-Kang Chang     auto entry_or = Entry<P>::New(std::move(primitive), key_info);
154*e7b1675dSTing-Kang Chang     if (!entry_or.ok()) return entry_or.status();
155*e7b1675dSTing-Kang Chang 
156*e7b1675dSTing-Kang Chang     std::string identifier = entry_or.value()->get_identifier();
157*e7b1675dSTing-Kang Chang     primitives[identifier].push_back(std::move(entry_or.value()));
158*e7b1675dSTing-Kang Chang 
159*e7b1675dSTing-Kang Chang     Entry<P>* stored_entry = primitives[identifier].back().get();
160*e7b1675dSTing-Kang Chang     primitives_in_keyset_order.push_back(stored_entry);
161*e7b1675dSTing-Kang Chang     return stored_entry;
162*e7b1675dSTing-Kang Chang   }
163*e7b1675dSTing-Kang Chang 
164*e7b1675dSTing-Kang Chang  public:
165*e7b1675dSTing-Kang Chang   // Builder is used to construct PrimitiveSet objects. Objects returned by
166*e7b1675dSTing-Kang Chang   // the builder are immutable. Calling any of the non-const methods on them
167*e7b1675dSTing-Kang Chang   // will fail.
168*e7b1675dSTing-Kang Chang   class Builder {
169*e7b1675dSTing-Kang Chang    public:
170*e7b1675dSTing-Kang Chang     // Adds 'primitive' to this set for the specified 'key'.
AddPrimitive(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info)171*e7b1675dSTing-Kang Chang     Builder& AddPrimitive(
172*e7b1675dSTing-Kang Chang         std::unique_ptr<P> primitive,
173*e7b1675dSTing-Kang Chang         const google::crypto::tink::KeysetInfo::KeyInfo& key_info) & {
174*e7b1675dSTing-Kang Chang       absl::MutexLock lock(&mutex_);
175*e7b1675dSTing-Kang Chang       if (!status_.ok()) return *this;
176*e7b1675dSTing-Kang Chang       status_ = AddPrimitiveImpl(std::move(primitive), key_info, primitives_,
177*e7b1675dSTing-Kang Chang                                  primitives_in_keyset_order_)
178*e7b1675dSTing-Kang Chang                     .status();
179*e7b1675dSTing-Kang Chang       return *this;
180*e7b1675dSTing-Kang Chang     }
181*e7b1675dSTing-Kang Chang 
AddPrimitive(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info)182*e7b1675dSTing-Kang Chang     Builder&& AddPrimitive(
183*e7b1675dSTing-Kang Chang         std::unique_ptr<P> primitive,
184*e7b1675dSTing-Kang Chang         const google::crypto::tink::KeysetInfo::KeyInfo& key_info) && {
185*e7b1675dSTing-Kang Chang       return std::move(AddPrimitive(std::move(primitive), key_info));
186*e7b1675dSTing-Kang Chang     }
187*e7b1675dSTing-Kang Chang 
188*e7b1675dSTing-Kang Chang     // Adds 'primitive' to this set for the specified 'key' and marks it
189*e7b1675dSTing-Kang Chang     // primary.
AddPrimaryPrimitive(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info)190*e7b1675dSTing-Kang Chang     Builder& AddPrimaryPrimitive(
191*e7b1675dSTing-Kang Chang         std::unique_ptr<P> primitive,
192*e7b1675dSTing-Kang Chang         const google::crypto::tink::KeysetInfo::KeyInfo& key_info) & {
193*e7b1675dSTing-Kang Chang       absl::MutexLock lock(&mutex_);
194*e7b1675dSTing-Kang Chang       if (!status_.ok()) return *this;
195*e7b1675dSTing-Kang Chang       auto entry_result =
196*e7b1675dSTing-Kang Chang           AddPrimitiveImpl(std::move(primitive), key_info, primitives_,
197*e7b1675dSTing-Kang Chang                            primitives_in_keyset_order_);
198*e7b1675dSTing-Kang Chang       if (!entry_result.ok()) {
199*e7b1675dSTing-Kang Chang         status_ = entry_result.status();
200*e7b1675dSTing-Kang Chang         return *this;
201*e7b1675dSTing-Kang Chang       }
202*e7b1675dSTing-Kang Chang       status_ = SetPrimaryImpl(&primary_, entry_result.value(), primitives_);
203*e7b1675dSTing-Kang Chang       return *this;
204*e7b1675dSTing-Kang Chang     }
205*e7b1675dSTing-Kang Chang 
AddPrimaryPrimitive(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info)206*e7b1675dSTing-Kang Chang     Builder&& AddPrimaryPrimitive(
207*e7b1675dSTing-Kang Chang         std::unique_ptr<P> primitive,
208*e7b1675dSTing-Kang Chang         const google::crypto::tink::KeysetInfo::KeyInfo& key_info) && {
209*e7b1675dSTing-Kang Chang       return std::move(AddPrimaryPrimitive(std::move(primitive), key_info));
210*e7b1675dSTing-Kang Chang     }
211*e7b1675dSTing-Kang Chang 
212*e7b1675dSTing-Kang Chang     // Add the given annotations. Existing annotations will not be overwritten.
AddAnnotations(absl::flat_hash_map<std::string,std::string> annotations)213*e7b1675dSTing-Kang Chang     Builder& AddAnnotations(
214*e7b1675dSTing-Kang Chang         absl::flat_hash_map<std::string, std::string> annotations) & {
215*e7b1675dSTing-Kang Chang       absl::MutexLock lock(&mutex_);
216*e7b1675dSTing-Kang Chang       annotations_.merge(std::move(annotations));
217*e7b1675dSTing-Kang Chang       return *this;
218*e7b1675dSTing-Kang Chang     }
219*e7b1675dSTing-Kang Chang 
AddAnnotations(absl::flat_hash_map<std::string,std::string> annotations)220*e7b1675dSTing-Kang Chang     Builder&& AddAnnotations(
221*e7b1675dSTing-Kang Chang         absl::flat_hash_map<std::string, std::string> annotations) && {
222*e7b1675dSTing-Kang Chang       return std::move(AddAnnotations(std::move(annotations)));
223*e7b1675dSTing-Kang Chang     }
224*e7b1675dSTing-Kang Chang 
Build()225*e7b1675dSTing-Kang Chang     crypto::tink::util::StatusOr<PrimitiveSet<P>> Build() && {
226*e7b1675dSTing-Kang Chang       absl::MutexLock lock(&mutex_);
227*e7b1675dSTing-Kang Chang       if (!status_.ok()) return status_;
228*e7b1675dSTing-Kang Chang       return PrimitiveSet<P>(std::move(primitives_), primary_,
229*e7b1675dSTing-Kang Chang                              std::move(primitives_in_keyset_order_),
230*e7b1675dSTing-Kang Chang                              std::move(annotations_));
231*e7b1675dSTing-Kang Chang     }
232*e7b1675dSTing-Kang Chang 
233*e7b1675dSTing-Kang Chang    private:
234*e7b1675dSTing-Kang Chang     // Owned by primitives_.
235*e7b1675dSTing-Kang Chang     Entry<P>* primary_ ABSL_GUARDED_BY(mutex_) = nullptr;
236*e7b1675dSTing-Kang Chang     CiphertextPrefixToPrimitivesMap primitives_ ABSL_GUARDED_BY(mutex_);
237*e7b1675dSTing-Kang Chang     // Entries in the original keyset key order, all owned by primitives_.
238*e7b1675dSTing-Kang Chang     std::vector<Entry<P>*> primitives_in_keyset_order_ ABSL_GUARDED_BY(mutex_);
239*e7b1675dSTing-Kang Chang     absl::flat_hash_map<std::string, std::string> annotations_
240*e7b1675dSTing-Kang Chang         ABSL_GUARDED_BY(mutex_);
241*e7b1675dSTing-Kang Chang     absl::Mutex mutex_;
242*e7b1675dSTing-Kang Chang     crypto::tink::util::Status status_ ABSL_GUARDED_BY(mutex_);
243*e7b1675dSTing-Kang Chang   };
244*e7b1675dSTing-Kang Chang 
245*e7b1675dSTing-Kang Chang   // PrimitiveSet is movable, but not copyable
246*e7b1675dSTing-Kang Chang   PrimitiveSet(PrimitiveSet&&) = default;
247*e7b1675dSTing-Kang Chang   PrimitiveSet<P>& operator=(PrimitiveSet&&) = default;
248*e7b1675dSTing-Kang Chang   PrimitiveSet(const PrimitiveSet&) = delete;
249*e7b1675dSTing-Kang Chang   PrimitiveSet<P>& operator=(const PrimitiveSet&) = delete;
250*e7b1675dSTing-Kang Chang 
251*e7b1675dSTing-Kang Chang   // Constructs an empty PrimitiveSet.
252*e7b1675dSTing-Kang Chang   // Note: This is equivalent to PrimitiveSet<P>(/*annotations=*/{}).
253*e7b1675dSTing-Kang Chang   ABSL_DEPRECATED(
254*e7b1675dSTing-Kang Chang       "Constructing PrimitiveSet using constructors is deprecated. Use "
255*e7b1675dSTing-Kang Chang       "PrimitiveSet<>::Builder instead.")
256*e7b1675dSTing-Kang Chang   PrimitiveSet<P>() = default;
257*e7b1675dSTing-Kang Chang   // Constructs an empty PrimitiveSet with `annotations`.
258*e7b1675dSTing-Kang Chang   ABSL_DEPRECATED(
259*e7b1675dSTing-Kang Chang       "Constructing PrimitiveSet using constructors is deprecated. Use "
260*e7b1675dSTing-Kang Chang       "PrimitiveSet<>::Builder instead.")
261*e7b1675dSTing-Kang Chang   explicit PrimitiveSet<P>(
262*e7b1675dSTing-Kang Chang       const absl::flat_hash_map<std::string, std::string>& annotations)
annotations_(annotations)263*e7b1675dSTing-Kang Chang       : annotations_(annotations) {}
264*e7b1675dSTing-Kang Chang 
265*e7b1675dSTing-Kang Chang   // Adds 'primitive' to this set for the specified 'key'.
266*e7b1675dSTing-Kang Chang   ABSL_DEPRECATED(
267*e7b1675dSTing-Kang Chang       "Mutating PrimitiveSets after construction is deprecated. Use "
268*e7b1675dSTing-Kang Chang       "PrimitiveSet<>::Builder instead.")
AddPrimitive(std::unique_ptr<P> primitive,const google::crypto::tink::KeysetInfo::KeyInfo & key_info)269*e7b1675dSTing-Kang Chang   crypto::tink::util::StatusOr<Entry<P>*> AddPrimitive(
270*e7b1675dSTing-Kang Chang       std::unique_ptr<P> primitive,
271*e7b1675dSTing-Kang Chang       const google::crypto::tink::KeysetInfo::KeyInfo& key_info) {
272*e7b1675dSTing-Kang Chang     if (!is_mutable()) {
273*e7b1675dSTing-Kang Chang       return util::Status(absl::StatusCode::kFailedPrecondition,
274*e7b1675dSTing-Kang Chang                           "PrimitiveSet is not mutable.");
275*e7b1675dSTing-Kang Chang     }
276*e7b1675dSTing-Kang Chang 
277*e7b1675dSTing-Kang Chang     absl::MutexLock lock(primitives_mutex_.get());
278*e7b1675dSTing-Kang Chang     return AddPrimitiveImpl(std::move(primitive), key_info, primitives_,
279*e7b1675dSTing-Kang Chang                             primitives_in_keyset_order_);
280*e7b1675dSTing-Kang Chang   }
281*e7b1675dSTing-Kang Chang 
282*e7b1675dSTing-Kang Chang   // Returns the entries with primitives identified by 'identifier'.
get_primitives(absl::string_view identifier)283*e7b1675dSTing-Kang Chang   crypto::tink::util::StatusOr<const Primitives*> get_primitives(
284*e7b1675dSTing-Kang Chang       absl::string_view identifier) const {
285*e7b1675dSTing-Kang Chang     absl::MutexLockMaybe lock(primitives_mutex_.get());
286*e7b1675dSTing-Kang Chang     auto found = primitives_.find(std::string(identifier));
287*e7b1675dSTing-Kang Chang     if (found == primitives_.end()) {
288*e7b1675dSTing-Kang Chang       return ToStatusF(absl::StatusCode::kNotFound,
289*e7b1675dSTing-Kang Chang                        "No primitives found for identifier '%s'.", identifier);
290*e7b1675dSTing-Kang Chang     }
291*e7b1675dSTing-Kang Chang     return &(found->second);
292*e7b1675dSTing-Kang Chang   }
293*e7b1675dSTing-Kang Chang 
294*e7b1675dSTing-Kang Chang   // Returns all primitives that use RAW prefix.
get_raw_primitives()295*e7b1675dSTing-Kang Chang   crypto::tink::util::StatusOr<const Primitives*> get_raw_primitives() const {
296*e7b1675dSTing-Kang Chang     return get_primitives(CryptoFormat::kRawPrefix);
297*e7b1675dSTing-Kang Chang   }
298*e7b1675dSTing-Kang Chang 
299*e7b1675dSTing-Kang Chang   // Sets the given 'primary' as the primary primitive of this set.
300*e7b1675dSTing-Kang Chang   ABSL_DEPRECATED(
301*e7b1675dSTing-Kang Chang       "Mutating PrimitiveSets after construction is deprecated. Use "
302*e7b1675dSTing-Kang Chang       "PrimitiveSet<>::Builder instead.")
set_primary(Entry<P> * primary)303*e7b1675dSTing-Kang Chang   crypto::tink::util::Status set_primary(Entry<P>* primary) {
304*e7b1675dSTing-Kang Chang     if (!is_mutable()) {
305*e7b1675dSTing-Kang Chang       return util::Status(absl::StatusCode::kFailedPrecondition,
306*e7b1675dSTing-Kang Chang                           "PrimitiveSet is not mutable.");
307*e7b1675dSTing-Kang Chang     }
308*e7b1675dSTing-Kang Chang     absl::MutexLock lock(primitives_mutex_.get());
309*e7b1675dSTing-Kang Chang     return SetPrimaryImpl(&primary_, primary, primitives_);
310*e7b1675dSTing-Kang Chang   }
311*e7b1675dSTing-Kang Chang 
312*e7b1675dSTing-Kang Chang   // Returns the entry with the primary primitive.
get_primary()313*e7b1675dSTing-Kang Chang   const Entry<P>* get_primary() const {
314*e7b1675dSTing-Kang Chang     absl::MutexLockMaybe lock(primitives_mutex_.get());
315*e7b1675dSTing-Kang Chang     return primary_;
316*e7b1675dSTing-Kang Chang   }
317*e7b1675dSTing-Kang Chang 
318*e7b1675dSTing-Kang Chang   // Returns all entries.
get_all()319*e7b1675dSTing-Kang Chang   std::vector<Entry<P>*> get_all() const {
320*e7b1675dSTing-Kang Chang     absl::MutexLockMaybe lock(primitives_mutex_.get());
321*e7b1675dSTing-Kang Chang     std::vector<Entry<P>*> result;
322*e7b1675dSTing-Kang Chang     for (const auto& prefix_and_vector : primitives_) {
323*e7b1675dSTing-Kang Chang       for (const auto& primitive : prefix_and_vector.second) {
324*e7b1675dSTing-Kang Chang         result.push_back(primitive.get());
325*e7b1675dSTing-Kang Chang       }
326*e7b1675dSTing-Kang Chang     }
327*e7b1675dSTing-Kang Chang     return result;
328*e7b1675dSTing-Kang Chang   }
329*e7b1675dSTing-Kang Chang 
330*e7b1675dSTing-Kang Chang   // Returns all entries in the original keyset key order.
get_all_in_keyset_order()331*e7b1675dSTing-Kang Chang   std::vector<Entry<P>*> get_all_in_keyset_order() const {
332*e7b1675dSTing-Kang Chang     absl::MutexLockMaybe lock(primitives_mutex_.get());
333*e7b1675dSTing-Kang Chang     return primitives_in_keyset_order_;
334*e7b1675dSTing-Kang Chang   }
335*e7b1675dSTing-Kang Chang 
get_annotations()336*e7b1675dSTing-Kang Chang   const absl::flat_hash_map<std::string, std::string>& get_annotations() const {
337*e7b1675dSTing-Kang Chang     return annotations_;
338*e7b1675dSTing-Kang Chang   }
339*e7b1675dSTing-Kang Chang 
is_mutable()340*e7b1675dSTing-Kang Chang   bool is_mutable() const { return primitives_mutex_ != nullptr; }
341*e7b1675dSTing-Kang Chang 
342*e7b1675dSTing-Kang Chang  private:
343*e7b1675dSTing-Kang Chang   // Constructs an empty PrimitiveSet.
344*e7b1675dSTing-Kang Chang   // Note: This is equivalent to PrimitiveSet<P>(/*annotations=*/{}).
PrimitiveSet(CiphertextPrefixToPrimitivesMap primitives,Entry<P> * primary,std::vector<Entry<P> * > primitives_in_keyset_order,absl::flat_hash_map<std::string,std::string> annotations)345*e7b1675dSTing-Kang Chang   PrimitiveSet(CiphertextPrefixToPrimitivesMap primitives, Entry<P>* primary,
346*e7b1675dSTing-Kang Chang                std::vector<Entry<P>*> primitives_in_keyset_order,
347*e7b1675dSTing-Kang Chang                absl::flat_hash_map<std::string, std::string> annotations)
348*e7b1675dSTing-Kang Chang       : primary_(primary),
349*e7b1675dSTing-Kang Chang         primitives_mutex_(nullptr),
350*e7b1675dSTing-Kang Chang         primitives_(std::move(primitives)),
351*e7b1675dSTing-Kang Chang         primitives_in_keyset_order_(std::move(primitives_in_keyset_order)),
352*e7b1675dSTing-Kang Chang         annotations_(std::move(annotations)) {}
353*e7b1675dSTing-Kang Chang 
354*e7b1675dSTing-Kang Chang   // Owned by primitives_.
355*e7b1675dSTing-Kang Chang   Entry<P>* primary_ ABSL_GUARDED_BY(primitives_mutex_) = nullptr;
356*e7b1675dSTing-Kang Chang   // If primitives_mutex_ is a nullptr, PrimitiveSet is immutable and lock-free.
357*e7b1675dSTing-Kang Chang   // If not nullptr, primitives_mutex_ guards all read and write access.
358*e7b1675dSTing-Kang Chang   mutable std::unique_ptr<absl::Mutex> primitives_mutex_ =
359*e7b1675dSTing-Kang Chang       absl::make_unique<absl::Mutex>();
360*e7b1675dSTing-Kang Chang   CiphertextPrefixToPrimitivesMap primitives_
361*e7b1675dSTing-Kang Chang       ABSL_GUARDED_BY(primitives_mutex_);
362*e7b1675dSTing-Kang Chang   // Entries in the original keyset key order, all owned by primitives_.
363*e7b1675dSTing-Kang Chang   std::vector<Entry<P>*> primitives_in_keyset_order_
364*e7b1675dSTing-Kang Chang       ABSL_GUARDED_BY(primitives_mutex_);
365*e7b1675dSTing-Kang Chang 
366*e7b1675dSTing-Kang Chang   absl::flat_hash_map<std::string, std::string> annotations_;
367*e7b1675dSTing-Kang Chang };
368*e7b1675dSTing-Kang Chang 
369*e7b1675dSTing-Kang Chang }  // namespace tink
370*e7b1675dSTing-Kang Chang }  // namespace crypto
371*e7b1675dSTing-Kang Chang 
372*e7b1675dSTing-Kang Chang #endif  // TINK_PRIMITIVE_SET_H_
373