• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/dilithium_sign_key_manager.h"
18 
19 #include <memory>
20 #include <string>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/container/flat_hash_set.h"
25 #include "absl/strings/str_cat.h"
26 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_avx2_sign.h"
27 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_avx2_verify.h"
28 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_key.h"
29 #include "tink/experimental/pqcrypto/signature/util/enums.h"
30 #include "tink/public_key_verify.h"
31 #include "tink/util/secret_data.h"
32 #include "tink/util/status.h"
33 #include "tink/util/statusor.h"
34 #include "tink/util/test_matchers.h"
35 
36 extern "C" {
37 #include "third_party/pqclean/crypto_sign/dilithium2/api.h"
38 #include "third_party/pqclean/crypto_sign/dilithium2aes/api.h"
39 #include "third_party/pqclean/crypto_sign/dilithium3/api.h"
40 #include "third_party/pqclean/crypto_sign/dilithium3aes/api.h"
41 #include "third_party/pqclean/crypto_sign/dilithium5/api.h"
42 #include "third_party/pqclean/crypto_sign/dilithium5aes/api.h"
43 }
44 
45 namespace crypto {
46 namespace tink {
47 namespace {
48 
49 using ::crypto::tink::subtle::DilithiumPublicKeyPqclean;
50 using ::crypto::tink::test::IsOk;
51 using ::crypto::tink::util::EnumsPqcrypto;
52 using ::crypto::tink::util::StatusOr;
53 using ::google::crypto::tink::DilithiumKeyFormat;
54 using ::google::crypto::tink::DilithiumParams;
55 using ::google::crypto::tink::DilithiumPrivateKey;
56 using ::google::crypto::tink::DilithiumPublicKey;
57 using ::google::crypto::tink::DilithiumSeedExpansion;
58 using ::google::crypto::tink::KeyData;
59 using ::testing::Eq;
60 using ::testing::Not;
61 using ::testing::SizeIs;
62 
63 struct DilithiumTestCase {
64   std::string test_name;
65   int32_t private_key_size;
66   int32_t public_key_size;
67   DilithiumSeedExpansion seed_expansion;
68 };
69 
70 using DilithiumSignKeyManagerTest = testing::TestWithParam<DilithiumTestCase>;
71 
72 // Helper function that returns a valid dilithium key format.
CreateValidKeyFormat(int32_t private_key_size,DilithiumSeedExpansion seed_expansion)73 StatusOr<DilithiumKeyFormat> CreateValidKeyFormat(
74     int32_t private_key_size, DilithiumSeedExpansion seed_expansion) {
75   DilithiumKeyFormat key_format;
76   DilithiumParams* params = key_format.mutable_params();
77   params->set_key_size(private_key_size);
78   params->set_seed_expansion(seed_expansion);
79 
80   return key_format;
81 }
82 
TEST(DilithiumSignKeyManagerTest,Basic)83 TEST(DilithiumSignKeyManagerTest, Basic) {
84   EXPECT_THAT(DilithiumSignKeyManager().get_version(), Eq(0));
85   EXPECT_THAT(DilithiumSignKeyManager().key_material_type(),
86               Eq(KeyData::ASYMMETRIC_PRIVATE));
87   EXPECT_THAT(DilithiumSignKeyManager().get_key_type(),
88               Eq("type.googleapis.com/google.crypto.tink.DilithiumPrivateKey"));
89 }
90 
TEST_P(DilithiumSignKeyManagerTest,ValidateKeyFormat)91 TEST_P(DilithiumSignKeyManagerTest, ValidateKeyFormat) {
92   const DilithiumTestCase& test_case = GetParam();
93 
94   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
95       test_case.private_key_size, test_case.seed_expansion);
96   ASSERT_THAT(key_format, IsOk());
97 
98   EXPECT_THAT(DilithiumSignKeyManager().ValidateKeyFormat(*key_format), IsOk());
99 }
100 
TEST_P(DilithiumSignKeyManagerTest,PrivateKeyWrongVersion)101 TEST_P(DilithiumSignKeyManagerTest, PrivateKeyWrongVersion) {
102   const DilithiumTestCase& test_case = GetParam();
103 
104   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
105       test_case.private_key_size, test_case.seed_expansion);
106   ASSERT_THAT(key_format, IsOk());
107 
108   StatusOr<DilithiumPrivateKey> private_key =
109       DilithiumSignKeyManager().CreateKey(*key_format);
110   ASSERT_THAT(private_key, IsOk());
111 
112   private_key->set_version(1);
113   EXPECT_THAT(DilithiumSignKeyManager().ValidateKey(*private_key), Not(IsOk()));
114 }
115 
TEST_P(DilithiumSignKeyManagerTest,CreateKey)116 TEST_P(DilithiumSignKeyManagerTest, CreateKey) {
117   const DilithiumTestCase& test_case = GetParam();
118 
119   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
120       test_case.private_key_size, test_case.seed_expansion);
121   ASSERT_THAT(key_format, IsOk());
122 
123   StatusOr<DilithiumPrivateKey> private_key =
124       DilithiumSignKeyManager().CreateKey(*key_format);
125   ASSERT_THAT(private_key, IsOk());
126 
127   EXPECT_THAT(private_key->version(), Eq(0));
128   EXPECT_THAT(private_key->public_key().version(), Eq(private_key->version()));
129   EXPECT_THAT(private_key->key_value(), SizeIs(test_case.private_key_size));
130   EXPECT_THAT(private_key->public_key().key_value(),
131               SizeIs(test_case.public_key_size));
132 }
133 
TEST_P(DilithiumSignKeyManagerTest,CreateKeyValid)134 TEST_P(DilithiumSignKeyManagerTest, CreateKeyValid) {
135   const DilithiumTestCase& test_case = GetParam();
136 
137   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
138       test_case.private_key_size, test_case.seed_expansion);
139   ASSERT_THAT(key_format, IsOk());
140 
141   StatusOr<DilithiumPrivateKey> private_key =
142       DilithiumSignKeyManager().CreateKey(*key_format);
143   ASSERT_THAT(private_key, IsOk());
144   EXPECT_THAT(DilithiumSignKeyManager().ValidateKey(*private_key), IsOk());
145 }
146 
TEST_P(DilithiumSignKeyManagerTest,CreateKeyAlwaysNew)147 TEST_P(DilithiumSignKeyManagerTest, CreateKeyAlwaysNew) {
148   const DilithiumTestCase& test_case = GetParam();
149 
150   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
151       test_case.private_key_size, test_case.seed_expansion);
152   ASSERT_THAT(key_format, IsOk());
153 
154   absl::flat_hash_set<std::string> keys;
155   int num_tests = 100;
156   for (int i = 0; i < num_tests; ++i) {
157     StatusOr<DilithiumPrivateKey> private_key =
158         DilithiumSignKeyManager().CreateKey(*key_format);
159     ASSERT_THAT(private_key, IsOk());
160     keys.insert(private_key->key_value());
161   }
162   EXPECT_THAT(keys, SizeIs(num_tests));
163 }
164 
TEST_P(DilithiumSignKeyManagerTest,GetPublicKey)165 TEST_P(DilithiumSignKeyManagerTest, GetPublicKey) {
166   const DilithiumTestCase& test_case = GetParam();
167 
168   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
169       test_case.private_key_size, test_case.seed_expansion);
170   ASSERT_THAT(key_format, IsOk());
171 
172   StatusOr<DilithiumPrivateKey> private_key =
173       DilithiumSignKeyManager().CreateKey(*key_format);
174   ASSERT_THAT(private_key, IsOk());
175 
176   StatusOr<DilithiumPublicKey> public_key_or =
177       DilithiumSignKeyManager().GetPublicKey(*private_key);
178   ASSERT_THAT(public_key_or, IsOk());
179 
180   EXPECT_THAT(public_key_or->version(),
181               Eq(private_key->public_key().version()));
182   EXPECT_THAT(public_key_or->key_value(),
183               Eq(private_key->public_key().key_value()));
184 }
185 
TEST_P(DilithiumSignKeyManagerTest,Create)186 TEST_P(DilithiumSignKeyManagerTest, Create) {
187   const DilithiumTestCase& test_case = GetParam();
188 
189   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
190       test_case.private_key_size, test_case.seed_expansion);
191   ASSERT_THAT(key_format, IsOk());
192 
193   util::StatusOr<DilithiumPrivateKey> private_key =
194       DilithiumSignKeyManager().CreateKey(*key_format);
195   ASSERT_THAT(private_key, IsOk());
196 
197   util::StatusOr<std::unique_ptr<PublicKeySign>> signer =
198       DilithiumSignKeyManager().GetPrimitive<PublicKeySign>(*private_key);
199   ASSERT_THAT(signer, IsOk());
200 
201   util::StatusOr<DilithiumPublicKeyPqclean> dilithium_public_key =
202       DilithiumPublicKeyPqclean::NewPublicKey(
203           private_key->public_key().key_value(),
204           EnumsPqcrypto::ProtoToSubtle(test_case.seed_expansion));
205 
206   util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
207       subtle::DilithiumAvx2Verify::New(*dilithium_public_key);
208   ASSERT_THAT(verifier, IsOk());
209 
210   std::string message = "Some message";
211   util::StatusOr<std::string> signature = (*signer)->Sign(message);
212   ASSERT_THAT(signature, IsOk());
213   EXPECT_THAT((*verifier)->Verify(*signature, message), IsOk());
214 }
215 
TEST_P(DilithiumSignKeyManagerTest,CreateDifferentKey)216 TEST_P(DilithiumSignKeyManagerTest, CreateDifferentKey) {
217   const DilithiumTestCase& test_case = GetParam();
218 
219   StatusOr<DilithiumKeyFormat> key_format = CreateValidKeyFormat(
220       test_case.private_key_size, test_case.seed_expansion);
221   ASSERT_THAT(key_format, IsOk());
222 
223   util::StatusOr<DilithiumPrivateKey> private_key =
224       DilithiumSignKeyManager().CreateKey(*key_format);
225   ASSERT_THAT(private_key, IsOk());
226 
227   util::StatusOr<std::unique_ptr<PublicKeySign>> signer =
228       DilithiumSignKeyManager().GetPrimitive<PublicKeySign>(*private_key);
229   ASSERT_THAT(signer, IsOk());
230 
231   std::string bad_public_key_data(test_case.public_key_size, '@');
232   util::StatusOr<DilithiumPublicKeyPqclean> dilithium_public_key =
233       DilithiumPublicKeyPqclean::NewPublicKey(
234           bad_public_key_data,
235           EnumsPqcrypto::ProtoToSubtle(test_case.seed_expansion));
236   util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
237       subtle::DilithiumAvx2Verify::New(*dilithium_public_key);
238   ASSERT_THAT(verifier, IsOk());
239 
240   std::string message = "Some message";
241   util::StatusOr<std::string> signature = (*signer)->Sign(message);
242   ASSERT_THAT(signature, IsOk());
243   EXPECT_THAT((*verifier)->Verify(*signature, message), Not(IsOk()));
244 }
245 
246 INSTANTIATE_TEST_SUITE_P(
247     DilithiumSignKeyManagerTests, DilithiumSignKeyManagerTest,
248     testing::ValuesIn<DilithiumTestCase>({
249         {"Dilithium2", PQCLEAN_DILITHIUM2_CRYPTO_SECRETKEYBYTES,
250          PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES,
251          DilithiumSeedExpansion::SEED_EXPANSION_SHAKE},
252         {"Dilithium3", PQCLEAN_DILITHIUM3_CRYPTO_SECRETKEYBYTES,
253          PQCLEAN_DILITHIUM3_CRYPTO_PUBLICKEYBYTES,
254          DilithiumSeedExpansion::SEED_EXPANSION_SHAKE},
255         {"Dilithium5", PQCLEAN_DILITHIUM5_CRYPTO_SECRETKEYBYTES,
256          PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES,
257          DilithiumSeedExpansion::SEED_EXPANSION_SHAKE},
258         {"Dilithium2Aes", PQCLEAN_DILITHIUM2AES_CRYPTO_SECRETKEYBYTES,
259          PQCLEAN_DILITHIUM2AES_CRYPTO_PUBLICKEYBYTES,
260          DilithiumSeedExpansion::SEED_EXPANSION_AES},
261         {"Dilithium3Aes", PQCLEAN_DILITHIUM3AES_CRYPTO_SECRETKEYBYTES,
262          PQCLEAN_DILITHIUM3AES_CRYPTO_PUBLICKEYBYTES,
263          DilithiumSeedExpansion::SEED_EXPANSION_AES},
264         {"Dilithium5Aes", PQCLEAN_DILITHIUM5AES_CRYPTO_SECRETKEYBYTES,
265          PQCLEAN_DILITHIUM5AES_CRYPTO_PUBLICKEYBYTES,
266          DilithiumSeedExpansion::SEED_EXPANSION_AES},
267     }),
268     [](const testing::TestParamInfo<DilithiumSignKeyManagerTest::ParamType>&
__anon4e7a377c0202(const testing::TestParamInfo<DilithiumSignKeyManagerTest::ParamType>& info) 269            info) { return info.param.test_name; });
270 
271 }  // namespace
272 
273 }  // namespace tink
274 }  // namespace crypto
275