aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/pubkey.cpp12
-rw-r--r--src/pubkey.h5
-rw-r--r--src/test/fuzz/miniscript.cpp5
-rw-r--r--src/test/key_tests.cpp10
-rw-r--r--src/test/miniscript_tests.cpp5
-rw-r--r--src/test/script_tests.cpp3
-rwxr-xr-xtest/functional/feature_framework_unit_tests.py1
-rw-r--r--test/functional/test_framework/crypto/secp256k1.py8
8 files changed, 39 insertions, 10 deletions
diff --git a/src/pubkey.cpp b/src/pubkey.cpp
index 11e1b4abb5..13e3c2dbe0 100644
--- a/src/pubkey.cpp
+++ b/src/pubkey.cpp
@@ -13,6 +13,7 @@
#include <secp256k1_schnorrsig.h>
#include <span.h>
#include <uint256.h>
+#include <util/strencodings.h>
#include <algorithm>
#include <cassert>
@@ -181,6 +182,17 @@ int ecdsa_signature_parse_der_lax(secp256k1_ecdsa_signature* sig, const unsigned
return 1;
}
+/** Nothing Up My Sleeve (NUMS) point
+ *
+ * NUMS_H is a point with an unknown discrete logarithm, constructed by taking the sha256 of 'g'
+ * (uncompressed encoding), which happens to be a point on the curve.
+ *
+ * For an example script for calculating H, refer to the unit tests in
+ * ./test/functional/test_framework/crypto/secp256k1.py
+ */
+static const std::vector<unsigned char> NUMS_H_DATA{ParseHex("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")};
+const XOnlyPubKey XOnlyPubKey::NUMS_H{NUMS_H_DATA};
+
XOnlyPubKey::XOnlyPubKey(Span<const unsigned char> bytes)
{
assert(bytes.size() == 32);
diff --git a/src/pubkey.h b/src/pubkey.h
index 15d7e7bc07..ae34ddd0af 100644
--- a/src/pubkey.h
+++ b/src/pubkey.h
@@ -233,6 +233,11 @@ private:
uint256 m_keydata;
public:
+ /** Nothing Up My Sleeve point H
+ * Used as an internal key for provably disabling the key path spend
+ * see BIP341 for more details */
+ static const XOnlyPubKey NUMS_H;
+
/** Construct an empty x-only pubkey. */
XOnlyPubKey() = default;
diff --git a/src/test/fuzz/miniscript.cpp b/src/test/fuzz/miniscript.cpp
index f10007222c..7e71af7c44 100644
--- a/src/test/fuzz/miniscript.cpp
+++ b/src/test/fuzz/miniscript.cpp
@@ -309,9 +309,6 @@ const struct KeyComparator {
// A dummy scriptsig to pass to VerifyScript (we always use Segwit v0).
const CScript DUMMY_SCRIPTSIG;
-//! Public key to be used as internal key for dummy Taproot spends.
-const std::vector<unsigned char> NUMS_PK{ParseHex("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")};
-
//! Construct a miniscript node as a shared_ptr.
template<typename... Args> NodeRef MakeNodeRef(Args&&... args) {
return miniscript::MakeNodeRef<CPubKey>(miniscript::internal::NoDupCheck{}, std::forward<Args>(args)...);
@@ -1018,7 +1015,7 @@ CScript ScriptPubKey(MsCtx ctx, const CScript& script, TaprootBuilder& builder)
// For Taproot outputs we always use a tree with a single script and a dummy internal key.
builder.Add(0, script, TAPROOT_LEAF_TAPSCRIPT);
- builder.Finalize(XOnlyPubKey{NUMS_PK});
+ builder.Finalize(XOnlyPubKey::NUMS_H);
return GetScriptForDestination(builder.GetOutput());
}
diff --git a/src/test/key_tests.cpp b/src/test/key_tests.cpp
index 86a8d17a76..aaf4ca4977 100644
--- a/src/test/key_tests.cpp
+++ b/src/test/key_tests.cpp
@@ -6,6 +6,7 @@
#include <common/system.h>
#include <key_io.h>
+#include <span.h>
#include <streams.h>
#include <test/util/random.h>
#include <test/util/setup_common.h>
@@ -364,4 +365,13 @@ BOOST_AUTO_TEST_CASE(key_ellswift)
}
}
+BOOST_AUTO_TEST_CASE(bip341_test_h)
+{
+ std::vector<unsigned char> G_uncompressed = ParseHex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8");
+ HashWriter hw;
+ hw.write(MakeByteSpan(G_uncompressed));
+ XOnlyPubKey H{hw.GetSHA256()};
+ BOOST_CHECK(XOnlyPubKey::NUMS_H == H);
+}
+
BOOST_AUTO_TEST_SUITE_END()
diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp
index a3699f84b6..7e39e9e4de 100644
--- a/src/test/miniscript_tests.cpp
+++ b/src/test/miniscript_tests.cpp
@@ -288,9 +288,6 @@ public:
}
};
-//! Public key to be used as internal key for dummy Taproot spends.
-const std::vector<unsigned char> NUMS_PK{ParseHex("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")};
-
using Fragment = miniscript::Fragment;
using NodeRef = miniscript::NodeRef<CPubKey>;
using miniscript::operator"" _mst;
@@ -330,7 +327,7 @@ CScript ScriptPubKey(miniscript::MiniscriptContext ctx, const CScript& script, T
// For Taproot outputs we always use a tree with a single script and a dummy internal key.
builder.Add(0, script, TAPROOT_LEAF_TAPSCRIPT);
- builder.Finalize(XOnlyPubKey{NUMS_PK});
+ builder.Finalize(XOnlyPubKey::NUMS_H);
return GetScriptForDestination(builder.GetOutput());
}
diff --git a/src/test/script_tests.cpp b/src/test/script_tests.cpp
index e4142e203c..314b26609c 100644
--- a/src/test/script_tests.cpp
+++ b/src/test/script_tests.cpp
@@ -1268,8 +1268,7 @@ BOOST_AUTO_TEST_CASE(sign_invalid_miniscript)
const auto invalid_pubkey{ParseHex("173d36c8c9c9c9ffffffffffff0200000000021e1e37373721361818181818181e1e1e1e19000000000000000000b19292929292926b006c9b9b9292")};
TaprootBuilder builder;
builder.Add(0, {invalid_pubkey}, 0xc0);
- XOnlyPubKey nums{ParseHex("50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")};
- builder.Finalize(nums);
+ builder.Finalize(XOnlyPubKey::NUMS_H);
prev.vout.emplace_back(0, GetScriptForDestination(builder.GetOutput()));
curr.vin.emplace_back(COutPoint{prev.GetHash(), 0});
sig_data.tr_spenddata = builder.GetSpendData();
diff --git a/test/functional/feature_framework_unit_tests.py b/test/functional/feature_framework_unit_tests.py
index c9754e083c..f03f084bed 100755
--- a/test/functional/feature_framework_unit_tests.py
+++ b/test/functional/feature_framework_unit_tests.py
@@ -25,6 +25,7 @@ TEST_FRAMEWORK_MODULES = [
"crypto.muhash",
"crypto.poly1305",
"crypto.ripemd160",
+ "crypto.secp256k1",
"script",
"segwit_addr",
"wallet_util",
diff --git a/test/functional/test_framework/crypto/secp256k1.py b/test/functional/test_framework/crypto/secp256k1.py
index 2e9e419da5..50a46dce37 100644
--- a/test/functional/test_framework/crypto/secp256k1.py
+++ b/test/functional/test_framework/crypto/secp256k1.py
@@ -15,6 +15,8 @@ Exports:
* G: the secp256k1 generator point
"""
+import unittest
+from hashlib import sha256
class FE:
"""Objects of this class represent elements of the field GF(2**256 - 2**32 - 977).
@@ -344,3 +346,9 @@ class FastGEMul:
# Precomputed table with multiples of G for fast multiplication
FAST_G = FastGEMul(G)
+
+class TestFrameworkSecp256k1(unittest.TestCase):
+ def test_H(self):
+ H = sha256(G.to_bytes_uncompressed()).digest()
+ assert GE.lift_x(FE.from_bytes(H)) is not None
+ self.assertEqual(H.hex(), "50929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0")