diff --git a/src/bench/CMakeLists.txt b/src/bench/CMakeLists.txt --- a/src/bench/CMakeLists.txt +++ b/src/bench/CMakeLists.txt @@ -53,6 +53,7 @@ mempool_eviction.cpp mempool_stress.cpp merkle_root.cpp + poly1305.cpp prevector.cpp rollingbloom.cpp rpc_blockchain.cpp diff --git a/src/bench/poly1305.cpp b/src/bench/poly1305.cpp new file mode 100644 --- /dev/null +++ b/src/bench/poly1305.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include + +/* Number of bytes to process per iteration */ +static constexpr uint64_t BUFFER_SIZE_TINY = 64; +static constexpr uint64_t BUFFER_SIZE_SMALL = 256; +static constexpr uint64_t BUFFER_SIZE_LARGE = 1024 * 1024; + +static void POLY1305(benchmark::State &state, size_t buffersize) { + std::vector tag(POLY1305_TAGLEN, 0); + std::vector key(POLY1305_KEYLEN, 0); + std::vector in(buffersize, 0); + while (state.KeepRunning()) { + poly1305_auth(tag.data(), in.data(), in.size(), key.data()); + } +} + +static void POLY1305_64BYTES(benchmark::State &state) { + POLY1305(state, BUFFER_SIZE_TINY); +} + +static void POLY1305_256BYTES(benchmark::State &state) { + POLY1305(state, BUFFER_SIZE_SMALL); +} + +static void POLY1305_1MB(benchmark::State &state) { + POLY1305(state, BUFFER_SIZE_LARGE); +} + +BENCHMARK(POLY1305_64BYTES, 500000); +BENCHMARK(POLY1305_256BYTES, 250000); +BENCHMARK(POLY1305_1MB, 340); diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -9,6 +9,7 @@ hkdf_sha256_32.cpp hmac_sha256.cpp hmac_sha512.cpp + poly1305.cpp ripemd160.cpp sha1.cpp sha256.cpp diff --git a/src/crypto/poly1305.h b/src/crypto/poly1305.h new file mode 100644 --- /dev/null +++ b/src/crypto/poly1305.h @@ -0,0 +1,17 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CRYPTO_POLY1305_H +#define BITCOIN_CRYPTO_POLY1305_H + +#include +#include + +#define POLY1305_KEYLEN 32 +#define POLY1305_TAGLEN 16 + +void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, + const uint8_t key[POLY1305_KEYLEN]); + +#endif // BITCOIN_CRYPTO_POLY1305_H diff --git a/src/crypto/poly1305.cpp b/src/crypto/poly1305.cpp new file mode 100644 --- /dev/null +++ b/src/crypto/poly1305.cpp @@ -0,0 +1,195 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +// Based on the public domain implementation by Andrew Moon +// poly1305-donna-unrolled.c from https://github.com/floodyberry/poly1305-donna + +#include +#include + +#include + +#define mul32x32_64(a, b) ((uint64_t)(a) * (b)) + +void poly1305_auth(uint8_t out[POLY1305_TAGLEN], const uint8_t *m, size_t inlen, + const uint8_t key[POLY1305_KEYLEN]) { + uint32_t t0, t1, t2, t3; + uint32_t h0, h1, h2, h3, h4; + uint32_t r0, r1, r2, r3, r4; + uint32_t s1, s2, s3, s4; + uint32_t b, nb; + size_t j; + uint64_t t[5]; + uint64_t f0, f1, f2, f3; + uint64_t g0, g1, g2, g3, g4; + uint64_t c; + uint8_t mp[16]; + + /* clamp key */ + t0 = ReadLE32(key + 0); + t1 = ReadLE32(key + 4); + t2 = ReadLE32(key + 8); + t3 = ReadLE32(key + 12); + + /* precompute multipliers */ + r0 = t0 & 0x3ffffff; + t0 >>= 26; + t0 |= t1 << 6; + r1 = t0 & 0x3ffff03; + t1 >>= 20; + t1 |= t2 << 12; + r2 = t1 & 0x3ffc0ff; + t2 >>= 14; + t2 |= t3 << 18; + r3 = t2 & 0x3f03fff; + t3 >>= 8; + r4 = t3 & 0x00fffff; + + s1 = r1 * 5; + s2 = r2 * 5; + s3 = r3 * 5; + s4 = r4 * 5; + + /* init state */ + h0 = 0; + h1 = 0; + h2 = 0; + h3 = 0; + h4 = 0; + + /* full blocks */ + if (inlen < 16) { + goto poly1305_donna_atmost15bytes; + } + +poly1305_donna_16bytes: + m += 16; + inlen -= 16; + + t0 = ReadLE32(m - 16); + t1 = ReadLE32(m - 12); + t2 = ReadLE32(m - 8); + t3 = ReadLE32(m - 4); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8) | (1 << 24); + +poly1305_donna_mul: + t[0] = mul32x32_64(h0, r0) + mul32x32_64(h1, s4) + mul32x32_64(h2, s3) + + mul32x32_64(h3, s2) + mul32x32_64(h4, s1); + t[1] = mul32x32_64(h0, r1) + mul32x32_64(h1, r0) + mul32x32_64(h2, s4) + + mul32x32_64(h3, s3) + mul32x32_64(h4, s2); + t[2] = mul32x32_64(h0, r2) + mul32x32_64(h1, r1) + mul32x32_64(h2, r0) + + mul32x32_64(h3, s4) + mul32x32_64(h4, s3); + t[3] = mul32x32_64(h0, r3) + mul32x32_64(h1, r2) + mul32x32_64(h2, r1) + + mul32x32_64(h3, r0) + mul32x32_64(h4, s4); + t[4] = mul32x32_64(h0, r4) + mul32x32_64(h1, r3) + mul32x32_64(h2, r2) + + mul32x32_64(h3, r1) + mul32x32_64(h4, r0); + + h0 = (uint32_t)t[0] & 0x3ffffff; + c = (t[0] >> 26); + t[1] += c; + h1 = (uint32_t)t[1] & 0x3ffffff; + b = (uint32_t)(t[1] >> 26); + t[2] += b; + h2 = (uint32_t)t[2] & 0x3ffffff; + b = (uint32_t)(t[2] >> 26); + t[3] += b; + h3 = (uint32_t)t[3] & 0x3ffffff; + b = (uint32_t)(t[3] >> 26); + t[4] += b; + h4 = (uint32_t)t[4] & 0x3ffffff; + b = (uint32_t)(t[4] >> 26); + h0 += b * 5; + + if (inlen >= 16) { + goto poly1305_donna_16bytes; + } + + /* final bytes */ +poly1305_donna_atmost15bytes: + if (!inlen) { + goto poly1305_donna_finish; + } + + for (j = 0; j < inlen; j++) { + mp[j] = m[j]; + } + mp[j++] = 1; + for (; j < 16; j++) { + mp[j] = 0; + } + inlen = 0; + + t0 = ReadLE32(mp + 0); + t1 = ReadLE32(mp + 4); + t2 = ReadLE32(mp + 8); + t3 = ReadLE32(mp + 12); + + h0 += t0 & 0x3ffffff; + h1 += ((((uint64_t)t1 << 32) | t0) >> 26) & 0x3ffffff; + h2 += ((((uint64_t)t2 << 32) | t1) >> 20) & 0x3ffffff; + h3 += ((((uint64_t)t3 << 32) | t2) >> 14) & 0x3ffffff; + h4 += (t3 >> 8); + + goto poly1305_donna_mul; + +poly1305_donna_finish: + b = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += b; + b = h1 >> 26; + h1 = h1 & 0x3ffffff; + h2 += b; + b = h2 >> 26; + h2 = h2 & 0x3ffffff; + h3 += b; + b = h3 >> 26; + h3 = h3 & 0x3ffffff; + h4 += b; + b = h4 >> 26; + h4 = h4 & 0x3ffffff; + h0 += b * 5; + b = h0 >> 26; + h0 = h0 & 0x3ffffff; + h1 += b; + + g0 = h0 + 5; + b = g0 >> 26; + g0 &= 0x3ffffff; + g1 = h1 + b; + b = g1 >> 26; + g1 &= 0x3ffffff; + g2 = h2 + b; + b = g2 >> 26; + g2 &= 0x3ffffff; + g3 = h3 + b; + b = g3 >> 26; + g3 &= 0x3ffffff; + g4 = h4 + b - (1 << 26); + + b = (g4 >> 31) - 1; + nb = ~b; + h0 = (h0 & nb) | (g0 & b); + h1 = (h1 & nb) | (g1 & b); + h2 = (h2 & nb) | (g2 & b); + h3 = (h3 & nb) | (g3 & b); + h4 = (h4 & nb) | (g4 & b); + + f0 = ((h0) | (h1 << 26)) + (uint64_t)ReadLE32(&key[16]); + f1 = ((h1 >> 6) | (h2 << 20)) + (uint64_t)ReadLE32(&key[20]); + f2 = ((h2 >> 12) | (h3 << 14)) + (uint64_t)ReadLE32(&key[24]); + f3 = ((h3 >> 18) | (h4 << 8)) + (uint64_t)ReadLE32(&key[28]); + + WriteLE32(&out[0], f0); + f1 += (f0 >> 32); + WriteLE32(&out[4], f1); + f2 += (f1 >> 32); + WriteLE32(&out[8], f2); + f3 += (f2 >> 32); + WriteLE32(&out[12], f3); +} diff --git a/src/test/crypto_tests.cpp b/src/test/crypto_tests.cpp --- a/src/test/crypto_tests.cpp +++ b/src/test/crypto_tests.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -251,6 +252,17 @@ } } +static void TestPoly1305(const std::string &hexmessage, + const std::string &hexkey, const std::string &hextag) { + std::vector key = ParseHex(hexkey); + std::vector m = ParseHex(hexmessage); + std::vector tag = ParseHex(hextag); + std::vector tagres; + tagres.resize(POLY1305_TAGLEN); + poly1305_auth(tagres.data(), m.data(), m.size(), key.data()); + BOOST_CHECK(tag == tagres); +} + static void TestHKDF_SHA256_32(const std::string &ikm_hex, const std::string &salt_hex, const std::string &info_hex, @@ -744,6 +756,108 @@ "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d"); } +BOOST_AUTO_TEST_CASE(poly1305_testvector) { + // RFC 7539, section 2.5.2. + TestPoly1305( + "43727970746f6772617068696320466f72756d2052657365617263682047726f7570", + "85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b", + "a8061dc1305136c6c22b8baf0c0127a9"); + + // RFC 7539, section A.3. + TestPoly1305( + "0000000000000000000000000000000000000000000000000000000000000000000000" + "0000000000000000000000000000000" + "000000000000000000000000000", + "0000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000"); + + TestPoly1305( + "416e79207375626d697373696f6e20746f20746865204945544620696e74656e646564" + "2062792074686520436f6e747269627" + "5746f7220666f72207075626c69636174696f6e20617320616c6c206f7220706172742" + "06f6620616e204945544620496e7465" + "726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74" + "206d6164652077697468696e2074686" + "520636f6e74657874206f6620616e204945544620616374697669747920697320636f6" + "e7369646572656420616e2022494554" + "4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e" + "636c756465206f72616c20737461746" + "56d656e747320696e20494554462073657373696f6e732c2061732077656c6c2061732" + "07772697474656e20616e6420656c65" + "6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e7920" + "74696d65206f7220706c6163652c207" + "768696368206172652061646472657373656420746f", + "0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e", + "36e5f6b5c5e06070f0efca96227a863e"); + + TestPoly1305( + "416e79207375626d697373696f6e20746f20746865204945544620696e74656e646564" + "2062792074686520436f6e747269627" + "5746f7220666f72207075626c69636174696f6e20617320616c6c206f7220706172742" + "06f6620616e204945544620496e7465" + "726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74" + "206d6164652077697468696e2074686" + "520636f6e74657874206f6620616e204945544620616374697669747920697320636f6" + "e7369646572656420616e2022494554" + "4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e" + "636c756465206f72616c20737461746" + "56d656e747320696e20494554462073657373696f6e732c2061732077656c6c2061732" + "07772697474656e20616e6420656c65" + "6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e7920" + "74696d65206f7220706c6163652c207" + "768696368206172652061646472657373656420746f", + "36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000", + "f3477e7cd95417af89a6b8794c310cf0"); + + TestPoly1305( + "2754776173206272696c6c69672c20616e642074686520736c6974687920746f766573" + "0a446964206779726520616e6420676" + "96d626c6520696e2074686520776162653a0a416c6c206d696d7379207765726520746" + "86520626f726f676f7665732c0a416e" + "6420746865206d6f6d65207261746873206f757467726162652e", + "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0", + "4541669a7eaaee61e708dc7cbcc5eb62"); + + TestPoly1305( + "ffffffffffffffffffffffffffffffff", + "0200000000000000000000000000000000000000000000000000000000000000", + "03000000000000000000000000000000"); + + TestPoly1305( + "02000000000000000000000000000000", + "02000000000000000000000000000000ffffffffffffffffffffffffffffffff", + "03000000000000000000000000000000"); + + TestPoly1305( + "fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff110000" + "00000000000000000000000000", + "0100000000000000000000000000000000000000000000000000000000000000", + "05000000000000000000000000000000"); + + TestPoly1305( + "fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe010101" + "01010101010101010101010101", + "0100000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000"); + + TestPoly1305( + "fdffffffffffffffffffffffffffffff", + "0200000000000000000000000000000000000000000000000000000000000000", + "faffffffffffffffffffffffffffffff"); + + TestPoly1305( + "e33594d7505e43b900000000000000003394d7505e4379cd0100000000000000000000" + "0000000000000000000000000001000000000000000000000000000000", + "0100000000000000040000000000000000000000000000000000000000000000", + "14000000000000005500000000000000"); + + TestPoly1305( + "e33594d7505e43b900000000000000003394d7505e4379cd0100000000000000000000" + "00000000000000000000000000", + "0100000000000000040000000000000000000000000000000000000000000000", + "13000000000000000000000000000000"); +} + BOOST_AUTO_TEST_CASE(countbits_tests) { FastRandomContext ctx; for (unsigned int i = 0; i <= 64; ++i) {