Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:55:09

0001 // siphash.h - written and placed in public domain by Jeffrey Walton.

0002 
0003 /// \file siphash.h

0004 /// \brief Classes for SipHash message authentication code

0005 /// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length

0006 ///   message and 128-bit secret key. It was designed to be efficient even for short inputs, with

0007 ///   performance comparable to non-cryptographic hash functions.

0008 /// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following.

0009 ///   <pre>  SecByteBlock key(16);

0010 ///   prng.GenerateBlock(key, key.size());

0011 ///

0012 ///   SipHash<2,4,false> hash(key, key.size());

0013 ///   hash.Update(...);

0014 ///   hash.Final(...);</pre>

0015 /// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following.

0016 ///   <pre>  SecByteBlock key(16);

0017 ///   prng.GenerateBlock(key, key.size());

0018 ///

0019 ///   SipHash<2,4,true> hash(key, key.size());

0020 ///   hash.Update(...);

0021 ///   hash.Final(...);</pre>

0022 /// \sa Jean-Philippe Aumasson and Daniel J. Bernstein <A HREF="http://131002.net/siphash/siphash.pdf">SipHash:

0023 ///   a fast short-input PRF</A>

0024 /// \since Crypto++ 6.0

0025 
0026 #ifndef CRYPTOPP_SIPHASH_H
0027 #define CRYPTOPP_SIPHASH_H
0028 
0029 #include "cryptlib.h"
0030 #include "secblock.h"
0031 #include "seckey.h"
0032 #include "misc.h"
0033 
0034 NAMESPACE_BEGIN(CryptoPP)
0035 
0036 /// \brief SipHash message authentication code information

0037 /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size

0038 template <bool T_128bit>
0039 class SipHash_Info : public FixedKeyLength<16>
0040 {
0041 public:
0042     CRYPTOPP_STATIC_CONSTEXPR const char* StaticAlgorithmName() {return "SipHash";}
0043     CRYPTOPP_CONSTANT(DIGESTSIZE = (T_128bit ? 16 : 8));
0044 };
0045 
0046 /// \brief SipHash message authentication code base class

0047 /// \tparam C the number of compression rounds

0048 /// \tparam D the number of finalization rounds

0049 /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size

0050 template <unsigned int C, unsigned int D, bool T_128bit>
0051 class SipHash_Base : public MessageAuthenticationCode, public SipHash_Info<T_128bit>
0052 {
0053 public:
0054     static std::string StaticAlgorithmName() {
0055         return std::string(SipHash_Info<T_128bit>::StaticAlgorithmName())+"-"+IntToString(C)+"-"+IntToString(D);
0056     }
0057 
0058     virtual ~SipHash_Base() {}
0059 
0060     SipHash_Base() : m_idx(0) {}
0061 
0062     virtual unsigned int DigestSize() const
0063         {return SipHash_Info<T_128bit>::DIGESTSIZE;}
0064     virtual size_t MinKeyLength() const
0065         {return SipHash_Info<T_128bit>::MIN_KEYLENGTH;}
0066     virtual size_t MaxKeyLength() const
0067         {return SipHash_Info<T_128bit>::MAX_KEYLENGTH;}
0068     virtual size_t DefaultKeyLength() const
0069         {return SipHash_Info<T_128bit>::DEFAULT_KEYLENGTH;}
0070     virtual size_t GetValidKeyLength(size_t keylength) const
0071         {CRYPTOPP_UNUSED(keylength); return SipHash_Info<T_128bit>::DEFAULT_KEYLENGTH;}
0072     virtual IV_Requirement IVRequirement() const
0073         {return SimpleKeyingInterface::NOT_RESYNCHRONIZABLE;}
0074     virtual unsigned int IVSize() const
0075         {return 0;}
0076     virtual unsigned int OptimalBlockSize() const
0077         {return sizeof(word64);}
0078     virtual unsigned int OptimalDataAlignment () const
0079         {return GetAlignmentOf<word64>();}
0080 
0081     virtual void Update(const byte *input, size_t length);
0082     virtual void TruncatedFinal(byte *digest, size_t digestSize);
0083 
0084 protected:
0085 
0086     virtual void UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params);
0087     virtual void Restart();
0088 
0089     inline void SIPROUND()
0090     {
0091         m_v[0] += m_v[1];
0092         m_v[1] = rotlConstant<13>(m_v[1]);
0093         m_v[1] ^= m_v[0];
0094         m_v[0] = rotlConstant<32>(m_v[0]);
0095         m_v[2] += m_v[3];
0096         m_v[3] = rotlConstant<16>(m_v[3]);
0097         m_v[3] ^= m_v[2];
0098         m_v[0] += m_v[3];
0099         m_v[3] = rotlConstant<21>(m_v[3]);
0100         m_v[3] ^= m_v[0];
0101         m_v[2] += m_v[1];
0102         m_v[1] = rotlConstant<17>(m_v[1]);
0103         m_v[1] ^= m_v[2];
0104         m_v[2] = rotlConstant<32>(m_v[2]);
0105     }
0106 
0107 private:
0108     FixedSizeSecBlock<word64, 4> m_v;
0109     FixedSizeSecBlock<word64, 2> m_k;
0110     FixedSizeSecBlock<word64, 2> m_b;
0111 
0112     // Tail bytes

0113     FixedSizeSecBlock<byte, 8> m_acc;
0114     size_t m_idx;
0115 };
0116 
0117 /// \brief SipHash message authentication code

0118 /// \tparam C the number of compression rounds

0119 /// \tparam D the number of finalization rounds

0120 /// \tparam T_128bit flag indicating 128-bit (true) versus 64-bit (false) digest size

0121 /// \details SipHash computes a 64-bit or 128-bit message authentication code from a variable-length

0122 ///   message and 128-bit secret key. It was designed to be efficient even for short inputs, with

0123 ///   performance comparable to non-cryptographic hash functions.

0124 /// \details To create a SipHash-2-4 object with a 64-bit MAC use code similar to the following.

0125 ///   <pre>  SecByteBlock key(16);

0126 ///   prng.GenerateBlock(key, key.size());

0127 ///

0128 ///   SipHash<2,4,false> hash(key, key.size());

0129 ///   hash.Update(...);

0130 ///   hash.Final(...);</pre>

0131 /// \details To create a SipHash-2-4 object with a 128-bit MAC use code similar to the following.

0132 ///   <pre>  SecByteBlock key(16);

0133 ///   prng.GenerateBlock(key, key.size());

0134 ///

0135 ///   SipHash<2,4,true> hash(key, key.size());

0136 ///   hash.Update(...);

0137 ///   hash.Final(...);</pre>

0138 /// \sa Jean-Philippe Aumasson and Daniel J. Bernstein <A HREF="http://131002.net/siphash/siphash.pdf">SipHash:

0139 ///   a fast short-input PRF</A>

0140 /// \since Crypto++ 6.0

0141 template <unsigned int C=2, unsigned int D=4, bool T_128bit=false>
0142 class SipHash : public SipHash_Base<C, D, T_128bit>
0143 {
0144 public:
0145     /// \brief Create a SipHash

0146     SipHash()
0147         {this->UncheckedSetKey(NULLPTR, 0, g_nullNameValuePairs);}
0148     /// \brief Create a SipHash

0149     /// \param key a byte array used to key the cipher

0150     /// \param length the size of the byte array, in bytes

0151     SipHash(const byte *key, unsigned int length)
0152         {this->ThrowIfInvalidKeyLength(length);
0153          this->UncheckedSetKey(key, length, g_nullNameValuePairs);}
0154 };
0155 
0156 template <unsigned int C, unsigned int D, bool T_128bit>
0157 void SipHash_Base<C,D,T_128bit>::Update(const byte *input, size_t length)
0158 {
0159     CRYPTOPP_ASSERT((input && length) || !length);
0160     if (!length) return;
0161 
0162     if (m_idx)
0163     {
0164         size_t head = STDMIN(size_t(8U-m_idx), length);
0165         std::memcpy(m_acc+m_idx, input, head);
0166         m_idx += head; input += head; length -= head;
0167 
0168         if (m_idx == 8)
0169         {
0170             word64 m = GetWord<word64>(true, LITTLE_ENDIAN_ORDER, m_acc);
0171             m_v[3] ^= m;
0172             for (unsigned int i = 0; i < C; ++i)
0173                 SIPROUND();
0174 
0175             m_v[0] ^= m;
0176             m_b[0] += 8;
0177 
0178             m_idx = 0;
0179         }
0180     }
0181 
0182     while (length >= 8)
0183     {
0184         word64 m = GetWord<word64>(false, LITTLE_ENDIAN_ORDER, input);
0185         m_v[3] ^= m;
0186         for (unsigned int i = 0; i < C; ++i)
0187             SIPROUND();
0188 
0189         m_v[0] ^= m;
0190         m_b[0] += 8;
0191 
0192         input += 8;
0193         length -= 8;
0194     }
0195 
0196     CRYPTOPP_ASSERT(length < 8);
0197     size_t tail = length % 8;
0198     if (tail)
0199     {
0200         std::memcpy(m_acc+m_idx, input, tail);
0201         m_idx += tail;
0202     }
0203 }
0204 
0205 template <unsigned int C, unsigned int D, bool T_128bit>
0206 void SipHash_Base<C,D,T_128bit>::TruncatedFinal(byte *digest, size_t digestSize)
0207 {
0208     CRYPTOPP_ASSERT(digest);      // Pointer is valid

0209 
0210     ThrowIfInvalidTruncatedSize(digestSize);
0211 
0212     // The high octet holds length and is digested mod 256

0213     m_b[0] += m_idx; m_b[0] <<= 56U;
0214     switch (m_idx)
0215     {
0216         case 7:
0217             m_b[0] |= ((word64)m_acc[6]) << 48;
0218             // fall through

0219         case 6:
0220             m_b[0] |= ((word64)m_acc[5]) << 40;
0221             // fall through

0222         case 5:
0223             m_b[0] |= ((word64)m_acc[4]) << 32;
0224             // fall through

0225         case 4:
0226             m_b[0] |= ((word64)m_acc[3]) << 24;
0227             // fall through

0228         case 3:
0229             m_b[0] |= ((word64)m_acc[2]) << 16;
0230             // fall through

0231         case 2:
0232             m_b[0] |= ((word64)m_acc[1]) << 8;
0233             // fall through

0234         case 1:
0235             m_b[0] |= ((word64)m_acc[0]);
0236             // fall through

0237         case 0:
0238             break;
0239     }
0240 
0241     m_v[3] ^= m_b[0];
0242 
0243     for (unsigned int i=0; i<C; i++)
0244         SIPROUND();
0245 
0246     m_v[0] ^= m_b[0];
0247 
0248     if (T_128bit)
0249         m_v[2] ^= 0xee;
0250     else
0251         m_v[2] ^= 0xff;
0252 
0253     for (unsigned int i=0; i<D; i++)
0254         SIPROUND();
0255 
0256     m_b[0] = m_v[0] ^ m_v[1] ^ m_v[2] ^ m_v[3];
0257     m_b[0] = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, m_b[0]);
0258 
0259     if (T_128bit)
0260     {
0261         m_v[1] ^= 0xdd;
0262         for (unsigned int i = 0; i<D; ++i)
0263             SIPROUND();
0264 
0265         m_b[1] = m_v[0] ^ m_v[1] ^ m_v[2] ^ m_v[3];
0266         m_b[1] = ConditionalByteReverse(LITTLE_ENDIAN_ORDER, m_b[1]);
0267     }
0268 
0269     memcpy_s(digest, digestSize, m_b.begin(), STDMIN(digestSize, (size_t)SipHash_Info<T_128bit>::DIGESTSIZE));
0270     Restart();
0271 }
0272 
0273 template <unsigned int C, unsigned int D, bool T_128bit>
0274 void SipHash_Base<C,D,T_128bit>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
0275 {
0276     CRYPTOPP_UNUSED(params);
0277     if (key && length)
0278     {
0279         m_k[0] = GetWord<word64>(false, LITTLE_ENDIAN_ORDER, key);
0280         m_k[1] = GetWord<word64>(false, LITTLE_ENDIAN_ORDER, key+8);
0281     }
0282     else
0283     {
0284         // Avoid Coverity finding

0285         m_k[0] = m_k[1] = 0;
0286     }
0287     Restart();
0288 }
0289 
0290 template <unsigned int C, unsigned int D, bool T_128bit>
0291 void SipHash_Base<C,D,T_128bit>::Restart ()
0292 {
0293     m_v[0] = W64LIT(0x736f6d6570736575);
0294     m_v[1] = W64LIT(0x646f72616e646f6d);
0295     m_v[2] = W64LIT(0x6c7967656e657261);
0296     m_v[3] = W64LIT(0x7465646279746573);
0297 
0298     m_v[3] ^= m_k[1];
0299     m_v[2] ^= m_k[0];
0300     m_v[1] ^= m_k[1];
0301     m_v[0] ^= m_k[0];
0302 
0303     if (T_128bit)
0304     {
0305         m_v[1] ^= 0xee;
0306     }
0307 
0308     m_idx = 0;
0309     m_b[0] = 0;
0310 }
0311 
0312 NAMESPACE_END
0313 
0314 #endif // CRYPTOPP_SIPHASH_H