/ src / crypto / poly1305.h
poly1305.h
 1  // Copyright (c) 2019-2022 The Bitcoin Core 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 BITCOIN_CRYPTO_POLY1305_H
 6  #define BITCOIN_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 // BITCOIN_CRYPTO_POLY1305_H