diff options
author | lloyd <[email protected]> | 2013-12-10 03:12:21 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2013-12-10 03:12:21 +0000 |
commit | 4874b0727843bba925bcd3b5c0659c5f1cb059d9 (patch) | |
tree | 0e946dde633162201396adb26eea165e74a6d779 | |
parent | c6ad94933ec0d718414ba41b3c289b872c04017f (diff) |
Add Threefish-512
-rw-r--r-- | checks/bench.h | 2 | ||||
-rw-r--r-- | checks/transform.cpp | 83 | ||||
-rw-r--r-- | checks/transform.vec | 12 | ||||
-rw-r--r-- | checks/validate.cpp | 1 | ||||
-rw-r--r-- | checks/validate.h | 1 | ||||
-rw-r--r-- | src/benchmark/benchmark.cpp | 4 | ||||
-rw-r--r-- | src/benchmark/benchmark.h | 3 | ||||
-rw-r--r-- | src/block/threefish/info.txt | 1 | ||||
-rw-r--r-- | src/block/threefish/threefish.cpp | 160 | ||||
-rw-r--r-- | src/block/threefish/threefish.h | 52 |
10 files changed, 315 insertions, 4 deletions
diff --git a/checks/bench.h b/checks/bench.h index b423a2215..3840bc112 100644 --- a/checks/bench.h +++ b/checks/bench.h @@ -17,4 +17,6 @@ bool bench_algo(const std::string& algo_name, void bench_pk(Botan::RandomNumberGenerator&, const std::string&, double seconds); +void time_transform(const std::string& algo); + #endif diff --git a/checks/transform.cpp b/checks/transform.cpp new file mode 100644 index 000000000..292bcf467 --- /dev/null +++ b/checks/transform.cpp @@ -0,0 +1,83 @@ +#include "validate.h" +#include "bench.h" + +#include <botan/libstate.h> +#include <botan/botan.h> +#include <botan/threefish.h> +#include <botan/benchmark.h> +#include <botan/hex.h> +#include <iostream> +#include <fstream> + +using namespace Botan; + +namespace { + +Transformation* get_transform(const std::string& algo) + { + if(algo == "Threefish-512") + return new Threefish_512; + + throw std::runtime_error("Unknown transform " + algo); + } + +secure_vector<byte> transform_test(const std::string& algo, + const secure_vector<byte>& nonce, + const secure_vector<byte>& key, + const secure_vector<byte>& in) + { + std::unique_ptr<Transformation> transform(get_transform(algo)); + + transform->set_key(key); + transform->start_vec(nonce); + + secure_vector<byte> out = in; + transform->update(out, 0); + + return out; + } + +} + +void test_transform() + { + std::ifstream vec("checks/transform.vec"); + + run_tests(vec, "Transform", "Output", true, + [](std::map<std::string, std::string> m) + { + return hex_encode(transform_test(m["Transform"], + hex_decode_locked(m["Nonce"]), + hex_decode_locked(m["Key"]), + hex_decode_locked(m["Input"]))); + }); + + time_transform("Threefish-512"); + } + +void time_transform(const std::string& algo) + { + std::unique_ptr<Transformation> tf(get_transform(algo)); + + AutoSeeded_RNG rng; + + tf->set_key(rng.random_vec(tf->maximum_keylength())); + tf->start_vec(rng.random_vec(tf->default_nonce_size())); + + for(size_t mult : { 1, 2, 4, 8, 16, 128, 1024 }) + { + const size_t buf_size = mult*tf->update_granularity(); + + secure_vector<byte> buffer(buf_size); + + double res = time_op(std::chrono::seconds(1), + [&tf,&buffer,buf_size]{ + tf->update(buffer); + buffer.resize(buf_size); + }); + + const u64bit Mbytes = (res * buf_size) / 1024 / 1024; + + std::cout << Mbytes << " MiB / second in " << buf_size << " blocks\n"; + } + } diff --git a/checks/transform.vec b/checks/transform.vec new file mode 100644 index 000000000..8f8a155e0 --- /dev/null +++ b/checks/transform.vec @@ -0,0 +1,12 @@ + +Transform = Threefish-512 +Input = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Key = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +Nonce = 00000000000000000000000000000000 +Output = B1A2BBC6EF6025BC40EB3822161F36E375D1BB0AEE3186FBD19E47C5D479947B7BC2F8586E35F0CFF7E7F03084B0B7B1F1AB3961A580A3E97EB41EA14A6D7BBE + +Transform = Threefish-512 +Input = FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0 +Nonce = 000102030405060708090A0B0C0D0E0F +Key = 101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F +Output = E304439626D45A2CB401CAD8D636249A6338330EB06D45DD8B36B90E97254779272A0A8D99463504784420EA18C9A725AF11DFFEA10162348927673D5C1CAF3D diff --git a/checks/validate.cpp b/checks/validate.cpp index 48932f0e4..866f414eb 100644 --- a/checks/validate.cpp +++ b/checks/validate.cpp @@ -418,6 +418,7 @@ u32bit do_validation_tests(const std::string& filename, if(should_pass) { + test_transform(); test_ocb(); test_hkdf(); test_pbkdf(); diff --git a/checks/validate.h b/checks/validate.h index 48830619b..bb4114c3f 100644 --- a/checks/validate.h +++ b/checks/validate.h @@ -39,6 +39,7 @@ void test_hkdf(); void test_pbkdf(); void test_kdf(); void test_aead(); +void test_transform(); void run_tests_bb(std::istream& src, const std::string& name_key, diff --git a/src/benchmark/benchmark.cpp b/src/benchmark/benchmark.cpp index 83fd87d1b..396670168 100644 --- a/src/benchmark/benchmark.cpp +++ b/src/benchmark/benchmark.cpp @@ -18,8 +18,6 @@ namespace Botan { -namespace { - double time_op(std::chrono::nanoseconds runtime, std::function<void ()> op) { std::chrono::nanoseconds time_used(0); @@ -41,8 +39,6 @@ double time_op(std::chrono::nanoseconds runtime, std::function<void ()> op) return reps / seconds_used; // ie, return ops per second } -} - std::map<std::string, double> time_algorithm_ops(const std::string& name, Algorithm_Factory& af, diff --git a/src/benchmark/benchmark.h b/src/benchmark/benchmark.h index 93224dd2e..40784a767 100644 --- a/src/benchmark/benchmark.h +++ b/src/benchmark/benchmark.h @@ -50,6 +50,9 @@ BOTAN_DLL algorithm_benchmark(const std::string& name, std::chrono::milliseconds milliseconds, size_t buf_size); +double BOTAN_DLL +time_op(std::chrono::nanoseconds runtime, std::function<void ()> op); + } #endif diff --git a/src/block/threefish/info.txt b/src/block/threefish/info.txt new file mode 100644 index 000000000..91fc7bfb1 --- /dev/null +++ b/src/block/threefish/info.txt @@ -0,0 +1 @@ +define THREEFISH 20131209 diff --git a/src/block/threefish/threefish.cpp b/src/block/threefish/threefish.cpp new file mode 100644 index 000000000..5877235ab --- /dev/null +++ b/src/block/threefish/threefish.cpp @@ -0,0 +1,160 @@ +/* +* Threefish +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/threefish.h> +#include <botan/rotate.h> +#include <botan/loadstor.h> + +namespace Botan { + +secure_vector<byte> Threefish_512::start(const byte tweak[], size_t tweak_len) + { + if(!valid_nonce_length(tweak_len)) + throw Invalid_IV_Length(name(), tweak_len); + + m_T.resize(3); + + m_T[0] = load_le<u64bit>(tweak, 0); + m_T[1] = load_le<u64bit>(tweak, 1); + m_T[2] = m_T[0] ^ m_T[1]; + + return secure_vector<byte>(); + } + +void Threefish_512::update(secure_vector<byte>& blocks, size_t offset) + { + byte* buf = &blocks[offset]; + size_t sz = blocks.size() - offset; + + BOTAN_ASSERT(sz % update_granularity() == 0, "Block sized input"); + + BOTAN_ASSERT(m_T.size() == 3, "Tweak was set"); + + while(sz) + { +#define THREEFISH_ROUND(I1,I2,I3,I4,I5,I6,I7,I8,ROT1,ROT2,ROT3,ROT4) \ + do { \ + X##I1 += X##I2; X##I2 = rotate_left(X##I2, ROT1) ^ X##I1; \ + X##I3 += X##I4; X##I4 = rotate_left(X##I4, ROT2) ^ X##I3; \ + X##I5 += X##I6; X##I6 = rotate_left(X##I6, ROT3) ^ X##I5; \ + X##I7 += X##I8; X##I8 = rotate_left(X##I8, ROT4) ^ X##I7; \ + } while(0); + +#define THREEFISH_INJECT_KEY(r) \ + do { \ + X0 += m_K[(r ) % 9]; \ + X1 += m_K[(r+1) % 9]; \ + X2 += m_K[(r+2) % 9]; \ + X3 += m_K[(r+3) % 9]; \ + X4 += m_K[(r+4) % 9]; \ + X5 += m_K[(r+5) % 9] + m_T[(r ) % 3]; \ + X6 += m_K[(r+6) % 9] + m_T[(r+1) % 3]; \ + X7 += m_K[(r+7) % 9] + (r); \ + } while(0); + + u64bit X0 = load_le<u64bit>(buf, 0); + u64bit X1 = load_le<u64bit>(buf, 1); + u64bit X2 = load_le<u64bit>(buf, 2); + u64bit X3 = load_le<u64bit>(buf, 3); + u64bit X4 = load_le<u64bit>(buf, 4); + u64bit X5 = load_le<u64bit>(buf, 5); + u64bit X6 = load_le<u64bit>(buf, 6); + u64bit X7 = load_le<u64bit>(buf, 7); + + THREEFISH_INJECT_KEY(0); + +#define THREEFISH_8_ROUNDS(R1,R2) \ + do { \ + THREEFISH_ROUND(0,1,2,3,4,5,6,7, 46,36,19,37); \ + THREEFISH_ROUND(2,1,4,7,6,5,0,3, 33,27,14,42); \ + THREEFISH_ROUND(4,1,6,3,0,5,2,7, 17,49,36,39); \ + THREEFISH_ROUND(6,1,0,7,2,5,4,3, 44, 9,54,56); \ + \ + THREEFISH_INJECT_KEY(R1); \ + \ + THREEFISH_ROUND(0,1,2,3,4,5,6,7, 39,30,34,24); \ + THREEFISH_ROUND(2,1,4,7,6,5,0,3, 13,50,10,17); \ + THREEFISH_ROUND(4,1,6,3,0,5,2,7, 25,29,39,43); \ + THREEFISH_ROUND(6,1,0,7,2,5,4,3, 8,35,56,22); \ + \ + THREEFISH_INJECT_KEY(R2); \ + } while(0); + + THREEFISH_8_ROUNDS(1,2); + THREEFISH_8_ROUNDS(3,4); + THREEFISH_8_ROUNDS(5,6); + THREEFISH_8_ROUNDS(7,8); + THREEFISH_8_ROUNDS(9,10); + THREEFISH_8_ROUNDS(11,12); + THREEFISH_8_ROUNDS(13,14); + THREEFISH_8_ROUNDS(15,16); + THREEFISH_8_ROUNDS(17,18); + + store_le(buf, X0, X1, X2, X3, X4, X5, X6, X7); + + buf += 64; + sz -= 64; + } + } + +Key_Length_Specification Threefish_512::key_spec() const + { + return Key_Length_Specification(64); + } + +void Threefish_512::key_schedule(const byte key[], size_t) + { + // todo: define key schedule for smaller keys + m_K.resize(9); + + for(size_t i = 0; i != 8; ++i) + m_K[i] = load_le<u64bit>(key, i); + + m_K[8] = m_K[0] ^ m_K[1] ^ m_K[2] ^ m_K[3] ^ + m_K[4] ^ m_K[5] ^ m_K[6] ^ m_K[7] ^ 0x1BD11BDAA9FC1A22; + } + +void Threefish_512::finish(secure_vector<byte>& blocks, size_t offset) + { + update(blocks, offset); + m_T.clear(); + } + +size_t Threefish_512::output_length(size_t input_length) const + { + if(input_length % update_granularity() == 0) + throw std::invalid_argument("Threefish - invalid input length " + std::to_string(input_length)); + + return input_length; + } + +size_t Threefish_512::update_granularity() const + { + return 64; // single block + } + +size_t Threefish_512::minimum_final_size() const + { + return 0; + } + +size_t Threefish_512::default_nonce_size() const + { + return 16; + } + +bool Threefish_512::valid_nonce_length(size_t nonce_len) const + { + return default_nonce_size() == nonce_len; + } + +void Threefish_512::clear() + { + zeroise(m_K); + } + +} diff --git a/src/block/threefish/threefish.h b/src/block/threefish/threefish.h new file mode 100644 index 000000000..8fa758b12 --- /dev/null +++ b/src/block/threefish/threefish.h @@ -0,0 +1,52 @@ +/* +* Threefish +* (C) 2013 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_THREEFISH_H__ +#define BOTAN_THREEFISH_H__ + +#include <botan/transform.h> + +namespace Botan { + +/** +* Threefish-512 +*/ +class BOTAN_DLL Threefish_512 : public Transformation + { + public: + secure_vector<byte> start(const byte tweak[], size_t tweak_len) override; + + void update(secure_vector<byte>& blocks, size_t offset) override; + + void finish(secure_vector<byte>& final_block, size_t offset) override; + + size_t output_length(size_t input_length) const override; + + size_t update_granularity() const override; + + size_t minimum_final_size() const override; + + size_t default_nonce_size() const override; + + bool valid_nonce_length(size_t nonce_len) const override; + + Key_Length_Specification key_spec() const override; + + std::string name() const { return "Threefish-512"; } + + void clear(); + + private: + void key_schedule(const byte key[], size_t key_len) override; + + secure_vector<u64bit> m_T; + secure_vector<u64bit> m_K; + }; + +} + +#endif |