// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 OR ISC #include #include #include #include #include #include "../../test/file_test.h" #include "../../test/test_util.h" #include "internal.h" // Set values for input/output lengths used in // |NISTTestVectors_SHAKESqueeze| test function #define RAND_BYTES 256 #define RAND_OUT_BYTES 256 #define RAND_BYTES_x4 34 #define RAND_OUT_BLCKS 6 #define BATCHED_x4 4 #define NUM_TESTS 10 // Table containing the length of the output to squeeze for the // initial call, followed by a output length for each subsequent call. static const struct { size_t startsz, incsz; } stride_tests[] = { // Test Edge Cases for SHAKE128 with blocksize of 168B { 1, 1 }, { 8, 8 }, { 9, 9 }, { 10, 10 }, { 1, 168 }, { 1, 168/2 }, { 1, 168/2-1 }, { 1, 168/2+1 }, { 1, 168*3 }, { 168/2 - 1, 168 }, { 168/2 - 1, 168-1 }, { 168/2 - 1, 168+1 }, { 168/2, 168 }, { 168/2, 168-1 }, { 168/2, 168+1 }, { 168/2 + 1, 168 }, { 168/2 + 1, 168-1 }, { 168/2 + 1, 168+1 }, { 168, 2 }, { 168, 168 }, { 168-1, 168 }, { 168-1, 168-1 }, { 168-1, 168+1 }, { 168+1, 168 }, { 168+1, 168-1 }, { 168+1, 168+1 }, { 168*3, 168 }, { 168*3, 168 + 1 }, { 168*3, 168 - 1 }, { 168*3, 168/2 }, { 168*3, 168/2 + 1 }, { 168*3, 168/2 - 1 }, // Test Edge Cases for SHAKE256 with blocksize of 136B { 1, 136 }, { 1, 136/2 }, { 1, 136/2-1 }, { 1, 136/2+1 }, { 1, 136*3 }, { 8, 8 }, { 9, 9 }, { 10, 10 }, { 136/2 - 1, 136 }, { 136/2 - 1, 136-1 }, { 136/2 - 1, 136+1 }, { 136/2, 136 }, { 136/2, 136-1 }, { 136/2, 136+1 }, { 136/2 + 1, 136 }, { 136/2 + 1, 136-1 }, { 136/2 + 1, 136+1 }, { 136, 2 }, { 136, 136 }, { 136-1, 136 }, { 136-1, 136-1 }, { 136-1, 136+1 }, { 136+1, 136 }, { 136+1, 136-1 }, { 136+1, 136+1 }, { 136*3, 136 }, { 136*3, 136 + 1 }, { 136*3, 136 - 1 }, { 136*3, 136/2 }, { 136*3, 136/2 + 1 }, { 136*3, 136/2 - 1 } }; // SHA3TestVector corresponds to one test case of the NIST published file // SHA3_256ShortMsg.txt. // https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/secure-hashing class SHA3TestVector { public: explicit SHA3TestVector() = default; ~SHA3TestVector() = default; bool ReadFromFileTest(FileTest *t); void NISTTestVectors(const EVP_MD *algorithm) const { uint32_t digest_length; std::unique_ptr digest(new uint8_t[EVP_MD_size(algorithm)]); bssl::ScopedEVP_MD_CTX ctx; // Test the correctness via the Init, Update and Final Digest APIs. ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), len_ / 8)); ASSERT_TRUE(EVP_DigestFinal(ctx.get(), digest.get(), &digest_length)); ASSERT_EQ(Bytes(digest.get(), EVP_MD_size(algorithm)), Bytes(digest_.data(), EVP_MD_size(algorithm))); // Test XOF-specific Digest functions with non XOF algorithms // Assert failure when |EVP_DigestSqueeze| or |EVP_DigestFinalXOF| // are called with digests different from XOF digests ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); ASSERT_FALSE(EVP_DigestSqueeze(ctx.get(), digest.get(), digest_length)); ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); } void NISTTestVectors_SingleShot(const EVP_MD *algorithm) const { uint32_t digest_length; std::unique_ptr digest(new uint8_t[EVP_MD_size(algorithm)]); // Test the correctness via the Single-Shot EVP_Digest APIs. ASSERT_TRUE(EVP_Digest(msg_.data(), len_ / 8, digest.get(), &digest_length, algorithm, nullptr)); ASSERT_EQ(Bytes(digest.get(), EVP_MD_size(algorithm)), Bytes(digest_.data(), EVP_MD_size(algorithm))); } void NISTTestVectors_SHAKE(const EVP_MD *algorithm) const { uint32_t digest_length = out_len_ / 8; std::unique_ptr digest(new uint8_t[digest_length]); bssl::ScopedEVP_MD_CTX ctx; // Test the incremental EVP API ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); // Test the one-shot ASSERT_TRUE(EVP_Digest(msg_.data(), msg_.size(), digest.get(), &digest_length, algorithm, nullptr)); EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); } // Test SHAKE Squeeze functionality through |EVP_Digest| APIs void NISTTestVectors_SHAKESqueeze(const EVP_MD *algorithm) const { uint8_t random_bytes[RAND_BYTES]; size_t sqd_bytes = 0, cur_test = 0, to_sq_bytes = 0; uint32_t digest_length = out_len_ / 8; std::unique_ptr digest(new uint8_t[digest_length]); std::unique_ptr digest_stream(new uint8_t[RAND_OUT_BYTES]); std::unique_ptr digest_signle_shot(new uint8_t[RAND_OUT_BYTES]); bssl::ScopedEVP_MD_CTX ctx; // Test Final XOF // Assert fail when |EVP_DigestFinalXOF| is called as a streaming API ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); ASSERT_FALSE(EVP_DigestSqueeze(ctx.get(), digest.get(), digest_length)); // Test the one-shot // Assert success when |EVP_Digest| is called OPENSSL_memset(digest.get(), 0, digest_length); ASSERT_TRUE(EVP_Digest(msg_.data(), msg_.size(), digest.get(), &digest_length, algorithm, nullptr)); EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); // Test Final // Assert fail when |EVP_DigestFinal| is called for XOF algorithms OPENSSL_memset(digest.get(), 0, digest_length); ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); ASSERT_FALSE(EVP_DigestFinal(ctx.get(), digest.get(), &digest_length)); ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); // Test Final XOF after Squeeze // Assert fail when |EVP_DigestFinalXOF| is called after |EVP_DigestSqueeze| ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get(), digest_length/2)); ASSERT_FALSE(EVP_DigestFinalXOF(ctx.get(), digest.get() + digest_length/2, digest_length/2)); // Test Update after Squeeze // Assert fail when |EVP_DigestUpdate| is called after |EVP_DigestSqueeze| ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get(), digest_length)); ASSERT_FALSE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); // Test Absorb // Assert success when |EVP_DigestUpdate| is called byte-by-byte OPENSSL_memset(digest.get(), 0, digest_length); ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), nullptr, 0)); for (const char p : msg_) { ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), &p, 1)); } ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest.get(), digest_length)); EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); // Test Squeeze // Assert success when |EVP_DigestSqueeze| is called byte-by-byte OPENSSL_memset(digest.get(), 0, digest_length); ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); for (size_t i = 0; i < digest_length; i++) { ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get() + i, 1)); } EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); // Test Squeeze // Assert success when |EVP_DigestSqueeze| is called in set byte increments for (cur_test = 0, sqd_bytes = 0; cur_test < (int) (sizeof(stride_tests)/sizeof(stride_tests[0])); cur_test++, sqd_bytes = 0) { to_sq_bytes = stride_tests[cur_test].startsz; OPENSSL_memset(digest.get(), 0, digest_length); ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); while (sqd_bytes < digest_length) { if ((sqd_bytes + to_sq_bytes) > digest_length) { to_sq_bytes = digest_length - sqd_bytes; } ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get() + sqd_bytes, to_sq_bytes)); sqd_bytes += to_sq_bytes; to_sq_bytes = stride_tests[cur_test].incsz; } EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); } // Test Squeeze Exhaustive // Assert success when |EVP_DigestSqueeze| is called in all possible byte increments for (to_sq_bytes = 1; to_sq_bytes < digest_length; to_sq_bytes++) { OPENSSL_memset(digest.get(), 0, digest_length); ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), msg_.data(), msg_.size())); for (sqd_bytes = 0; sqd_bytes <= digest_length - to_sq_bytes; sqd_bytes+=to_sq_bytes) { ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get() + sqd_bytes, to_sq_bytes)); } if ((digest_length - sqd_bytes) > 0) { ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest.get() + sqd_bytes, digest_length - sqd_bytes)); } EXPECT_EQ(Bytes(digest.get(), digest_length), Bytes(digest_.data(), digest_length)); } // Test Squeeze with random Input // Assert success when |EVP_DigestSqueeze| is called on a random message ASSERT_TRUE(RAND_bytes(random_bytes, RAND_BYTES)); ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes, RAND_BYTES)); for (size_t i = 0; i < RAND_OUT_BYTES; i++) { ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + i, 1)); } ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes, RAND_BYTES)); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), RAND_OUT_BYTES)); EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), RAND_OUT_BYTES)), EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), RAND_OUT_BYTES))); // Test Squeeze with random Input // Assert success when |EVP_DigestSqueeze| is called on a random message // in set byte increments for (cur_test = 0, sqd_bytes = 0; cur_test < (int) (sizeof(stride_tests)/sizeof(stride_tests[0])); cur_test++, sqd_bytes = 0) { to_sq_bytes = stride_tests[cur_test].startsz; OPENSSL_memset(digest_stream.get(), 0, RAND_OUT_BYTES); OPENSSL_memset(digest_signle_shot.get(), 0, RAND_OUT_BYTES); ASSERT_TRUE(RAND_bytes(random_bytes, RAND_BYTES)); // Incremental Squeezes ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes, RAND_BYTES)); while (sqd_bytes < RAND_OUT_BYTES) { if ((sqd_bytes + to_sq_bytes) > RAND_OUT_BYTES) { to_sq_bytes = RAND_OUT_BYTES - sqd_bytes; } ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + sqd_bytes, to_sq_bytes)); sqd_bytes += to_sq_bytes; to_sq_bytes = stride_tests[cur_test].incsz; } // Single-Shot Squeeze ASSERT_TRUE(EVP_DigestInit_ex(ctx.get(), algorithm, NULL)); ASSERT_TRUE(EVP_DigestUpdate(ctx.get(), random_bytes, RAND_BYTES)); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), RAND_OUT_BYTES)); EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), RAND_OUT_BYTES)), EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), RAND_OUT_BYTES))); } // Test Final XOF without Update // Assert fail when |EVP_DigestFinalXOF| is called as a streaming API OPENSSL_memset(digest_signle_shot.get(), 0, RAND_OUT_BYTES); OPENSSL_memset(digest_stream.get(), 0, RAND_OUT_BYTES); ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestFinalXOF(ctx.get(), digest_signle_shot.get(), RAND_OUT_BYTES)); ASSERT_TRUE(EVP_DigestInit(ctx.get(), algorithm)); ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get(), RAND_OUT_BYTES/2)); ASSERT_TRUE(EVP_DigestSqueeze(ctx.get(), digest_stream.get() + RAND_OUT_BYTES/2, RAND_OUT_BYTES/2)); EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_stream.get(), RAND_OUT_BYTES)), EncodeHex(bssl::MakeConstSpan(digest_signle_shot.get(), RAND_OUT_BYTES))); } private: uint32_t len_; uint32_t out_len_; std::vector msg_; std::vector digest_; }; // Read the |key| attribute from |file_test| and convert it to an integer. template bool FileTestReadInt(FileTest *file_test, T *out, const std::string &key) { std::string s; return file_test->GetAttribute(&s, key) && testing::internal::ParseInt32( testing::Message() << "The value " << s.data() << " is not convertable to an integer.", s.data(), (int *)out); } bool SHA3TestVector::ReadFromFileTest(FileTest *t) { if (t->HasAttribute("Outputlen")) { if (!FileTestReadInt(t, &out_len_, "Outputlen")) { return false; } } if (t->HasAttribute("Len")) { if (!FileTestReadInt(t, &len_, "Len")) { return false; } } if (!t->GetBytes(&msg_, "Msg") || !t->GetBytes(&digest_, "MD")) { return false; } return true; } TEST(SHA3Test, NISTTestVectors) { FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_224ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_224(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_256ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_256(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_384ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_384(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_512ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_512(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_224LongMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_224(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_256LongMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_256(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_384LongMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_384(); test_vec.NISTTestVectors(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_512LongMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_512(); test_vec.NISTTestVectors(algorithm); }); } TEST(SHA3Test, NISTTestVectors_SingleShot) { FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_224ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_224(); test_vec.NISTTestVectors_SingleShot(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_256ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_256(); test_vec.NISTTestVectors_SingleShot(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_384ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_384(); test_vec.NISTTestVectors_SingleShot(algorithm); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHA3_512ShortMsg.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); const EVP_MD *algorithm = EVP_sha3_512(); test_vec.NISTTestVectors_SingleShot(algorithm); }); } TEST(KeccakInternalTest, SqueezeOutputBufferOverflow) { EVP_MD_unstable_sha3_enable(true); KECCAK1600_CTX ctx; std::vector out; std::vector canary(8); std::fill(canary.begin(), canary.end(), 0xff); const size_t out_lens[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, (1 << 5), (1 << 16) + 1}; for (auto out_len : out_lens) { EXPECT_TRUE(SHA3_Init(&ctx, SHA3_384_DIGEST_BITLENGTH)); out.resize(out_len + canary.size()); std::copy(canary.begin(), canary.end(), out.end() - canary.size()); Keccak1600_Squeeze(ctx.A, out.data(), out_len, ctx.block_size, 1); EXPECT_TRUE(std::equal(out.end() - canary.size(), out.end(), canary.begin()) == true); } EVP_MD_unstable_sha3_enable(false); } // Test x4 batched SHAKE against 4 consecutive SHAKE calls // Assert success when digest and digest_x4 values are equal TEST(SHAKETest_x4, RandomMessages) { KECCAK1600_CTX_x4 ctx; uint8_t random_in[BATCHED_x4][RAND_BYTES_x4]; uint8_t digest[BATCHED_x4][RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE]; uint8_t digest_x4[BATCHED_x4][RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE]; // Test |SHAKE128_Init_x4|, |SHAKE128_Absorb_once_x4|, and |SHAKE128_Squeezeblocks_x4| functions // Assert success when digest and digest_x4 values are equal for (int i = 0; i < NUM_TESTS; i++) { for (int j = 0; j < BATCHED_x4; j++) { OPENSSL_memset(digest[j], 0, RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE); OPENSSL_memset(digest_x4[j], 0, RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE); ASSERT_TRUE(RAND_bytes(random_in[j], RAND_BYTES_x4)); ASSERT_TRUE(SHAKE128(random_in[j], RAND_BYTES_x4, digest[j], RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE)); } // Compute one batched x4 SHAKE128 ASSERT_TRUE(SHAKE128_Init_x4(&ctx)); ASSERT_TRUE(SHAKE128_Absorb_once_x4(&ctx, random_in[0], random_in[1], random_in[2], random_in[3], RAND_BYTES_x4)); ASSERT_TRUE(SHAKE128_Squeezeblocks_x4(digest_x4[0], digest_x4[1], digest_x4[2], digest_x4[3], &ctx, RAND_OUT_BLCKS)); for (int j = 0; j < BATCHED_x4; j++) { EXPECT_EQ(Bytes(digest_x4[j], RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE), Bytes(digest[j], RAND_OUT_BLCKS * SHAKE128_BLOCKSIZE)); } } // Test |SHAKE256_x4| function // Assert success when digest and digest_x4 values are equal for (int i = 0; i < NUM_TESTS; i++) { for (int j = 0; j < BATCHED_x4; j++) { OPENSSL_memset(digest[j], 0, RAND_OUT_BLCKS); OPENSSL_memset(digest_x4[j], 0, RAND_OUT_BLCKS); ASSERT_TRUE(RAND_bytes(random_in[j], RAND_BYTES_x4)); SHAKE256(random_in[j], RAND_BYTES_x4, digest[j], RAND_OUT_BLCKS); } // Compute one batched x4 SHAKE128 ASSERT_TRUE(SHAKE256_x4(random_in[0], random_in[1], random_in[2], random_in[3], RAND_BYTES_x4, digest_x4[0], digest_x4[1], digest_x4[2], digest_x4[3], RAND_OUT_BLCKS)); for (int j = 0; j < BATCHED_x4; j++) { EXPECT_EQ(EncodeHex(bssl::MakeConstSpan(digest_x4[j], RAND_OUT_BLCKS)), EncodeHex(bssl::MakeConstSpan(digest[j], RAND_OUT_BLCKS))); } } } TEST(SHAKETest, NISTTestVectors) { FileTestGTest("crypto/fipsmodule/sha/testvectors/SHAKE128VariableOut.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); test_vec.NISTTestVectors_SHAKE(EVP_shake128()); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHAKE256VariableOut.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); test_vec.NISTTestVectors_SHAKE(EVP_shake256()); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHAKE128VariableOut.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); test_vec.NISTTestVectors_SHAKESqueeze(EVP_shake128()); }); FileTestGTest("crypto/fipsmodule/sha/testvectors/SHAKE256VariableOut.txt", [](FileTest *t) { SHA3TestVector test_vec; EXPECT_TRUE(test_vec.ReadFromFileTest(t)); test_vec.NISTTestVectors_SHAKESqueeze(EVP_shake256()); }); }