diff --git a/src/Makefile.test.include b/src/Makefile.test.include index f7668d804b..2f9d9e9aaa 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -39,6 +39,7 @@ BITCOIN_TESTS =\ test/base58_tests.cpp \ test/base64_tests.cpp \ test/bech32_tests.cpp \ + test/blech32_tests.cpp \ test/bip32_tests.cpp \ test/blockchain_tests.cpp \ test/blockencodings_tests.cpp \ diff --git a/src/bech32.cpp b/src/bech32.cpp index d6b29391a9..7a83866e80 100644 --- a/src/bech32.cpp +++ b/src/bech32.cpp @@ -4,7 +4,7 @@ #include -namespace +namespace bech32 { typedef std::vector data; @@ -138,11 +138,6 @@ data CreateChecksum(const std::string& hrp, const data& values) return ret; } -} // namespace - -namespace bech32 -{ - /** Encode a Bech32 string. */ std::string Encode(const std::string& hrp, const data& values) { data checksum = CreateChecksum(hrp, values); diff --git a/src/bech32.h b/src/bech32.h index 2e2823e974..ea17ad0072 100644 --- a/src/bech32.h +++ b/src/bech32.h @@ -25,6 +25,9 @@ std::string Encode(const std::string& hrp, const std::vector& values); /** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */ std::pair> Decode(const std::string& str); +/// Exported for testing. +uint32_t PolyMod(const std::vector& v); + } // namespace bech32 #endif // BITCOIN_BECH32_H diff --git a/src/blech32.cpp b/src/blech32.cpp index 8acd4f0a1f..38c1941fdc 100644 --- a/src/blech32.cpp +++ b/src/blech32.cpp @@ -11,7 +11,7 @@ * TODO: Update comments */ -namespace +namespace blech32 { typedef std::vector data; @@ -41,7 +41,7 @@ data Cat(data x, const data& y) /** This function will compute what 6 5-bit values to XOR into the last 6 input values, in order to * make the checksum 0. These 6 values are packed together in a single 30-bit integer. The higher * bits correspond to earlier values. */ -uint32_t PolyMod(const data& v) +uint64_t PolyMod(const data& v) { // The input is interpreted as a list of coefficients of a polynomial over F = GF(32), with an // implicit 1 in front. If the input is [v0,v1,v2,v3,v4], that polynomial is v(x) = @@ -136,7 +136,7 @@ data CreateChecksum(const std::string& hrp, const data& values) { data enc = Cat(ExpandHRP(hrp), values); enc.resize(enc.size() + 12); // ELEMENTS: Append 6->12 zeroes - uint32_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes. + uint64_t mod = PolyMod(enc) ^ 1; // Determine what to XOR into those 6 zeroes. data ret(12); // ELEMENTS: 6->12 for (size_t i = 0; i < 12; ++i) { // ELEMENTS: 6->12 // Convert the 5-bit groups in mod to checksum values. @@ -145,11 +145,6 @@ data CreateChecksum(const std::string& hrp, const data& values) return ret; } -} // namespace - -namespace blech32 -{ - /** Encode a Blech32 string. */ std::string Encode(const std::string& hrp, const data& values) { data checksum = CreateChecksum(hrp, values); diff --git a/src/blech32.h b/src/blech32.h index cfe907581e..775c207e66 100644 --- a/src/blech32.h +++ b/src/blech32.h @@ -25,6 +25,11 @@ std::string Encode(const std::string& hrp, const std::vector& values); /** Decode a Bech32 string. Returns (hrp, data). Empty hrp means failure. */ std::pair> Decode(const std::string& str); +/// Exported for testing. +uint64_t PolyMod(const std::vector& v); +/// Exported for testing. +std::vector CreateChecksum(const std::string& hrp, const std::vector& values); + } // namespace blech32 #endif // BITCOIN_BLECH32_H diff --git a/src/test/bech32_tests.cpp b/src/test/bech32_tests.cpp index 6ecc9ac705..caad8fa593 100644 --- a/src/test/bech32_tests.cpp +++ b/src/test/bech32_tests.cpp @@ -66,4 +66,22 @@ BOOST_AUTO_TEST_CASE(bip173_testvectors_invalid) } } +BOOST_AUTO_TEST_CASE(bech32_polymod_sanity) +{ + std::vector data(40); + GetRandBytes(data.data(), data.size()); + + std::vector base32; + ConvertBits<8, 5, true>([&](unsigned char c) { base32.push_back(c); }, data.begin(), data.end()); + uint64_t plm1 = bech32::PolyMod(base32); + + // Now add 1023 zeros. + for (auto i = 0; i < 1023; i++) { + base32.push_back(0); + } + uint64_t plm2 = bech32::PolyMod(base32); + + BOOST_CHECK_EQUAL(plm1, plm2); +} + BOOST_AUTO_TEST_SUITE_END() diff --git a/src/test/blech32_tests.cpp b/src/test/blech32_tests.cpp new file mode 100644 index 0000000000..a175a9c074 --- /dev/null +++ b/src/test/blech32_tests.cpp @@ -0,0 +1,46 @@ +// Copyright (c) 2017 Pieter Wuille +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include +#include +#include +#include + +#include + +BOOST_FIXTURE_TEST_SUITE(blech32_tests, BasicTestingSetup) + +BOOST_AUTO_TEST_CASE(blech32_polymod_sanity) +{ + std::vector data(40); + GetRandBytes(data.data(), data.size()); + + std::vector base32; + ConvertBits<8, 5, true>([&](unsigned char c) { base32.push_back(c); }, data.begin(), data.end()); + uint64_t plm1 = blech32::PolyMod(base32); + + // Now add 1023 zeros. + for (auto i = 0; i < 1023; i++) { + base32.push_back(0); + } + uint64_t plm2 = blech32::PolyMod(base32); + + BOOST_CHECK_EQUAL(plm1, plm2); +} + +BOOST_AUTO_TEST_CASE(blech32_checksum) +{ + std::vector vector{7,2,3,4,5,6,7,8,9,234,123,213,16}; + std::vector b32; + ConvertBits<8, 5, true>([&](unsigned char c) { b32.push_back(c); }, vector.begin(), vector.end()); + std::vector cs = blech32::CreateChecksum("lq", b32); + + std::vector expected_cs{22,13,13,5,4,4,23,7,28,21,30,12}; + for (size_t i = 0; i < expected_cs.size(); i++) { + BOOST_CHECK_EQUAL(expected_cs[i], cs[i]); + } +} + +BOOST_AUTO_TEST_SUITE_END() +