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_avx2_verify.h"
18
19 #include <algorithm>
20 #include <cstddef>
21 #include <iterator>
22 #include <memory>
23 #include <string>
24 #include <utility>
25
26 #include "absl/memory/memory.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/str_format.h"
29 #include "absl/strings/string_view.h"
30 #include "tink/experimental/pqcrypto/signature/subtle/dilithium_key.h"
31 #include "tink/public_key_verify.h"
32 #include "tink/util/statusor.h"
33
34 extern "C" {
35 #include "third_party/pqclean/crypto_sign/dilithium2/api.h"
36 #include "third_party/pqclean/crypto_sign/dilithium2aes/api.h"
37 #include "third_party/pqclean/crypto_sign/dilithium3/api.h"
38 #include "third_party/pqclean/crypto_sign/dilithium3aes/api.h"
39 #include "third_party/pqclean/crypto_sign/dilithium5/api.h"
40 #include "third_party/pqclean/crypto_sign/dilithium5aes/api.h"
41 }
42
43 namespace crypto {
44 namespace tink {
45 namespace subtle {
46
47 // static
New(DilithiumPublicKeyPqclean public_key)48 util::StatusOr<std::unique_ptr<PublicKeyVerify>> DilithiumAvx2Verify::New(
49 DilithiumPublicKeyPqclean public_key) {
50 auto status = internal::CheckFipsCompatibility<DilithiumAvx2Verify>();
51 if (!status.ok()) return status;
52
53 int32_t key_size = public_key.GetKeyData().size();
54
55 if (key_size != PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES &&
56 key_size != PQCLEAN_DILITHIUM3_CRYPTO_PUBLICKEYBYTES &&
57 key_size != PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES) {
58 return util::Status(
59 absl::StatusCode::kInvalidArgument,
60 absl::StrFormat("Invalid public key size (%d). "
61 "The only valid sizes are %d, %d, %d.",
62 key_size, PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES,
63 PQCLEAN_DILITHIUM3_CRYPTO_PUBLICKEYBYTES,
64 PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES));
65 }
66
67 return {absl::WrapUnique(new DilithiumAvx2Verify(std::move(public_key)))};
68 }
69
Verify(absl::string_view signature,absl::string_view data) const70 util::Status DilithiumAvx2Verify::Verify(absl::string_view signature,
71 absl::string_view data) const {
72 int32_t key_size = public_key_.GetKeyData().size();
73 int result = 1;
74
75 switch (key_size) {
76 case PQCLEAN_DILITHIUM2_CRYPTO_PUBLICKEYBYTES: {
77 switch (public_key_.GetSeedExpansion()) {
78 case DilithiumSeedExpansion::SEED_EXPANSION_AES: {
79 result = PQCLEAN_DILITHIUM2AES_crypto_sign_verify(
80 reinterpret_cast<const uint8_t *>(signature.data()),
81 signature.size(), reinterpret_cast<const uint8_t *>(data.data()),
82 data.size(),
83 reinterpret_cast<const uint8_t *>(
84 public_key_.GetKeyData().data()));
85
86 break;
87 }
88 case DilithiumSeedExpansion::SEED_EXPANSION_SHAKE: {
89 result = PQCLEAN_DILITHIUM2_crypto_sign_verify(
90 reinterpret_cast<const uint8_t *>(signature.data()),
91 signature.size(), reinterpret_cast<const uint8_t *>(data.data()),
92 data.size(),
93 reinterpret_cast<const uint8_t *>(
94 public_key_.GetKeyData().data()));
95 break;
96 }
97 default: {
98 return util::Status(absl::StatusCode::kInternal,
99 "Invalid seed expansion.");
100 }
101 }
102 break;
103 }
104 case PQCLEAN_DILITHIUM3_CRYPTO_PUBLICKEYBYTES: {
105 switch (public_key_.GetSeedExpansion()) {
106 case DilithiumSeedExpansion::SEED_EXPANSION_AES: {
107 result = PQCLEAN_DILITHIUM3AES_crypto_sign_verify(
108 reinterpret_cast<const uint8_t *>(signature.data()),
109 signature.size(), reinterpret_cast<const uint8_t *>(data.data()),
110 data.size(),
111 reinterpret_cast<const uint8_t *>(
112 public_key_.GetKeyData().data()));
113 break;
114 }
115 case DilithiumSeedExpansion::SEED_EXPANSION_SHAKE: {
116 result = PQCLEAN_DILITHIUM3_crypto_sign_verify(
117 reinterpret_cast<const uint8_t *>(signature.data()),
118 signature.size(), reinterpret_cast<const uint8_t *>(data.data()),
119 data.size(),
120 reinterpret_cast<const uint8_t *>(
121 public_key_.GetKeyData().data()));
122 break;
123 }
124 default: {
125 return util::Status(absl::StatusCode::kInternal,
126 "Invalid seed expansion.");
127 }
128 }
129 break;
130 }
131 case PQCLEAN_DILITHIUM5_CRYPTO_PUBLICKEYBYTES: {
132 switch (public_key_.GetSeedExpansion()) {
133 case DilithiumSeedExpansion::SEED_EXPANSION_AES: {
134 result = PQCLEAN_DILITHIUM5AES_crypto_sign_verify(
135 reinterpret_cast<const uint8_t *>(signature.data()),
136 signature.size(), reinterpret_cast<const uint8_t *>(data.data()),
137 data.size(),
138 reinterpret_cast<const uint8_t *>(
139 public_key_.GetKeyData().data()));
140 break;
141 }
142 case DilithiumSeedExpansion::SEED_EXPANSION_SHAKE: {
143 result = PQCLEAN_DILITHIUM5_crypto_sign_verify(
144 reinterpret_cast<const uint8_t *>(signature.data()),
145 signature.size(), reinterpret_cast<const uint8_t *>(data.data()),
146 data.size(),
147 reinterpret_cast<const uint8_t *>(
148 public_key_.GetKeyData().data()));
149 break;
150 }
151 default: {
152 return util::Status(absl::StatusCode::kInternal,
153 "Invalid seed expansion.");
154 }
155 }
156 break;
157 }
158 default:
159 return util::Status(absl::StatusCode::kInternal, "Invalid keysize.");
160 }
161
162 if (result != 0) {
163 return util::Status(absl::StatusCode::kInvalidArgument,
164 "Signature is not valid.");
165 }
166
167 return util::OkStatus();
168 }
169
170 } // namespace subtle
171 } // namespace tink
172 } // namespace crypto
173