Merge branch 'crypto'
This commit is contained in:
commit
08536765b6
@ -53,6 +53,8 @@ UTIL_FILES = \
|
||||
coord/store.hpp \
|
||||
crypto/arc4.cpp \
|
||||
crypto/arc4.hpp \
|
||||
crypto/ice.cpp \
|
||||
crypto/ice.hpp \
|
||||
crypto/tea.cpp \
|
||||
crypto/tea.hpp \
|
||||
crypto/xtea.cpp \
|
||||
@ -126,6 +128,8 @@ UTIL_FILES = \
|
||||
hash/hmac.hpp \
|
||||
hash/hotp.cpp \
|
||||
hash/hotp.hpp \
|
||||
hash/keccak.cpp \
|
||||
hash/keccak.hpp \
|
||||
hash/md2.cpp \
|
||||
hash/md2.hpp \
|
||||
hash/md4.cpp \
|
||||
@ -393,6 +397,7 @@ TEST_BIN = \
|
||||
test/colour \
|
||||
test/coord \
|
||||
test/crypto/arc4 \
|
||||
test/crypto/ice \
|
||||
test/crypto/tea \
|
||||
test/crypto/xtea \
|
||||
test/crypto/xxtea \
|
||||
@ -405,6 +410,7 @@ TEST_BIN = \
|
||||
test/geom/ray \
|
||||
test/hash/murmur \
|
||||
test/hash/fasthash \
|
||||
test/hash/keccak \
|
||||
test/hmac \
|
||||
test/hotp \
|
||||
test/hton \
|
||||
|
2
README
2
README
@ -1 +1,3 @@
|
||||
A simple cross-platform C++ utility library.
|
||||
|
||||
For the love of God, do not use the crypto routines. I am not a cryptographer or a security specialist. You have been warned.
|
||||
|
16
bitwise.hpp
16
bitwise.hpp
@ -31,25 +31,21 @@ const uint8_t BITMASK_7BITS = 0x7F;
|
||||
const uint8_t BITMASK_8BITS = 0xFF;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#define MODT(x) ((x) % (sizeof (T) * 8))
|
||||
|
||||
template <typename T>
|
||||
constexpr T
|
||||
rotatel (const T &value, size_t magnitude) {
|
||||
return (value << MODT (magnitude)) |
|
||||
(value >> sizeof (value) * 8 - MODT (magnitude));
|
||||
rotatel [[gnu::pure]] (const T value, size_t magnitude)
|
||||
{
|
||||
return (value << magnitude) | (value >> sizeof (value) * 8 - magnitude);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
constexpr T
|
||||
rotater (const T &value, size_t magnitude) {
|
||||
return (value >> MODT (magnitude)) |
|
||||
(value << sizeof (value) * 8 - MODT (magnitude));
|
||||
rotater [[gnu::pure]] (const T value, size_t magnitude)
|
||||
{
|
||||
return (value >> magnitude) | (value << sizeof (value) * 8 - magnitude);
|
||||
}
|
||||
|
||||
#undef MODT
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// TODO: make constexpr for C++14
|
||||
|
437
crypto/ice.cpp
Normal file
437
crypto/ice.cpp
Normal file
@ -0,0 +1,437 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
// Derived from Mathew Kwan's 1996 C++ public domain implementation of ICE:
|
||||
// http://www.darkside.com.au/ice/
|
||||
//
|
||||
// M. Kwan, The Design of the ICE Encryption Algorithm, proceedings of Fast
|
||||
// Software Encryption - Fourth International Workshop, Haifa, Israel,
|
||||
// Springer-Verlag, pp. 69-82, 1997
|
||||
|
||||
#include "./ice.hpp"
|
||||
|
||||
#include "endian.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
* C++ implementation of the ICE encryption algorithm.
|
||||
*
|
||||
* Written by Matthew Kwan - July 1996
|
||||
*/
|
||||
|
||||
|
||||
/* The S-boxes */
|
||||
static uint32_t ice_sbox[4][1024];
|
||||
static bool ice_sboxes_initialised = false;
|
||||
|
||||
|
||||
/* Modulo values for the S-boxes */
|
||||
static
|
||||
constexpr
|
||||
uint_fast16_t
|
||||
ice_smod[4][4] = {
|
||||
{333, 313, 505, 369},
|
||||
{379, 375, 319, 391},
|
||||
{361, 445, 451, 397},
|
||||
{397, 425, 395, 505}
|
||||
};
|
||||
|
||||
|
||||
/* XOR values for the S-boxes */
|
||||
constexpr
|
||||
uint8_t
|
||||
ice_sxor[4][4] = {
|
||||
{0x83, 0x85, 0x9b, 0xcd},
|
||||
{0xcc, 0xa7, 0xad, 0x41},
|
||||
{0x4b, 0x2e, 0xd4, 0x33},
|
||||
{0xea, 0xcb, 0x2e, 0x04}
|
||||
};
|
||||
|
||||
|
||||
/* Permutation values for the P-box */
|
||||
constexpr
|
||||
uint32_t
|
||||
ice_pbox[32] = {
|
||||
0x00000001, 0x00000080, 0x00000400, 0x00002000,
|
||||
0x00080000, 0x00200000, 0x01000000, 0x40000000,
|
||||
0x00000008, 0x00000020, 0x00000100, 0x00004000,
|
||||
0x00010000, 0x00800000, 0x04000000, 0x20000000,
|
||||
0x00000004, 0x00000010, 0x00000200, 0x00008000,
|
||||
0x00020000, 0x00400000, 0x08000000, 0x10000000,
|
||||
0x00000002, 0x00000040, 0x00000800, 0x00001000,
|
||||
0x00040000, 0x00100000, 0x02000000, 0x80000000
|
||||
};
|
||||
|
||||
|
||||
/* The key rotation schedule */
|
||||
constexpr
|
||||
std::array<uint_fast8_t,8>
|
||||
ice_keyrot[2] = {
|
||||
{ 0, 1, 2, 3, 2, 1, 3, 0, },
|
||||
{ 1, 3, 2, 0, 3, 1, 0, 2, },
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* 8-bit Galois Field multiplication of a by b, modulo m.
|
||||
* Just like arithmetic multiplication, except that additions and
|
||||
* subtractions are replaced by XOR.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
static
|
||||
T
|
||||
gf_mult (T a, T b, const T m)
|
||||
{
|
||||
T res = 0;
|
||||
|
||||
while (b) {
|
||||
if (b & 1u)
|
||||
res ^= a;
|
||||
|
||||
a <<= 1u;
|
||||
b >>= 1u;
|
||||
|
||||
if (a >= 256)
|
||||
a ^= m;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Galois Field exponentiation.
|
||||
* Raise the base to the power of 7, modulo m.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
static
|
||||
T
|
||||
gf_exp7 (const T b,
|
||||
const T m)
|
||||
{
|
||||
if (b == 0)
|
||||
return 0;
|
||||
|
||||
T x;
|
||||
|
||||
x = gf_mult (b, b, m);
|
||||
x = gf_mult (b, x, m);
|
||||
x = gf_mult (x, x, m);
|
||||
|
||||
return gf_mult (b, x, m);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Carry out the ICE 32-bit P-box permutation.
|
||||
*/
|
||||
|
||||
static
|
||||
uint32_t
|
||||
ice_perm32 (uint32_t x)
|
||||
{
|
||||
uint32_t res = 0;
|
||||
const uint32_t *pbox = ice_pbox;
|
||||
|
||||
while (x) {
|
||||
if (x & 1)
|
||||
res |= *pbox;
|
||||
pbox++;
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialise the ICE S-boxes.
|
||||
* This only has to be done once.
|
||||
*/
|
||||
static
|
||||
void
|
||||
ice_sboxes_init (void)
|
||||
{
|
||||
for (unsigned i = 0; i < 1024; i++) {
|
||||
const uint_fast16_t col = (i >> 1) & 0xff;
|
||||
const uint_fast16_t row = (i & 0x1) | ((i & 0x200) >> 8);
|
||||
|
||||
for (unsigned j = 0; j < 4; ++j) {
|
||||
const auto p = gf_exp7 (
|
||||
col ^ ice_sxor[j][row],
|
||||
ice_smod[j][row]
|
||||
) << (24 - j * 8);
|
||||
|
||||
ice_sbox[j][i] = ice_perm32 (p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a new ICE key.
|
||||
*/
|
||||
|
||||
ice::ice (unsigned n,
|
||||
const uint64_t *key_first,
|
||||
const uint64_t *key_last)
|
||||
{
|
||||
if (!ice_sboxes_initialised) {
|
||||
ice_sboxes_init ();
|
||||
ice_sboxes_initialised = true;
|
||||
}
|
||||
|
||||
if (n < 1) {
|
||||
m_size = 1;
|
||||
m_rounds = 8;
|
||||
} else {
|
||||
m_size = n;
|
||||
m_rounds = n * 16;
|
||||
}
|
||||
|
||||
m_schedule.resize (m_rounds);
|
||||
|
||||
set (key_first, key_last);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Destroy an ICE key.
|
||||
*/
|
||||
|
||||
ice::~ice ()
|
||||
{
|
||||
for (auto &s: m_schedule)
|
||||
std::fill (std::begin (s), std::end (s), 0);
|
||||
|
||||
m_rounds = m_size = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The single round ICE f function.
|
||||
*/
|
||||
|
||||
static
|
||||
uint32_t
|
||||
ice_f (uint32_t p, const ice::subkey_t &sk)
|
||||
{
|
||||
uint_fast64_t tl, tr; /* Expanded 40-bit values */
|
||||
uint_fast64_t al, ar; /* Salted expanded 40-bit values */
|
||||
|
||||
/* Left half expansion */
|
||||
tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00);
|
||||
|
||||
/* Right half expansion */
|
||||
tr = (p & 0x3ff) | ((p << 2) & 0xffc00);
|
||||
|
||||
/* Perform the salt permutation */
|
||||
// al = (tr & sk->val[2]) | (tl & ~sk->val[2]);
|
||||
// ar = (tl & sk->val[2]) | (tr & ~sk->val[2]);
|
||||
al = sk[2] & (tl ^ tr);
|
||||
ar = al ^ tr;
|
||||
al ^= tl;
|
||||
|
||||
al ^= sk[0]; /* XOR with the subkey */
|
||||
ar ^= sk[1];
|
||||
|
||||
/* S-box lookup and permutation */
|
||||
return (
|
||||
ice_sbox[0][al >> 10] | ice_sbox[1][al & 0x3ff]
|
||||
| ice_sbox[2][ar >> 10] | ice_sbox[3][ar & 0x3ff]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encrypt a block of 8 bytes of data with the given ICE key.
|
||||
*/
|
||||
uint64_t
|
||||
ice::encrypt (const uint64_t _ptext) const
|
||||
{
|
||||
union {
|
||||
uint64_t pword;
|
||||
uint8_t pbytes[8];
|
||||
};
|
||||
|
||||
pword = hton (_ptext);
|
||||
|
||||
uint32_t l, r;
|
||||
|
||||
l = (((uint32_t) pbytes[0]) << 24u)
|
||||
| (((uint32_t) pbytes[1]) << 16u)
|
||||
| (((uint32_t) pbytes[2]) << 8u)
|
||||
| pbytes[3];
|
||||
r = (((uint32_t) pbytes[4]) << 24u)
|
||||
| (((uint32_t) pbytes[5]) << 16u)
|
||||
| (((uint32_t) pbytes[6]) << 8u)
|
||||
| pbytes[7];
|
||||
|
||||
for (unsigned i = 0; i < m_rounds; i += 2) {
|
||||
l ^= ice_f (r, m_schedule[i]);
|
||||
r ^= ice_f (l, m_schedule[i + 1]);
|
||||
}
|
||||
|
||||
union {
|
||||
uint64_t cword;
|
||||
uint8_t cbytes[8];
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
cbytes[3 - i] = r & 0xff;
|
||||
cbytes[7 - i] = l & 0xff;
|
||||
|
||||
r >>= 8u;
|
||||
l >>= 8u;
|
||||
}
|
||||
|
||||
return hton (cword);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decrypt a block of 8 bytes of data with the given ICE key.
|
||||
*/
|
||||
|
||||
uint64_t
|
||||
ice::decrypt (const uint64_t _ctext) const
|
||||
{
|
||||
union {
|
||||
uint64_t cword;
|
||||
uint8_t cbytes[8];
|
||||
};
|
||||
|
||||
cword = hton (_ctext);
|
||||
|
||||
uint32_t l, r;
|
||||
|
||||
l = (((uint32_t) cbytes[0]) << 24u)
|
||||
| (((uint32_t) cbytes[1]) << 16u)
|
||||
| (((uint32_t) cbytes[2]) << 8u)
|
||||
| cbytes[3];
|
||||
r = (((uint32_t) cbytes[4]) << 24u)
|
||||
| (((uint32_t) cbytes[5]) << 16u)
|
||||
| (((uint32_t) cbytes[6]) << 8u)
|
||||
| cbytes[7];
|
||||
|
||||
for (int i = m_rounds - 1; i > 0; i -= 2) {
|
||||
l ^= ice_f (r, m_schedule[i]);
|
||||
r ^= ice_f (l, m_schedule[i - 1]);
|
||||
}
|
||||
|
||||
union {
|
||||
uint64_t pword;
|
||||
uint8_t pbytes[8];
|
||||
};
|
||||
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
pbytes[3 - i] = r & 0xff;
|
||||
pbytes[7 - i] = l & 0xff;
|
||||
|
||||
r >>= 8;
|
||||
l >>= 8;
|
||||
}
|
||||
|
||||
return hton (pword);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set 8 rounds [n, n+7] of the key schedule of an ICE key.
|
||||
*/
|
||||
|
||||
void
|
||||
ice::scheduleBuild (std::array<uint16_t,4> &kb,
|
||||
int n,
|
||||
const std::array<uint_fast8_t,8> &keyrot)
|
||||
{
|
||||
for (unsigned i = 0; i < 8; i++) {
|
||||
int kr = keyrot[i];
|
||||
subkey_t &isk = m_schedule[n + i];
|
||||
|
||||
std::fill (std::begin (isk), std::end (isk), 0);
|
||||
|
||||
for (unsigned j = 0; j < 15; j++) {
|
||||
uint32_t &curr_sk = isk[j % 3];
|
||||
|
||||
for (unsigned k = 0; k < 4; k++) {
|
||||
auto &curr_kb = kb[(kr + k) & 3];
|
||||
unsigned bit = curr_kb & 1;
|
||||
|
||||
curr_sk = (curr_sk << 1) | bit;
|
||||
curr_kb = (curr_kb >> 1) | ((bit ^ 1) << 15);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the key schedule of an ICE key.
|
||||
*/
|
||||
|
||||
void
|
||||
ice::set (const uint64_t *_key_first, const uint64_t *_key_last)
|
||||
{
|
||||
auto key = reinterpret_cast<const uint8_t*> (_key_first);
|
||||
|
||||
if (m_rounds == 8) {
|
||||
std::array<uint16_t,4> kb;
|
||||
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
kb[3 - i] = (key[i * 2] << 8) | key[i * 2 + 1];
|
||||
|
||||
scheduleBuild (kb, 0, ice_keyrot[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < m_size; i++) {
|
||||
std::array<uint16_t,4> kb;
|
||||
|
||||
for (unsigned j = 0; j < 4; j++)
|
||||
kb[3 - j] = (key[i * 8 + j * 2] << 8) | key[i * 8 + j * 2 + 1];
|
||||
|
||||
scheduleBuild (kb, i * 8, ice_keyrot[0]);
|
||||
scheduleBuild (kb, m_rounds - 8 - i * 8, ice_keyrot[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the key size, in bytes.
|
||||
*/
|
||||
|
||||
unsigned
|
||||
ice::key_size () const
|
||||
{
|
||||
return (m_size * 8);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Return the block size, in bytes.
|
||||
*/
|
||||
|
||||
unsigned
|
||||
ice::block_size () const
|
||||
{
|
||||
return (8);
|
||||
}
|
64
crypto/ice.hpp
Normal file
64
crypto/ice.hpp
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __CRYPTO_ICE_HPP
|
||||
#define __CRYPTO_ICE_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
// An implementation of the ICE symmetric-key block cipher
|
||||
//
|
||||
// we make a token attempt to zero our buffers, but we can't guarantee this
|
||||
// will take place (given compiler optimisations). further security is
|
||||
// outside the scope of this class.
|
||||
class ice {
|
||||
public:
|
||||
ice (unsigned n, uint64_t key);
|
||||
|
||||
ice (unsigned n,
|
||||
const uint64_t *key_first,
|
||||
const uint64_t *key_last);
|
||||
~ice ();
|
||||
|
||||
void
|
||||
set (const uint64_t *key_first, const uint64_t *key_last);
|
||||
|
||||
uint64_t encrypt (uint64_t plaintext) const;
|
||||
uint64_t decrypt (uint64_t ciphertext) const;
|
||||
|
||||
unsigned key_size () const;
|
||||
unsigned block_size () const;
|
||||
|
||||
using subkey_t = std::array<uint32_t,3>;
|
||||
|
||||
private:
|
||||
void
|
||||
scheduleBuild (std::array<uint16_t,4> &k,
|
||||
int n,
|
||||
const std::array<uint_fast8_t,8> &keyrot);
|
||||
|
||||
unsigned m_size;
|
||||
unsigned m_rounds;
|
||||
|
||||
std::vector<subkey_t> m_schedule;
|
||||
};
|
||||
|
||||
struct ice_error : public std::runtime_error { using runtime_error::runtime_error; };
|
||||
struct level_error : public ice_error { using ice_error::ice_error; };
|
||||
|
||||
#endif
|
@ -20,7 +20,7 @@
|
||||
#include "./maths.hpp"
|
||||
#include "./stream.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
using util::extent;
|
||||
|
@ -24,6 +24,8 @@
|
||||
|
||||
#include <random>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
namespace util { namespace geom {
|
||||
template <size_t S, typename T, typename G>
|
||||
struct sampler<S,T,AABB,G> {
|
||||
|
485
hash/keccak.cpp
Normal file
485
hash/keccak.cpp
Normal file
@ -0,0 +1,485 @@
|
||||
#include "./keccak.hpp"
|
||||
|
||||
#include "../endian.hpp"
|
||||
#include "../maths.hpp"
|
||||
#include "../bitwise.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
|
||||
#if 0
|
||||
#define FOR(i,n) for(i=0; i<n; ++i)
|
||||
|
||||
int LFSR86540(u8 *R) { (*R)=((*R)<<1)^(((*R)&0x80)?0x71:0); return ((*R)&2)>>1; }
|
||||
#define ROL(a,o) ((((u64)a)<<o)^(((u64)a)>>(64-o)))
|
||||
static u64 load64(const u8 *x) { ui i; u64 u=0; FOR(i,8) { u<<=8; u|=x[7-i]; } return u; }
|
||||
static void store64(u8 *x, u64 u) { ui i; FOR(i,8) { x[i]=u; u>>=8; } }
|
||||
static void xor64(u8 *x, u64 u) { ui i; FOR(i,8) { x[i]^=u; u>>=8; } }
|
||||
#define rL(x,y) load64((u8*)s+8*(x+5*y))
|
||||
#define wL(x,y,l) store64((u8*)s+8*(x+5*y),l)
|
||||
#define XL(x,y,l) xor64((u8*)s+8*(x+5*y),l)
|
||||
void KeccakF1600(void *s)
|
||||
{
|
||||
ui r,x,y,i,j,Y; u8 R=0x01; u64 C[5],D;
|
||||
for(i=0; i<24; i++) {
|
||||
/*θ*/ FOR(x,5) C[x]=rL(x,0)^rL(x,1)^rL(x,2)^rL(x,3)^rL(x,4); FOR(x,5) { D=C[(x+4)%5]^ROL(C[(x+1)%5],1); FOR(y,5) XL(x,y,D); }
|
||||
/*ρπ*/ x=1; y=r=0; D=rL(x,y); FOR(j,24) { r+=j+1; Y=(2*x+3*y)%5; x=y; y=Y; C[0]=rL(x,y); wL(x,y,ROL(D,r%64)); D=C[0]; }
|
||||
/*χ*/ FOR(y,5) { FOR(x,5) C[x]=rL(x,y); FOR(x,5) wL(x,y,C[x]^((~C[(x+1)%5])&C[(x+2)%5])); }
|
||||
/*ι*/ FOR(j,7) if (LFSR86540(&R)) XL(0,0,(u64)1<<((1<<j)-1));
|
||||
}
|
||||
}
|
||||
void Keccak(ui r, ui c, const u8 *in, u64 inLen, u8 sfx, u8 *out, u64 outLen)
|
||||
{
|
||||
/*initialize*/ u8 s[200]; ui R=r/8; ui i,b=0; FOR(i,200) s[i]=0;
|
||||
/*absorb*/ while(inLen>0) { b=(inLen<R)?inLen:R; FOR(i,b) s[i]^=in[i]; in+=b; inLen-=b; if (b==R) { KeccakF1600(s); b=0; } }
|
||||
/*pad*/ s[b]^=sfx; if((sfx&0x80)&&(b==(R-1))) KeccakF1600(s); s[R-1]^=0x80; KeccakF1600(s);
|
||||
/*squeeze*/ while(outLen>0) { b=(outLen<R)?outLen:R; FOR(i,b) out[i]=s[i]; out+=b; outLen-=b; if(outLen>0) KeccakF1600(s); }
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// derived from Keccak (KCP) readable-and-compact C implementation
|
||||
|
||||
/*
|
||||
Implementation by the Keccak, Keyak and Ketje Teams, namely, Guido Bertoni,
|
||||
Joan Daemen, Michaël Peeters, Gilles Van Assche and Ronny Van Keer, hereby
|
||||
denoted as "the implementer".
|
||||
|
||||
For more information, feedback or questions, please refer to our websites:
|
||||
http://keccak.noekeon.org/
|
||||
http://keyak.noekeon.org/
|
||||
http://ketje.noekeon.org/
|
||||
|
||||
To the extent possible under law, the implementer has waived all copyright
|
||||
and related or neighboring rights to the source code in this file.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
/*
|
||||
================================================================
|
||||
The purpose of this source file is to demonstrate a readable and compact
|
||||
implementation of all the Keccak instances approved in the FIPS 202 standard,
|
||||
including the hash functions and the extendable-output functions (XOFs).
|
||||
|
||||
We focused on clarity and on source-code compactness,
|
||||
rather than on the performance.
|
||||
|
||||
The advantages of this implementation are:
|
||||
+ The source code is compact, after removing the comments, that is. :-)
|
||||
+ There are no tables with arbitrary constants.
|
||||
+ For clarity, the comments link the operations to the specifications using
|
||||
the same notation as much as possible.
|
||||
+ There is no restriction in cryptographic features. In particular,
|
||||
the SHAKE128 and SHAKE256 XOFs can produce any output length.
|
||||
+ The code does not use much RAM, as all operations are done in place.
|
||||
|
||||
The drawbacks of this implementation are:
|
||||
- There is no message queue. The whole message must be ready in a buffer.
|
||||
- It is not optimized for peformance.
|
||||
|
||||
The implementation is even simpler on a little endian platform. Just define the
|
||||
LITTLE_ENDIAN symbol in that case.
|
||||
|
||||
For a more complete set of implementations, please refer to
|
||||
the Keccak Code Package at https://github.com/gvanas/KeccakCodePackage
|
||||
|
||||
For more information, please refer to:
|
||||
* [Keccak Reference] http://keccak.noekeon.org/Keccak-reference-3.0.pdf
|
||||
* [Keccak Specifications Summary] http://keccak.noekeon.org/specs_summary.html
|
||||
|
||||
This file uses UTF-8 encoding, as some comments use Greek letters.
|
||||
================================================================
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to compute the Keccak[r, c] sponge function over a given input.
|
||||
* @param rate The value of the rate r.
|
||||
* @param capacity The value of the capacity c.
|
||||
* @param input Pointer to the input message.
|
||||
* @param inputByteLen The number of input bytes provided in the input message.
|
||||
* @param delimitedSuffix Bits that will be automatically appended to the end
|
||||
* of the input message, as in domain separation.
|
||||
* This is a byte containing from 0 to 7 bits
|
||||
* These <i>n</i> bits must be in the least significant bit positions
|
||||
* and must be delimited with a bit 1 at position <i>n</i>
|
||||
* (counting from 0=LSB to 7=MSB) and followed by bits 0
|
||||
* from position <i>n</i>+1 to position 7.
|
||||
* Some examples:
|
||||
* - If no bits are to be appended, then @a delimitedSuffix must be 0x01.
|
||||
* - If the 2-bit sequence 0,1 is to be appended (as for SHA3-*), @a delimitedSuffix must be 0x06.
|
||||
* - If the 4-bit sequence 1,1,1,1 is to be appended (as for SHAKE*), @a delimitedSuffix must be 0x1F.
|
||||
* - If the 7-bit sequence 1,1,0,1,0,0,0 is to be absorbed, @a delimitedSuffix must be 0x8B.
|
||||
* @param output Pointer to the buffer where to store the output.
|
||||
* @param outputByteLen The number of output bytes desired.
|
||||
* @pre One must have r+c=1600 and the rate a multiple of 8 bits in this implementation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to compute SHAKE128 on the input message with any output length.
|
||||
*/
|
||||
void
|
||||
FIPS202_SHAKE128(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen)
|
||||
{
|
||||
keccak k (1344, 256, 0x1f);
|
||||
k.update (input, inputByteLen);
|
||||
k.digest (output, outputByteLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to compute SHAKE256 on the input message with any output length.
|
||||
*/
|
||||
void FIPS202_SHAKE256(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen)
|
||||
{
|
||||
keccak k (1088, 512, 0x1f);
|
||||
k.update (input, inputByteLen);
|
||||
k.digest (output, outputByteLen);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to compute SHA3-224 on the input message. The output length is fixed to 28 bytes.
|
||||
*/
|
||||
void FIPS202_SHA3_224(const uint8_t *input, size_t inputByteLen, uint8_t *output)
|
||||
{
|
||||
keccak k (1152, 448, 0x06);
|
||||
|
||||
for (unsigned int i = 0; i < inputByteLen; ++i)
|
||||
k.update (&input[i], 1);
|
||||
//k.update (input, inputByteLen);
|
||||
k.digest (output, 28);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to compute SHA3-256 on the input message. The output length is fixed to 32 bytes.
|
||||
*/
|
||||
void FIPS202_SHA3_256(const uint8_t *input, size_t inputByteLen, uint8_t *output)
|
||||
{
|
||||
keccak k (1088, 512, 0x06);
|
||||
k.update (input, inputByteLen);
|
||||
k.digest (output, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to compute SHA3-384 on the input message. The output length is fixed to 48 bytes.
|
||||
*/
|
||||
void FIPS202_SHA3_384(const uint8_t *input, size_t inputByteLen, uint8_t *output)
|
||||
{
|
||||
keccak k (832, 768, 0x06);
|
||||
k.update (input, inputByteLen);
|
||||
k.digest (output, 48);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to compute SHA3-512 on the input message. The output length is fixed to 64 bytes.
|
||||
*/
|
||||
void FIPS202_SHA3_512(const uint8_t *input, size_t inputByteLen, uint8_t *output)
|
||||
{
|
||||
keccak k (576, 1024, 0x06);
|
||||
k.update (input, inputByteLen);
|
||||
k.digest (output, 64);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
================================================================
|
||||
A readable and compact implementation of the Keccak-f[1600] permutation.
|
||||
================================================================
|
||||
*/
|
||||
|
||||
static constexpr
|
||||
size_t
|
||||
i (size_t x, size_t y)
|
||||
{
|
||||
return x + 5 * y;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function that computes the linear feedback shift register (LFSR) used to
|
||||
* define the round constants (see [Keccak Reference, Section 1.2]).
|
||||
*/
|
||||
class lfsr86540 {
|
||||
public:
|
||||
lfsr86540 ():
|
||||
value (0x1)
|
||||
{ ; }
|
||||
|
||||
|
||||
bool
|
||||
update (void)
|
||||
{
|
||||
bool result = value & 0x01;
|
||||
if (value & 0x80)
|
||||
// Primitive polynomial over GF(2): x^8+x^6+x^5+x^4+1
|
||||
value = (value << 1) ^ 0x71;
|
||||
else
|
||||
value <<= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
uint8_t value;
|
||||
};
|
||||
|
||||
|
||||
// θ step, see [Keccak Reference, Section 2.3.2]
|
||||
static void
|
||||
permute_theta (uint64_t m_words[5][5])
|
||||
{
|
||||
uint64_t C[5], D;
|
||||
|
||||
// Compute the parity of the columns
|
||||
for (unsigned x = 0; x < 5; ++x)
|
||||
C[x] = m_words[0][x] ^ m_words[1][x] ^ m_words[2][x] ^ m_words[3][x] ^ m_words[4][x];
|
||||
|
||||
for (unsigned x = 0; x < 5; ++x) {
|
||||
// Compute the θ effect for a given column
|
||||
D = C[(x+4)%5] ^ rotatel (C[(x+1)%5], 1);
|
||||
|
||||
// Add the θ effect to the whole column
|
||||
for (unsigned y = 0; y < 5; ++y)
|
||||
m_words[y][x] ^= D;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
permute_rho (uint64_t m_words[5][5])
|
||||
{
|
||||
m_words[0][1] = rotatel (m_words[0][1], 1);
|
||||
m_words[0][2] = rotatel (m_words[0][2], 62);
|
||||
m_words[0][3] = rotatel (m_words[0][3], 28);
|
||||
m_words[0][4] = rotatel (m_words[0][4], 27);
|
||||
m_words[1][0] = rotatel (m_words[1][0], 36);
|
||||
m_words[1][1] = rotatel (m_words[1][1], 44);
|
||||
m_words[1][2] = rotatel (m_words[1][2], 6);
|
||||
m_words[1][3] = rotatel (m_words[1][3], 55);
|
||||
m_words[1][4] = rotatel (m_words[1][4], 20);
|
||||
m_words[2][0] = rotatel (m_words[2][0], 3);
|
||||
m_words[2][1] = rotatel (m_words[2][1], 10);
|
||||
m_words[2][2] = rotatel (m_words[2][2], 43);
|
||||
m_words[2][3] = rotatel (m_words[2][3], 25);
|
||||
m_words[2][4] = rotatel (m_words[2][4], 39);
|
||||
m_words[3][0] = rotatel (m_words[3][0], 41);
|
||||
m_words[3][1] = rotatel (m_words[3][1], 45);
|
||||
m_words[3][2] = rotatel (m_words[3][2], 15);
|
||||
m_words[3][3] = rotatel (m_words[3][3], 21);
|
||||
m_words[3][4] = rotatel (m_words[3][4], 8);
|
||||
m_words[4][0] = rotatel (m_words[4][0], 18);
|
||||
m_words[4][1] = rotatel (m_words[4][1], 2);
|
||||
m_words[4][2] = rotatel (m_words[4][2], 61);
|
||||
m_words[4][3] = rotatel (m_words[4][3], 56);
|
||||
m_words[4][4] = rotatel (m_words[4][4], 14);
|
||||
return;
|
||||
|
||||
|
||||
for (size_t i = 1; i < 25; ++i) {
|
||||
//unsigned r = ((t+1)*(t+2)/2)%64;
|
||||
unsigned r = ((i + 1) * (i + 2) / 2) % 64;
|
||||
|
||||
m_words[i/5][i%5] = rotatel (m_words[i/5][i%5], r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
permute_pi (uint64_t m_words[5][5])
|
||||
{
|
||||
//auto A = reinterpret_cast<uint64_t*> (m_words);
|
||||
|
||||
//uint64_t A1;
|
||||
//A1 = A[1];
|
||||
//A[ 1] = A[ 6];
|
||||
//A[ 6] = A[ 9];
|
||||
//A[ 9] = A[22];
|
||||
//A[22] = A[14];
|
||||
//A[14] = A[20];
|
||||
//A[20] = A[ 2];
|
||||
//A[ 2] = A[12];
|
||||
//A[12] = A[13];
|
||||
//A[13] = A[19];
|
||||
//A[19] = A[23];
|
||||
//A[23] = A[15];
|
||||
//A[15] = A[ 4];
|
||||
//A[ 4] = A[24];
|
||||
//A[24] = A[21];
|
||||
//A[21] = A[ 8];
|
||||
//A[ 8] = A[16];
|
||||
//A[16] = A[ 5];
|
||||
//A[ 5] = A[ 3];
|
||||
//A[ 3] = A[18];
|
||||
//A[18] = A[17];
|
||||
//A[17] = A[11];
|
||||
//A[11] = A[ 7];
|
||||
//A[ 7] = A[10];
|
||||
//A[10] = A1;
|
||||
//return;
|
||||
|
||||
unsigned x = 1, y = 0;
|
||||
uint64_t current = m_words[y][x];
|
||||
uint64_t temp;
|
||||
// Iterate over ((0 1)(2 3))^t * (1 0) for 0 ≤ t ≤ 23
|
||||
for (unsigned t = 0; t < 24; ++t) {
|
||||
unsigned int Y = (2*x+3*y)%5;
|
||||
x = y;
|
||||
y = Y;
|
||||
|
||||
temp = m_words[y][x];
|
||||
m_words[y][x] = current;
|
||||
current = temp;
|
||||
}
|
||||
|
||||
//for (unsigned int i = 0; i < 5; ++i)
|
||||
// for (unsigned int j = 0; j < 5; ++j)
|
||||
// m_words[j][(2*i+3*j)%5] = m_words[i][j];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function that computes the Keccak-f[1600] permutation on the given state.
|
||||
*/
|
||||
void
|
||||
keccak::permute (void)
|
||||
{
|
||||
for (size_t i = 0; i < m_bitrate/64; ++i)
|
||||
m_words[i/5][i%5] = ltoh (m_words[i/5][i%5]);
|
||||
|
||||
lfsr86540 shift;
|
||||
|
||||
for (unsigned round = 0; round < 24; ++round) {
|
||||
permute_theta (m_words);
|
||||
permute_rho (m_words);
|
||||
permute_pi (m_words);
|
||||
|
||||
|
||||
if (0) { // === ρ and π steps (see [Keccak Reference, Sections 2.3.3 and 2.3.4]) ===
|
||||
uint64_t current, temp;
|
||||
// Start at coordinates (1 0)
|
||||
unsigned x = 1, y = 0;
|
||||
current = m_words[y][x];
|
||||
// Iterate over ((0 1)(2 3))^t * (1 0) for 0 ≤ t ≤ 23
|
||||
for (unsigned t = 0; t < 24; ++t) {
|
||||
// Compute the rotation constant r = (t+1)(t+2)/2
|
||||
unsigned int r = ((t+1)*(t+2)/2)%64;
|
||||
|
||||
// Compute ((0 1)(2 3)) * (x y)
|
||||
unsigned int Y = (2*x+3*y)%5; x = y; y = Y;
|
||||
|
||||
// Swap current and state(x,y), and rotate
|
||||
temp = m_words[y][x];
|
||||
m_words[y][x] = rotatel (current, r);
|
||||
current = temp;
|
||||
}
|
||||
}
|
||||
|
||||
{ // === χ step (see [Keccak Reference, Section 2.3.1]) ===
|
||||
uint64_t temp[5];
|
||||
for (unsigned y = 0; y < 5; ++y) {
|
||||
// Take a copy of the plane
|
||||
for (unsigned x = 0; x < 5; ++x)
|
||||
temp[x] = m_words[y][x];
|
||||
|
||||
// Compute χ on the plane
|
||||
for(unsigned x = 0; x < 5; ++x)
|
||||
m_words[y][x] = temp[x] ^((~temp[(x+1)%5]) & temp[(x+2)%5]);
|
||||
}
|
||||
}
|
||||
|
||||
{ // === ι step (see [Keccak Reference, Section 2.3.5]) ===
|
||||
for (unsigned j = 0; j < 7; ++j) {
|
||||
unsigned int bitPosition = (1 << j) - 1; //2^j-1
|
||||
if (shift.update ())
|
||||
m_words[0][0] ^= uint64_t{1} << bitPosition;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
================================================================
|
||||
A readable and compact implementation of the Keccak sponge functions
|
||||
that use the Keccak-f[1600] permutation.
|
||||
================================================================
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
|
||||
|
||||
void
|
||||
keccak::update (
|
||||
const uint8_t *input,
|
||||
size_t len
|
||||
) {
|
||||
unsigned int byterate = m_bitrate / 8;
|
||||
|
||||
while (len) {
|
||||
auto chunk = util::min (len, byterate - m_cursor);
|
||||
|
||||
for (unsigned i = 0; i < chunk; ++i)
|
||||
m_bytes[m_cursor++] ^= *input++;
|
||||
|
||||
len -= chunk;
|
||||
|
||||
if (m_cursor == byterate) {
|
||||
permute ();
|
||||
m_cursor = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
keccak::digest (
|
||||
uint8_t *output,
|
||||
size_t len
|
||||
) {
|
||||
unsigned byterate = m_bitrate / 8u;
|
||||
|
||||
// === Do the padding and switch to the squeezing phase ===
|
||||
// Absorb the last few bits and add the first bit of padding (which
|
||||
// coincides with the delimiter in delimitedSuffix)
|
||||
m_bytes[m_cursor] ^= m_suffix;
|
||||
|
||||
// If the first bit of padding is at position rate-1, we need a whole new
|
||||
// block for the second bit of padding
|
||||
if (m_suffix & 0x80 && m_cursor == byterate - 1)
|
||||
permute ();
|
||||
|
||||
// Add the second bit of padding
|
||||
m_bytes[byterate - 1] ^= 0x80;
|
||||
|
||||
// === Squeeze out all the output blocks ===
|
||||
while (len) {
|
||||
permute ();
|
||||
|
||||
auto chunk = util::min (len, byterate);
|
||||
std::copy_n (m_bytes.begin (), chunk, output);
|
||||
|
||||
output += chunk;
|
||||
len -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
keccak::keccak (unsigned _bitrate,
|
||||
unsigned _capacity,
|
||||
uint8_t _suffix):
|
||||
m_bitrate (_bitrate),
|
||||
m_capacity (_capacity),
|
||||
m_suffix (_suffix),
|
||||
m_cursor (0)
|
||||
{
|
||||
// we could support bitrates that are multiples of 8, but 64 simplifies
|
||||
// some state handling, and the SHA-3 constants are all multiples of 64
|
||||
// bits anyway.
|
||||
if ((m_bitrate + m_capacity) / 8 != sizeof (m_bytes) || m_bitrate % 64 != 0)
|
||||
throw "error";
|
||||
|
||||
std::fill (std::begin (m_bytes), std::end (m_bytes), 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
53
hash/keccak.hpp
Normal file
53
hash/keccak.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright 2016 Danny Robson <danny@nerdcruft.net>
|
||||
*/
|
||||
|
||||
#ifndef __HASH_KECCAK_HPP
|
||||
#define __HASH_KECCAK_HPP
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
class keccak {
|
||||
public:
|
||||
keccak (unsigned bitrate, unsigned capacity, uint8_t suffix);
|
||||
|
||||
void update (const uint8_t *input, size_t len);
|
||||
void digest (uint8_t *output, size_t len);
|
||||
|
||||
private:
|
||||
void permute (void);
|
||||
|
||||
const unsigned m_bitrate;
|
||||
const unsigned m_capacity;
|
||||
const uint8_t m_suffix;
|
||||
|
||||
size_t m_cursor;
|
||||
|
||||
union {
|
||||
std::array<uint8_t, 200> m_bytes;
|
||||
uint64_t m_words[5][5];
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
void FIPS202_SHAKE128(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen);
|
||||
void FIPS202_SHAKE256(const uint8_t *input, size_t inputByteLen, uint8_t *output, size_t outputByteLen);
|
||||
void FIPS202_SHA3_224(const uint8_t *input, size_t inputByteLen, uint8_t *output);
|
||||
void FIPS202_SHA3_256(const uint8_t *input, size_t inputByteLen, uint8_t *output);
|
||||
void FIPS202_SHA3_384(const uint8_t *input, size_t inputByteLen, uint8_t *output);
|
||||
void FIPS202_SHA3_512(const uint8_t *input, size_t inputByteLen, uint8_t *output);
|
||||
|
||||
#endif
|
18
tap.hpp
18
tap.hpp
@ -45,34 +45,34 @@ namespace util { namespace TAP {
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_eq (const T&, const U&, const std::string &fmt, Args&...);
|
||||
void expect_eq (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_neq (const T&, const U&, const std::string &fmt, Args&...);
|
||||
void expect_neq (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_gt (const T&, const U&, const std::string &fmt, Args&...);
|
||||
void expect_gt (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_ge (const T&, const U&, const std::string &fmt, Args&...);
|
||||
void expect_ge (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_lt (const T&, const U&, const std::string &fmt, Args&...);
|
||||
void expect_lt (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void expect_le (const T&, const U&, const std::string &fmt, Args&...);
|
||||
void expect_le (const T&, const U&, const std::string &fmt, Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
void expect_nan (const T&, const std::string &fmt, Args&...);
|
||||
void expect_nan (const T&, const std::string &fmt, Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
void expect_nothrow (T&&, const std::string &fmt, Args&...);
|
||||
void expect_nothrow (T&&, const std::string &fmt, Args&&...);
|
||||
|
||||
template <typename E, typename T, typename ...Args>
|
||||
void expect_throw (T&&, const std::string &fmt, Args&...);
|
||||
void expect_throw (T&&, const std::string &fmt, Args&&...);
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
void skip (const std::string &msg);
|
||||
|
12
tap.ipp
12
tap.ipp
@ -54,7 +54,7 @@ util::TAP::logger::expect (const std::function<bool(Args...)> &test, Args&&... a
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void
|
||||
util::TAP::logger::expect_eq (const T&a, const U &b, const std::string &fmt, Args&... args)
|
||||
util::TAP::logger::expect_eq (const T&a, const U &b, const std::string &fmt, Args&&... args)
|
||||
{
|
||||
static const std::function<bool(const T&,const U&)> TEST = [] (const T &t, const U &u) -> bool {
|
||||
return almost_equal (t, u);
|
||||
@ -67,7 +67,7 @@ util::TAP::logger::expect_eq (const T&a, const U &b, const std::string &fmt, Arg
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename U, typename ...Args>
|
||||
void
|
||||
util::TAP::logger::expect_neq (const T&a, const U &b, const std::string &fmt, Args&... args)
|
||||
util::TAP::logger::expect_neq (const T&a, const U &b, const std::string &fmt, Args&&... args)
|
||||
{
|
||||
static const std::function<bool(const T&,const U&)> TEST = [] (const T &t, const U &u) -> bool {
|
||||
return !almost_equal (t, u);
|
||||
@ -84,7 +84,7 @@ void \
|
||||
util::TAP::logger::expect_ ## SUFFIX (const T &a, \
|
||||
const U &b, \
|
||||
const std::string &fmt, \
|
||||
Args&... args) \
|
||||
Args&&... args) \
|
||||
{ \
|
||||
static const std::function< \
|
||||
bool(const T&,const U&) \
|
||||
@ -111,7 +111,7 @@ TAP_TEST(le, <=)
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
void
|
||||
util::TAP::logger::expect_nan (const T &t, const std::string &fmt, Args&... args)
|
||||
util::TAP::logger::expect_nan (const T &t, const std::string &fmt, Args&&... args)
|
||||
{
|
||||
bool(*func)(T) = std::isnan;
|
||||
expect<const T&> (
|
||||
@ -125,7 +125,7 @@ util::TAP::logger::expect_nan (const T &t, const std::string &fmt, Args&... args
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename T, typename ...Args>
|
||||
void
|
||||
util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&... args)
|
||||
util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&&... args)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
@ -142,7 +142,7 @@ util::TAP::logger::expect_nothrow (T &&t, const std::string &fmt, Args&... args)
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename E, typename T, typename ...Args>
|
||||
void
|
||||
util::TAP::logger::expect_throw (T &&t, const std::string &fmt, Args&... args)
|
||||
util::TAP::logger::expect_throw (T &&t, const std::string &fmt, Args&&... args)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
|
43
test/crypto/ice.cpp
Normal file
43
test/crypto/ice.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "crypto/ice.hpp"
|
||||
#include "tap.hpp"
|
||||
#include "iterator.hpp"
|
||||
#include "stream.hpp"
|
||||
#include "endian.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
|
||||
int
|
||||
main (int, char**)
|
||||
{
|
||||
const uint64_t data = 0xfedcba9876543210;
|
||||
|
||||
struct {
|
||||
unsigned level;
|
||||
uint64_t crypt;
|
||||
std::vector<uint64_t> key;
|
||||
} TESTS[] = {
|
||||
{ 0, 0xde240d83a00a9cc0, { 0xdeadbeef01234567 } },
|
||||
{ 1, 0x7d6ef1ef30d47a96, { 0xdeadbeef01234567 } },
|
||||
{ 2, 0xf94840d86972f21c, { 0x0011223344556677, 0x8899aabbccddeeff } },
|
||||
};
|
||||
|
||||
util::TAP::logger tap;
|
||||
|
||||
for (const auto &t: TESTS) {
|
||||
std::vector<uint64_t> k (t.key.cbegin (), t.key.cend ());
|
||||
std::transform (k.cbegin (), k.cend (), k.begin (), hton<uint64_t>);
|
||||
|
||||
ice key (t.level, k.data (), k.data () + k.size ());
|
||||
|
||||
auto crypt = key.encrypt (data);
|
||||
auto plain = key.decrypt (t.crypt);
|
||||
|
||||
tap.expect_eq (crypt, t.crypt, "ICE level %u certification, encrypt", t.level);
|
||||
tap.expect_eq (plain, data, "ICE level %u certification, decrypt", t.level);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
}
|
179
test/hash/keccak.cpp
Normal file
179
test/hash/keccak.cpp
Normal file
@ -0,0 +1,179 @@
|
||||
#include "hash/keccak.hpp"
|
||||
#include "debug.hpp"
|
||||
#include "tap.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
static constexpr
|
||||
uint8_t
|
||||
from_hex (char c) {
|
||||
switch (c) {
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
return c - '0';
|
||||
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
return 10 + c - 'A';
|
||||
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
return 10 + c - 'a';
|
||||
}
|
||||
|
||||
unreachable ();
|
||||
}
|
||||
|
||||
|
||||
template <size_t S>
|
||||
static constexpr
|
||||
std::array<uint8_t,S/2>
|
||||
make_array (const char (&str)[S])
|
||||
{
|
||||
if (S < 1)
|
||||
return {};
|
||||
|
||||
static_assert (S % 2 == 1, "requires full bytes + null");
|
||||
std::array<uint8_t,S/2> out {};
|
||||
|
||||
for (size_t i = 0; i < S - 1; i+=2) {
|
||||
out[i / 2] = +from_hex (str[i]) << 4 | +from_hex (str[i+1]);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template <size_t S>
|
||||
static
|
||||
std::vector<uint8_t>
|
||||
make_vector (const char (&str)[S]) {
|
||||
const auto arr = make_array (str);
|
||||
return std::vector<uint8_t> (arr.cbegin (), arr.cend ());
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int, char**)
|
||||
{
|
||||
util::TAP::logger tap;
|
||||
|
||||
static const struct {
|
||||
const char *msg;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
std::array<uint8_t, 28> sha3_224;
|
||||
std::array<uint8_t, 32> sha3_256;
|
||||
std::array<uint8_t, 48> sha3_384;
|
||||
std::array<uint8_t, 64> sha3_512;
|
||||
} TESTS[] = {
|
||||
{
|
||||
" empty string",
|
||||
{ },
|
||||
make_array ("6B4E03423667DBB73B6E15454F0EB1ABD4597F9A1B078E3F5B5A6BC7"),
|
||||
make_array ("A7FFC6F8BF1ED76651C14756A061D662F580FF4DE43B49FA82D80A4B80F8434A"),
|
||||
make_array ("0C63A75B845E4F7D01107D852E4C2485C51A50AAAA94FC61995E71BBEE983A2AC3713831264ADB47FB6BD1E058D5F004"),
|
||||
make_array ("A69F73CCA23A9AC5C8B567DC185A756E97C982164FE25859E0D1DCC1475C80A615B2123AF1F5F94C11E3E9402C3AC558F500199D95B6D3E301758586281DCD26"),
|
||||
},
|
||||
{
|
||||
" 8-bit string",
|
||||
make_vector ("CC"),
|
||||
make_array ("DF70ADC49B2E76EEE3A6931B93FA41841C3AF2CDF5B32A18B5478C39"),
|
||||
make_array ("677035391CD3701293D385F037BA32796252BB7CE180B00B582DD9B20AAAD7F0"),
|
||||
make_array ("5EE7F374973CD4BB3DC41E3081346798497FF6E36CB9352281DFE07D07FC530CA9AD8EF7AAD56EF5D41BE83D5E543807"),
|
||||
make_array ("3939FCC8B57B63612542DA31A834E5DCC36E2EE0F652AC72E02624FA2E5ADEECC7DD6BB3580224B4D6138706FC6E80597B528051230B00621CC2B22999EAA205"),
|
||||
},
|
||||
{
|
||||
" 16-bit string",
|
||||
make_vector ("41FB"),
|
||||
make_array ("BFF295861DAEDF33E70519B1E2BCB4C2E9FE3364D789BC3B17301C15"),
|
||||
make_array ("39F31B6E653DFCD9CAED2602FD87F61B6254F581312FB6EEEC4D7148FA2E72AA"),
|
||||
make_array ("1DD81609DCC290EFFD7AC0A95D4A20821580E56BD50DBD843920650BE7A80A1719577DA337CFDF86E51C764CAA2E10BD"),
|
||||
make_array ("AA092865A40694D91754DBC767B5202C546E226877147A95CB8B4C8F8709FE8CD6905256B089DA37896EA5CA19D2CD9AB94C7192FC39F7CD4D598975A3013C69"),
|
||||
},
|
||||
{
|
||||
"224-bit string",
|
||||
make_vector ("0F8B2D8FCFD9D68CFFC17CCFB117709B53D26462A3F346FB7C79B85E"),
|
||||
make_array ("1E693B0BCE2372550DAEF35B14F13AB43441ED6742DEE3E86FD1D8EF"),
|
||||
make_array ("6DE164A9626D5A4F54D854AC158994F35A8E362ECC753F55182790934A2E0D06"),
|
||||
make_array ("641A7AF13B889D1A0F1AA3E4E4FF8CC5903C47E1A52BDEA257D80E37E596564AB33EEAD06717CDB6B706CB6986293D4F"),
|
||||
make_array ("21132FC11F6040AD493D627027C752CE29816589DE7BE78562914B63D1A9219803DDBD9673AA749F37FF4D6E1B5AE2A12633BA8B0C9994E031EBF6C42E58A793"),
|
||||
},
|
||||
{
|
||||
"256-bit string",
|
||||
make_vector ("9F2FCC7C90DE090D6B87CD7E9718C1EA6CB21118FC2D5DE9F97E5DB6AC1E9C10"),
|
||||
make_array ("887921848AD98458F3DB3E0ECD5AD5DB1F0BF9F2D0CA08601074D597"),
|
||||
make_array ("2F1A5F7159E34EA19CDDC70EBF9B81F1A66DB40615D7EAD3CC1F1B954D82A3AF"),
|
||||
make_array ("BAAE7AAED4FBF42F9316C7E8F722EEB06A598B509F184B22FBD5A81C93D95FFF711F5DE90847B3248B6DF76CABCE07EE"),
|
||||
make_array ("B087C90421AEBF87911647DE9D465CBDA166B672EC47CCD4054A7135A1EF885E7903B52C3F2C3FE722B1C169297A91B82428956A02C631A2240F12162C7BC726"),
|
||||
},
|
||||
{
|
||||
"384-bit string",
|
||||
make_vector ("D8FABA1F5194C4DB5F176FABFFF856924EF627A37CD08CF55608BBA8F1E324D7C7F157298EABC4DCE7D89CE5162499F9"),
|
||||
make_array ("B7A51FBB084DEEB55136EFD7260E5B112E3C40D1A2D14B142DF930DF"),
|
||||
make_array ("34F8607EC10C092C1BA0B6565CE6197062C4E1A35A8E8C723E48A2D2416C3790"),
|
||||
make_array ("A127FEFCDD240F762CCE3F5F1551FC7E1CDEBC7950D1CD94C6888F490CB2285A10FD0EE797B168C5CA4761FA232AAF05"),
|
||||
make_array ("7EF3A2894C6ECBC4201B15348F90671515ACCBA3C8166621F864A9184BF08C3F5A895F6B599D3CB41F20A8A1DF25AE84F1A6D7C8DE74FB7CEF48F7E96FDE8D43"),
|
||||
},
|
||||
{
|
||||
"512-bit string",
|
||||
make_vector ("E926AE8B0AF6E53176DBFFCC2A6B88C6BD765F939D3D178A9BDE9EF3AA131C61E31C1E42CDFAF4B4DCDE579A37E150EFBEF5555B4C1CB40439D835A724E2FAE7"),
|
||||
make_array ("C154607F986F9BF902D831293C8386D36B201EABA6F6FB0B678B4B81"),
|
||||
make_array ("27A6441EE939B46E2C378D7AFEB0E891C47A28120E488EFF0AB71AF08788CEB3"),
|
||||
make_array ("423BA134D3BCB5E440AC83372C7EDDBA3AE3BDDF1222F505C19CDE246AD76A2B0D07239A54E1D0934C9B3D29D49E5FBD"),
|
||||
make_array ("EB5067BF762A291CF258AD69A816A0B089E0BD44F8E5B74CF60BCE64734E59853CCB8D091CD2E33F90AA063FB7942CF5965D459200144C1A0801ABD69A9A094A"),
|
||||
},
|
||||
{
|
||||
"520-bit string",
|
||||
make_vector ("16E8B3D8F988E9BB04DE9C96F2627811C973CE4A5296B4772CA3EEFEB80A652BDF21F50DF79F32DB23F9F73D393B2D57D9A0297F7A2F2E79CFDA39FA393DF1AC00"),
|
||||
make_array ("95E87AC90F541AB90CBCF7FD7E0E0C152CEF78D5EE1830E9ED8A1ED7"),
|
||||
make_array ("C4BB067383002DB44CA773918BB74104B604A583E12B06BE56C270F8B43512F2"),
|
||||
make_array ("662C4851D311A786DE4CDA7E9EA1EFF0BFA462761FF6CF804E591ED9A15B0DC93A2BB6A6CFFDC8D7D23A233A52C86EAD"),
|
||||
make_array ("B0E23D600BA4215F79D50047BBFED50DF7D6E769514D796AFD166DEECA88BD1CBE0AFC72A41E0317A223225B4F5882F723AFCBA3AF7C457EB525946DA6C53BB0"),
|
||||
},
|
||||
{
|
||||
"1,000,000 'a' string",
|
||||
std::vector<uint8_t> (1'000'000, 'a'),
|
||||
make_array ("d69335b93325192e516a912e6d19a15cb51c6ed5c15243e7a7fd653c"),
|
||||
make_array ("5c8875ae474a3634ba4fd55ec85bffd661f32aca75c6d699d0cdcb6c115891c1"),
|
||||
make_array ("eee9e24d78c1855337983451df97c8ad9eedf256c6334f8e948d252d5e0e76847aa0774ddb90a842190d2c558b4b8340"),
|
||||
make_array ("3c3a876da14034ab60627c077bb98f7e120a2a5370212dffb3385a18d4f38859ed311d0a9d5141ce9cc5c66ee689b266a8aa18ace8282a0e0db596c90b0a7b87"),
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto &t: TESTS) {
|
||||
#define TEST(WIDTH) \
|
||||
do { \
|
||||
std::array<uint8_t, WIDTH/8> sha3_##WIDTH; \
|
||||
std::fill (std::begin (sha3_##WIDTH), std::end (sha3_##WIDTH), 0); \
|
||||
\
|
||||
FIPS202_SHA3_##WIDTH (t.data.data (), t.data.size (), &sha3_##WIDTH[0]); \
|
||||
\
|
||||
tap.expect_eq (t.sha3_##WIDTH, sha3_##WIDTH, "sha3-%u %s", unsigned (WIDTH), t.msg); \
|
||||
} while (0)
|
||||
|
||||
TEST(224);
|
||||
TEST(256);
|
||||
TEST(384);
|
||||
TEST(512);
|
||||
}
|
||||
|
||||
return tap.status ();
|
||||
}
|
Loading…
Reference in New Issue
Block a user