xref: /aosp_15_r20/external/tink/cc/experimental/pqcrypto/signature/subtle/dilithium_key.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_key.h"
18 
19 #include <string>
20 #include <utility>
21 
22 #include "absl/memory/memory.h"
23 #include "absl/status/status.h"
24 #include "absl/strings/str_format.h"
25 #include "tink/util/secret_data.h"
26 #include "tink/util/statusor.h"
27 
28 extern "C" {
29 #include "third_party/pqclean/crypto_sign/dilithium2/api.h"
30 #include "third_party/pqclean/crypto_sign/dilithium2aes/api.h"
31 #include "third_party/pqclean/crypto_sign/dilithium3/api.h"
32 #include "third_party/pqclean/crypto_sign/dilithium3aes/api.h"
33 #include "third_party/pqclean/crypto_sign/dilithium5/api.h"
34 #include "third_party/pqclean/crypto_sign/dilithium5aes/api.h"
35 }
36 
37 namespace crypto {
38 namespace tink {
39 namespace subtle {
40 
41 // static
42 util::StatusOr<DilithiumPrivateKeyPqclean>
NewPrivateKey(util::SecretData key_data,DilithiumSeedExpansion seed_expansion)43 DilithiumPrivateKeyPqclean::NewPrivateKey(
44     util::SecretData key_data, DilithiumSeedExpansion seed_expansion) {
45   return DilithiumPrivateKeyPqclean(key_data, seed_expansion);
46 }
47 
48 // static
49 util::StatusOr<std::pair<DilithiumPrivateKeyPqclean, DilithiumPublicKeyPqclean>>
GenerateKeyPair(int32_t private_key_size,DilithiumSeedExpansion seed_expansion)50 DilithiumPrivateKeyPqclean::GenerateKeyPair(
51     int32_t private_key_size, DilithiumSeedExpansion seed_expansion) {
52   std::string public_key;
53   std::string private_key;
54   private_key.resize(private_key_size);
55 
56   // Check if the key_size parameter is correct.
57   switch (private_key_size) {
58     // Dilithium2.
59     case PQCLEAN_DILITHIUM2_CRYPTO_SECRETKEYBYTES: {
60       switch (seed_expansion) {
61         case DilithiumSeedExpansion::SEED_EXPANSION_AES: {
62           public_key.resize(PQCLEAN_DILITHIUM2AES_CRYPTO_PUBLICKEYBYTES);
63           PQCLEAN_DILITHIUM2AES_crypto_sign_keypair(
64               reinterpret_cast<uint8_t*>(public_key.data()),
65               reinterpret_cast<uint8_t*>(private_key.data()));
66           break;
67         }
68         case DilithiumSeedExpansion::SEED_EXPANSION_SHAKE: {
69           public_key.resize(PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES);
70           PQCLEAN_DILITHIUM2_crypto_sign_keypair(
71               reinterpret_cast<uint8_t*>(public_key.data()),
72               reinterpret_cast<uint8_t*>(private_key.data()));
73           break;
74         }
75         default: {
76           return util::Status(absl::StatusCode::kInvalidArgument,
77                               "Invalid seed expansion");
78         }
79       }
80       break;
81     }
82     // Dilithium3.
83     case PQCLEAN_DILITHIUM3_CRYPTO_SECRETKEYBYTES: {
84       switch (seed_expansion) {
85         case DilithiumSeedExpansion::SEED_EXPANSION_AES: {
86           public_key.resize(PQCLEAN_DILITHIUM3AES_CRYPTO_PUBLICKEYBYTES);
87           PQCLEAN_DILITHIUM3AES_crypto_sign_keypair(
88               reinterpret_cast<uint8_t*>(public_key.data()),
89               reinterpret_cast<uint8_t*>(private_key.data()));
90           break;
91         }
92         case DilithiumSeedExpansion::SEED_EXPANSION_SHAKE: {
93           public_key.resize(PQCLEAN_DILITHIUM3_CRYPTO_PUBLICKEYBYTES);
94           PQCLEAN_DILITHIUM3_crypto_sign_keypair(
95               reinterpret_cast<uint8_t*>(public_key.data()),
96               reinterpret_cast<uint8_t*>(private_key.data()));
97           break;
98         }
99         default: {
100           return util::Status(absl::StatusCode::kInvalidArgument,
101                               "Invalid seed expansion");
102         }
103       }
104       break;
105     }
106     // Dilithium5.
107     case PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES: {
108       switch (seed_expansion) {
109         case DilithiumSeedExpansion::SEED_EXPANSION_AES: {
110           public_key.resize(PQCLEAN_DILITHIUM5AES_CRYPTO_PUBLICKEYBYTES);
111           PQCLEAN_DILITHIUM5AES_crypto_sign_keypair(
112               reinterpret_cast<uint8_t*>(public_key.data()),
113               reinterpret_cast<uint8_t*>(private_key.data()));
114           break;
115         }
116         case DilithiumSeedExpansion::SEED_EXPANSION_SHAKE: {
117           public_key.resize(PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES);
118           PQCLEAN_DILITHIUM5_crypto_sign_keypair(
119               reinterpret_cast<uint8_t*>(public_key.data()),
120               reinterpret_cast<uint8_t*>(private_key.data()));
121           break;
122         }
123         default: {
124           return util::Status(absl::StatusCode::kInvalidArgument,
125                               "Invalid seed expansion");
126         }
127       }
128       break;
129     }
130     // Invalid key size.
131     default: {
132       return util::Status(
133           absl::StatusCode::kInvalidArgument,
134           absl::StrFormat("Invalid private key size (%d). "
135                           "The only valid sizes are %d, %d, %d.",
136                           private_key_size,
137                           PQCLEAN_DILITHIUM2_CRYPTO_SECRETKEYBYTES,
138                           PQCLEAN_DILITHIUM3_CRYPTO_SECRETKEYBYTES,
139                           PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES));
140     }
141   }
142 
143   util::SecretData private_key_data =
144       util::SecretDataFromStringView(private_key);
145 
146   util::StatusOr<DilithiumPrivateKeyPqclean> dilithium_private_key =
147       DilithiumPrivateKeyPqclean::NewPrivateKey(std::move(private_key_data),
148                                                 seed_expansion);
149   util::StatusOr<DilithiumPublicKeyPqclean> dilithium_public_key =
150       DilithiumPublicKeyPqclean::NewPublicKey(public_key, seed_expansion);
151 
152   return std::make_pair(*dilithium_private_key, *dilithium_public_key);
153 }
154 
GetKeyData() const155 const util::SecretData& DilithiumPrivateKeyPqclean::GetKeyData() const {
156   return key_data_;
157 }
158 
GetSeedExpansion() const159 const DilithiumSeedExpansion& DilithiumPrivateKeyPqclean::GetSeedExpansion()
160     const {
161   return seed_expansion_;
162 }
163 
164 // static
165 util::StatusOr<DilithiumPublicKeyPqclean>
NewPublicKey(absl::string_view key_data,DilithiumSeedExpansion seed_expansion)166 DilithiumPublicKeyPqclean::NewPublicKey(absl::string_view key_data,
167                                         DilithiumSeedExpansion seed_expansion) {
168   return DilithiumPublicKeyPqclean(key_data, seed_expansion);
169 }
170 
GetKeyData() const171 const std::string& DilithiumPublicKeyPqclean::GetKeyData() const {
172   return key_data_;
173 }
174 
GetSeedExpansion() const175 const DilithiumSeedExpansion& DilithiumPublicKeyPqclean::GetSeedExpansion()
176     const {
177   return seed_expansion_;
178 }
179 
180 }  // namespace subtle
181 }  // namespace tink
182 }  // namespace crypto
183