diff options
Diffstat (limited to 'src/tests/test_newhope.cpp')
-rw-r--r-- | src/tests/test_newhope.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/tests/test_newhope.cpp b/src/tests/test_newhope.cpp new file mode 100644 index 000000000..ed3690f55 --- /dev/null +++ b/src/tests/test_newhope.cpp @@ -0,0 +1,134 @@ +/* +* (C) 2016 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include "tests.h" + +#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA) + #include <botan/newhope.h> + #include <botan/chacha.h> + #include <botan/rng.h> +#endif + +namespace Botan_Tests { + +#if defined(BOTAN_HAS_NEWHOPE) && defined(BOTAN_HAS_CHACHA) + +class NEWHOPE_RNG : public Botan::RandomNumberGenerator + { + public: + std::string name() const override { return "NEWHOPE_RNG"; } + void clear() override { /* ignored */ } + + void randomize(byte out[], size_t len) override + { + if(m_first.size() == len) + { + if(len != 32) + throw Test_Error("NEWHOPE_RNG called in unexpected way, bad test?"); + + Botan::copy_mem(out, m_first.data(), m_first.size()); + return; + } + + /* + * This slavishly emulates the behavior of the reference + * implementations RNG, in order to ensure that from the same + * random seed we compute the exact same result. + */ + Botan::clear_mem(out, len); + m_chacha.cipher1(out, len); + + m_calls += 1; + + byte nonce[8] = { 0 }; + + if(m_calls < 3) + { + nonce[0] = m_calls; + } + else + { + nonce[7] = m_calls; + } + + m_chacha.set_iv(nonce, 8); + } + + bool is_seeded() const override { return true; } + + void add_entropy(const byte[], size_t) override { /* ignored */ } + + NEWHOPE_RNG(const std::vector<uint8_t>& seed) + { + if(seed.size() != 64 && seed.size() != 32) + { + throw Test_Error("Invalid NEWHOPE RNG seed"); + } + + if(seed.size() == 64) + { + m_first.assign(seed.begin(), seed.begin() + 32); + m_chacha.set_key(seed.data() + 32, 32); + } + else + { + m_chacha.set_key(seed.data(), 32); + } + } + + private: + Botan::ChaCha m_chacha; + std::vector<uint8_t> m_first; + byte m_calls = 0; + }; + +class NEWHOPE_Tests : public Text_Based_Test + { + public: + NEWHOPE_Tests() : Text_Based_Test("pubkey/newhope.vec", {"DRBG_SeedA", "H_OutputA", "DRBG_SeedB", "H_OutputB", "SharedKey"}) {} + + Test::Result run_one_test(const std::string&, const VarMap& vars) override + { + Test::Result result("NEWHOPE"); + + const std::vector<uint8_t> h_output_a = get_req_bin(vars, "H_OutputA"); + const std::vector<uint8_t> h_output_b = get_req_bin(vars, "H_OutputB"); + const std::vector<uint8_t> shared_key = get_req_bin(vars, "SharedKey"); + + NEWHOPE_RNG drbg_a(get_req_bin(vars, "DRBG_SeedA")); + NEWHOPE_RNG drbg_b(get_req_bin(vars, "DRBG_SeedB")); + + std::vector<uint8_t> send_a(NEWHOPE_SENDABYTES); + Botan::newhope_poly a_sk; + Botan::newhope_keygen(send_a.data(), &a_sk, drbg_a); + + std::vector<uint8_t> h_send_a(32); + Botan::newhope_hash(h_send_a.data(), send_a.data(), send_a.size()); + + result.test_eq("Hash Output A", h_send_a, h_output_a); + + std::vector<uint8_t> sharedkey_b(32); + std::vector<uint8_t> send_b(NEWHOPE_SENDBBYTES); + Botan::newhope_sharedb(sharedkey_b.data(), send_b.data(), send_a.data(), drbg_b); + result.test_eq("Key B", sharedkey_b, shared_key); + + std::vector<uint8_t> h_send_b(32); + Botan::newhope_hash(h_send_b.data(), send_b.data(), send_b.size()); + result.test_eq("Hash Output B", h_send_b, h_output_b); + + std::vector<uint8_t> sharedkey_a(32); + newhope_shareda(sharedkey_a.data(), &a_sk, send_b.data()); + result.test_eq("Key A", sharedkey_a, shared_key); + + return result; + } + }; + +BOTAN_REGISTER_TEST("newhope", NEWHOPE_Tests); + +#endif + +} |