poly1305.h raw
1 // Copyright (c) 2019-present 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 <cstddef>
12 #include <cstdint>
13 #include <span>
14
15 #define POLY1305_BLOCK_SIZE 16
16
17 namespace poly1305_donna {
18
19 // Based on the public domain implementation by Andrew Moon
20 // poly1305-donna-32.h from https://github.com/floodyberry/poly1305-donna
21
22 typedef struct {
23 uint32_t r[5];
24 uint32_t h[5];
25 uint32_t pad[4];
26 size_t leftover;
27 unsigned char buffer[POLY1305_BLOCK_SIZE];
28 unsigned char final;
29 } poly1305_context;
30
31 void poly1305_init(poly1305_context *st, const unsigned char key[32]) noexcept;
32 void poly1305_update(poly1305_context *st, const unsigned char *m, size_t bytes) noexcept;
33 void poly1305_finish(poly1305_context *st, unsigned char mac[16]) noexcept;
34
35 } // namespace poly1305_donna
36
37 /** C++ wrapper with std::byte span interface around poly1305_donna code. */
38 class Poly1305
39 {
40 poly1305_donna::poly1305_context m_ctx;
41
42 public:
43 /** Length of the output produced by Finalize(). */
44 static constexpr unsigned TAGLEN{16};
45
46 /** Length of the keys expected by the constructor. */
47 static constexpr unsigned KEYLEN{32};
48
49 /** Construct a Poly1305 object with a given 32-byte key. */
50 Poly1305(std::span<const std::byte> key) noexcept
51 {
52 assert(key.size() == KEYLEN);
53 poly1305_donna::poly1305_init(&m_ctx, UCharCast(key.data()));
54 }
55
56 /** Process message bytes. */
57 Poly1305& Update(std::span<const std::byte> msg) noexcept
58 {
59 poly1305_donna::poly1305_update(&m_ctx, UCharCast(msg.data()), msg.size());
60 return *this;
61 }
62
63 /** Write authentication tag to 16-byte out. */
64 void Finalize(std::span<std::byte> out) noexcept
65 {
66 assert(out.size() == TAGLEN);
67 poly1305_donna::poly1305_finish(&m_ctx, UCharCast(out.data()));
68 }
69 };
70
71 #endif // BITCOIN_CRYPTO_POLY1305_H
72