Skip to content

Commit 3060e36

Browse files
committed
Add the RFC6979 PRNG
1 parent a8f5087 commit 3060e36

File tree

4 files changed

+121
-0
lines changed

4 files changed

+121
-0
lines changed

src/Makefile.am

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,14 @@ crypto_libbitcoin_crypto_a_SOURCES = \
206206
crypto/sha256.cpp \
207207
crypto/sha512.cpp \
208208
crypto/hmac_sha256.cpp \
209+
crypto/rfc6979_hmac_sha256.cpp \
209210
crypto/hmac_sha512.cpp \
210211
crypto/ripemd160.cpp \
211212
crypto/common.h \
212213
crypto/sha256.h \
213214
crypto/sha512.h \
214215
crypto/hmac_sha256.h \
216+
crypto/rfc6979_hmac_sha256.h \
215217
crypto/hmac_sha512.h \
216218
crypto/sha1.h \
217219
crypto/ripemd160.h

src/crypto/rfc6979_hmac_sha256.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright (c) 2014 The Bitcoin 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+
#include "crypto/rfc6979_hmac_sha256.h"
6+
7+
#include <string.h>
8+
9+
#include <algorithm>
10+
11+
static const unsigned char zero[1] = {0x00};
12+
static const unsigned char one[1] = {0x01};
13+
14+
RFC6979_HMAC_SHA256::RFC6979_HMAC_SHA256(const unsigned char* key, size_t keylen, const unsigned char* msg, size_t msglen) : retry(false)
15+
{
16+
memset(V, 0x01, sizeof(V));
17+
memset(K, 0x00, sizeof(K));
18+
19+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Write(zero, sizeof(zero)).Write(key, keylen).Write(msg, msglen).Finalize(K);
20+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V);
21+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Write(one, sizeof(one)).Write(key, keylen).Write(msg, msglen).Finalize(K);
22+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V);
23+
}
24+
25+
RFC6979_HMAC_SHA256::~RFC6979_HMAC_SHA256()
26+
{
27+
memset(V, 0x01, sizeof(V));
28+
memset(K, 0x00, sizeof(K));
29+
}
30+
31+
void RFC6979_HMAC_SHA256::Generate(unsigned char* output, size_t outputlen)
32+
{
33+
if (retry) {
34+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Write(zero, sizeof(zero)).Finalize(K);
35+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V);
36+
}
37+
38+
while (outputlen > 0) {
39+
CHMAC_SHA256(K, sizeof(K)).Write(V, sizeof(V)).Finalize(V);
40+
size_t len = std::min(outputlen, sizeof(V));
41+
memcpy(output, V, len);
42+
output += len;
43+
outputlen -= len;
44+
}
45+
46+
retry = true;
47+
}

src/crypto/rfc6979_hmac_sha256.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright (c) 2014 The Bitcoin 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_RFC6979_HMAC_SHA256_H
6+
#define BITCOIN_RFC6979_HMAC_SHA256_H
7+
8+
#include "crypto/hmac_sha256.h"
9+
10+
#include <stdint.h>
11+
#include <stdlib.h>
12+
13+
/** The RFC 6979 PRNG using HMAC-SHA256. */
14+
class RFC6979_HMAC_SHA256
15+
{
16+
private:
17+
unsigned char V[CHMAC_SHA256::OUTPUT_SIZE];
18+
unsigned char K[CHMAC_SHA256::OUTPUT_SIZE];
19+
bool retry;
20+
21+
public:
22+
/**
23+
* Construct a new RFC6979 PRNG, using the given key and message.
24+
* The message is assumed to be already hashed.
25+
*/
26+
RFC6979_HMAC_SHA256(const unsigned char* key, size_t keylen, const unsigned char* msg, size_t msglen);
27+
28+
/**
29+
* Generate a byte array.
30+
*/
31+
void Generate(unsigned char* output, size_t outputlen);
32+
33+
~RFC6979_HMAC_SHA256();
34+
};
35+
36+
#endif // BITCOIN_RFC6979_HMAC_SHA256_H

src/test/crypto_tests.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Distributed under the MIT/X11 software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

5+
#include "crypto/rfc6979_hmac_sha256.h"
56
#include "crypto/ripemd160.h"
67
#include "crypto/sha1.h"
78
#include "crypto/sha256.h"
@@ -13,6 +14,7 @@
1314

1415
#include <vector>
1516

17+
#include <boost/assign/list_of.hpp>
1618
#include <boost/test/unit_test.hpp>
1719

1820
BOOST_AUTO_TEST_SUITE(crypto_tests)
@@ -246,4 +248,38 @@ BOOST_AUTO_TEST_CASE(hmac_sha512_testvectors) {
246248
"b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58");
247249
}
248250

251+
void TestRFC6979(const std::string& hexkey, const std::string& hexmsg, const std::vector<std::string>& hexout)
252+
{
253+
std::vector<unsigned char> key = ParseHex(hexkey);
254+
std::vector<unsigned char> msg = ParseHex(hexmsg);
255+
RFC6979_HMAC_SHA256 rng(&key[0], key.size(), &msg[0], msg.size());
256+
257+
for (unsigned int i = 0; i < hexout.size(); i++) {
258+
std::vector<unsigned char> out = ParseHex(hexout[i]);
259+
std::vector<unsigned char> gen;
260+
gen.resize(out.size());
261+
rng.Generate(&gen[0], gen.size());
262+
BOOST_CHECK(out == gen);
263+
}
264+
}
265+
266+
BOOST_AUTO_TEST_CASE(rfc6979_hmac_sha256)
267+
{
268+
TestRFC6979(
269+
"0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f00",
270+
"4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a",
271+
boost::assign::list_of
272+
("4fe29525b2086809159acdf0506efb86b0ec932c7ba44256ab321e421e67e9fb")
273+
("2bf0fff1d3c378a22dc5de1d856522325c65b504491a0cbd01cb8f3aa67ffd4a")
274+
("f528b410cb541f77000d7afb6c5b53c5c471eab43e466d9ac5190c39c82fd82e"));
275+
276+
TestRFC6979(
277+
"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
278+
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
279+
boost::assign::list_of
280+
("9c236c165b82ae0cd590659e100b6bab3036e7ba8b06749baf6981e16f1a2b95")
281+
("df471061625bc0ea14b682feee2c9c02f235da04204c1d62a1536c6e17aed7a9")
282+
("7597887cbd76321f32e30440679a22cf7f8d9d2eac390e581fea091ce202ba94"));
283+
}
284+
249285
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)