Skip to content

Commit

Permalink
Merge bitcoin#15519: Add Poly1305 implementation
Browse files Browse the repository at this point in the history
e9d5e97 Poly1305: tolerate the intentional unsigned wraparound in poly1305.cpp (Jonas Schnelli)
b34bf30 Add Poly1305 bench (Jonas Schnelli)
03be7f4 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 bitcoin#15512).

Tree-SHA512: f8c1ad2f686b980a7498ca50c517e2348ac7b1fe550565156f6c2b20faf764978e4fa6b5b1c3777a16e7a12e2eca3fb57a59be9c788b00d4358ee80f2959edb1
  • Loading branch information
laanwj authored and PastaPastaPasta committed Jul 23, 2019
1 parent db5f316 commit 4493671
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Expand Up @@ -374,6 +374,8 @@ crypto_libdash_crypto_a_SOURCES = \
crypto/hmac_sha256.h \
crypto/hmac_sha512.cpp \
crypto/hmac_sha512.h \
crypto/poly1305.h \
crypto/poly1305.cpp \
crypto/ripemd160.cpp \
crypto/aes_helper.c \
crypto/ripemd160.h \
Expand Down
1 change: 1 addition & 0 deletions src/Makefile.bench.include
Expand Up @@ -28,6 +28,7 @@ bench_bench_dash_SOURCES = \
bench/mempool_eviction.cpp \
bench/base58.cpp \
bench/lockedpool.cpp \
bench/poly1305.cpp \
bench/perf.cpp \
bench/perf.h \
bench/prevector_destructor.cpp \
Expand Down
41 changes: 41 additions & 0 deletions src/bench/poly1305.cpp
@@ -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 changes: 141 additions & 0 deletions src/crypto/poly1305.cpp
@@ -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 changes: 17 additions & 0 deletions 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 <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
82 changes: 82 additions & 0 deletions src/test/crypto_tests.cpp
Expand Up @@ -4,6 +4,7 @@

#include "crypto/aes.h"
#include "crypto/chacha20.h"
#include "crypto/poly1305.h"
#include "crypto/ripemd160.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
Expand Down Expand Up @@ -219,6 +220,17 @@ void TestChaCha20(const std::string &hex_message, const std::string &hexkey, uin
}
}

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);
}

std::string LongTestString(void) {
std::string ret;
for (int i=0; i<200000; i++) {
Expand Down Expand Up @@ -537,6 +549,76 @@ BOOST_AUTO_TEST_CASE(chacha20_testvector)
"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)
{
FastRandomContext ctx;
Expand Down

0 comments on commit 4493671

Please sign in to comment.