aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2013-12-10 03:12:21 +0000
committerlloyd <[email protected]>2013-12-10 03:12:21 +0000
commit4874b0727843bba925bcd3b5c0659c5f1cb059d9 (patch)
tree0e946dde633162201396adb26eea165e74a6d779
parentc6ad94933ec0d718414ba41b3c289b872c04017f (diff)
Add Threefish-512
-rw-r--r--checks/bench.h2
-rw-r--r--checks/transform.cpp83
-rw-r--r--checks/transform.vec12
-rw-r--r--checks/validate.cpp1
-rw-r--r--checks/validate.h1
-rw-r--r--src/benchmark/benchmark.cpp4
-rw-r--r--src/benchmark/benchmark.h3
-rw-r--r--src/block/threefish/info.txt1
-rw-r--r--src/block/threefish/threefish.cpp160
-rw-r--r--src/block/threefish/threefish.h52
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