Merge #15519: Add Poly1305 implementation

e9d5e97561 Poly1305: tolerate the intentional unsigned wraparound in poly1305.cpp (Jonas Schnelli)
b34bf302f2 Add Poly1305 bench (Jonas Schnelli)
03be7f48fa Add Poly1305 implementation (Jonas Schnelli)

Pull request description:

  This adds a currently unused Poly1305 implementation including test vectors from RFC7539.

  Required for BIP151 (and related to #15512).

Tree-SHA512: f8c1ad2f686b980a7498ca50c517e2348ac7b1fe550565156f6c2b20faf764978e4fa6b5b1c3777a16e7a12e2eca3fb57a59be9c788b00d4358ee80f2959edb1
This commit is contained in:
Wladimir J. van der Laan 2019-03-27 11:46:07 +01:00
commit 208406038c
No known key found for this signature in database
GPG key ID: 1E4AED62986CD25D
7 changed files with 285 additions and 0 deletions

View file

@ -346,6 +346,8 @@ crypto_libbitcoin_crypto_base_a_SOURCES = \
crypto/hmac_sha256.h \ crypto/hmac_sha256.h \
crypto/hmac_sha512.cpp \ crypto/hmac_sha512.cpp \
crypto/hmac_sha512.h \ crypto/hmac_sha512.h \
crypto/poly1305.h \
crypto/poly1305.cpp \
crypto/ripemd160.cpp \ crypto/ripemd160.cpp \
crypto/ripemd160.h \ crypto/ripemd160.h \
crypto/sha1.cpp \ crypto/sha1.cpp \

View file

@ -31,6 +31,7 @@ bench_bench_bitcoin_SOURCES = \
bench/base58.cpp \ bench/base58.cpp \
bench/bech32.cpp \ bench/bech32.cpp \
bench/lockedpool.cpp \ bench/lockedpool.cpp \
bench/poly1305.cpp \
bench/prevector.cpp bench/prevector.cpp
nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES) nodist_bench_bench_bitcoin_SOURCES = $(GENERATED_BENCH_FILES)

41
src/bench/poly1305.cpp Normal file
View file

@ -0,0 +1,41 @@
// 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 <iostream>
#include <bench/bench.h>
#include <crypto/poly1305.h>
/* 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<unsigned char> tag(POLY1305_TAGLEN, 0);
std::vector<unsigned char> key(POLY1305_KEYLEN, 0);
std::vector<unsigned char> 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);

141
src/crypto/poly1305.cpp Normal file
View file

@ -0,0 +1,141 @@
// 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 <crypto/common.h>
#include <crypto/poly1305.h>
#include <string.h>
#define mul32x32_64(a,b) ((uint64_t)(a) * (b))
void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen, const unsigned char 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;
unsigned char 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);
}

17
src/crypto/poly1305.h Normal file
View file

@ -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 <stdint.h>
#include <stdlib.h>
#define POLY1305_KEYLEN 32
#define POLY1305_TAGLEN 16
void poly1305_auth(unsigned char out[POLY1305_TAGLEN], const unsigned char *m, size_t inlen,
const unsigned char key[POLY1305_KEYLEN]);
#endif // BITCOIN_CRYPTO_POLY1305_H

View file

@ -4,6 +4,7 @@
#include <crypto/aes.h> #include <crypto/aes.h>
#include <crypto/chacha20.h> #include <crypto/chacha20.h>
#include <crypto/poly1305.h>
#include <crypto/ripemd160.h> #include <crypto/ripemd160.h>
#include <crypto/sha1.h> #include <crypto/sha1.h>
#include <crypto/sha256.h> #include <crypto/sha256.h>
@ -200,6 +201,17 @@ static void TestChaCha20(const std::string &hexkey, uint64_t nonce, uint64_t see
BOOST_CHECK(out == outres); BOOST_CHECK(out == outres);
} }
static void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag)
{
std::vector<unsigned char> key = ParseHex(hexkey);
std::vector<unsigned char> m = ParseHex(hexmessage);
std::vector<unsigned char> tag = ParseHex(hextag);
std::vector<unsigned char> tagres;
tagres.resize(POLY1305_TAGLEN);
poly1305_auth(tagres.data(), m.data(), m.size(), key.data());
BOOST_CHECK(tag == tagres);
}
static std::string LongTestString() { static std::string LongTestString() {
std::string ret; std::string ret;
for (int i=0; i<200000; i++) { for (int i=0; i<200000; i++) {
@ -524,6 +536,76 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
"fab78c9"); "fab78c9");
} }
BOOST_AUTO_TEST_CASE(poly1305_testvector)
{
// RFC 7539, section 2.5.2.
TestPoly1305("43727970746f6772617068696320466f72756d2052657365617263682047726f7570",
"85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b",
"a8061dc1305136c6c22b8baf0c0127a9");
// RFC 7539, section A.3.
TestPoly1305("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
"000000000000000000000000000",
"0000000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000");
TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
"5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
"726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
"520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
"4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
"56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
"6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
"768696368206172652061646472657373656420746f",
"0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e",
"36e5f6b5c5e06070f0efca96227a863e");
TestPoly1305("416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e747269627"
"5746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465"
"726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686"
"520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e2022494554"
"4620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c20737461746"
"56d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c65"
"6374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207"
"768696368206172652061646472657373656420746f",
"36e5f6b5c5e06070f0efca96227a863e00000000000000000000000000000000",
"f3477e7cd95417af89a6b8794c310cf0");
TestPoly1305("2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e6420676"
"96d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e"
"6420746865206d6f6d65207261746873206f757467726162652e",
"1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
"4541669a7eaaee61e708dc7cbcc5eb62");
TestPoly1305("ffffffffffffffffffffffffffffffff",
"0200000000000000000000000000000000000000000000000000000000000000",
"03000000000000000000000000000000");
TestPoly1305("02000000000000000000000000000000",
"02000000000000000000000000000000ffffffffffffffffffffffffffffffff",
"03000000000000000000000000000000");
TestPoly1305("fffffffffffffffffffffffffffffffff0ffffffffffffffffffffffffffffff11000000000000000000000000000000",
"0100000000000000000000000000000000000000000000000000000000000000",
"05000000000000000000000000000000");
TestPoly1305("fffffffffffffffffffffffffffffffffbfefefefefefefefefefefefefefefe01010101010101010101010101010101",
"0100000000000000000000000000000000000000000000000000000000000000",
"00000000000000000000000000000000");
TestPoly1305("fdffffffffffffffffffffffffffffff",
"0200000000000000000000000000000000000000000000000000000000000000",
"faffffffffffffffffffffffffffffff");
TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd01000000000000000000000000000000000000000000000001000000000000000000000000000000",
"0100000000000000040000000000000000000000000000000000000000000000",
"14000000000000005500000000000000");
TestPoly1305("e33594d7505e43b900000000000000003394d7505e4379cd010000000000000000000000000000000000000000000000",
"0100000000000000040000000000000000000000000000000000000000000000",
"13000000000000000000000000000000");
}
BOOST_AUTO_TEST_CASE(countbits_tests) BOOST_AUTO_TEST_CASE(countbits_tests)
{ {
FastRandomContext ctx; FastRandomContext ctx;

View file

@ -15,6 +15,7 @@ unsigned-integer-overflow:coded_stream.h
unsigned-integer-overflow:core_write.cpp unsigned-integer-overflow:core_write.cpp
unsigned-integer-overflow:crypto/chacha20.cpp unsigned-integer-overflow:crypto/chacha20.cpp
unsigned-integer-overflow:crypto/ctaes/ctaes.c unsigned-integer-overflow:crypto/ctaes/ctaes.c
unsigned-integer-overflow:crypto/poly1305.cpp
unsigned-integer-overflow:crypto/ripemd160.cpp unsigned-integer-overflow:crypto/ripemd160.cpp
unsigned-integer-overflow:crypto/sha1.cpp unsigned-integer-overflow:crypto/sha1.cpp
unsigned-integer-overflow:crypto/sha256.cpp unsigned-integer-overflow:crypto/sha256.cpp