poly1305.h raw

   1  // Copyright (c) 2019-2022 The Limenka developers
   2  // Distributed under the MIT software license, see the accompanying
   3  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
   4  
   5  #ifndef LIMENKA_CRYPTO_POLY1305_H
   6  #define LIMENKA_CRYPTO_POLY1305_H
   7  
   8  #include <span.h>
   9  
  10  #include <cassert>
  11  #include <cstdlib>
  12  #include <stdint.h>
  13  
  14  #define POLY1305_BLOCK_SIZE 16
  15  
  16  namespace poly1305_donna {
  17  
  18  // Based on the public domain implementation by Andrew Moon
  19  // poly1305-donna-32.h from https://github.com/floodyberry/poly1305-donna
  20  
  21  typedef struct {
  22      uint32_t r[5];
  23      uint32_t h[5];
  24      uint32_t pad[4];
  25      size_t leftover;
  26      unsigned char buffer[POLY1305_BLOCK_SIZE];
  27      unsigned char final;
  28  } poly1305_context;
  29  
  30  void poly1305_init(poly1305_context *st, const unsigned char key[32]) noexcept;
  31  void poly1305_update(poly1305_context *st, const unsigned char *m, size_t bytes) noexcept;
  32  void poly1305_finish(poly1305_context *st, unsigned char mac[16]) noexcept;
  33  
  34  }  // namespace poly1305_donna
  35  
  36  /** C++ wrapper with std::byte Span interface around poly1305_donna code. */
  37  class Poly1305
  38  {
  39      poly1305_donna::poly1305_context m_ctx;
  40  
  41  public:
  42      /** Length of the output produced by Finalize(). */
  43      static constexpr unsigned TAGLEN{16};
  44  
  45      /** Length of the keys expected by the constructor. */
  46      static constexpr unsigned KEYLEN{32};
  47  
  48      /** Construct a Poly1305 object with a given 32-byte key. */
  49      Poly1305(Span<const std::byte> key) noexcept
  50      {
  51          assert(key.size() == KEYLEN);
  52          poly1305_donna::poly1305_init(&m_ctx, UCharCast(key.data()));
  53      }
  54  
  55      /** Process message bytes. */
  56      Poly1305& Update(Span<const std::byte> msg) noexcept
  57      {
  58          poly1305_donna::poly1305_update(&m_ctx, UCharCast(msg.data()), msg.size());
  59          return *this;
  60      }
  61  
  62      /** Write authentication tag to 16-byte out. */
  63      void Finalize(Span<std::byte> out) noexcept
  64      {
  65          assert(out.size() == TAGLEN);
  66          poly1305_donna::poly1305_finish(&m_ctx, UCharCast(out.data()));
  67      }
  68  };
  69  
  70  #endif // LIMENKA_CRYPTO_POLY1305_H
  71