diff --git a/.gitignore b/.gitignore
index f7bcbd1459..367942103f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,6 +136,7 @@ test/lint/test_runner/target/
/doc/doxygen/
+libbitcoinconsensus.pc
contrib/devtools/split-debug.sh
# Output from running db4 installation
diff --git a/Makefile.am b/Makefile.am
index b746299a42..73f1f6c4ea 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,11 @@ endif
.PHONY: deploy FORCE
.INTERMEDIATE: $(COVERAGE_INFO)
+if BUILD_BITCOIN_LIBS
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libbitcoinconsensus.pc
+endif
+
BITCOIND_BIN=$(top_builddir)/src/$(BITCOIN_DAEMON_NAME)$(EXEEXT)
BITCOIN_QT_BIN=$(top_builddir)/src/qt/$(BITCOIN_GUI_NAME)$(EXEEXT)
BITCOIN_TEST_BIN=$(top_builddir)/src/test/$(BITCOIN_TEST_NAME)$(EXEEXT)
diff --git a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
index a34ef41d16..95fdcdb79b 100644
--- a/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
+++ b/build_msvc/libbitcoin_consensus/libbitcoin_consensus.vcxproj
@@ -15,6 +15,7 @@
+
diff --git a/ci/test/00_setup_env_native_previous_releases.sh b/ci/test/00_setup_env_native_previous_releases.sh
index 9da3b18999..3166686d9a 100755
--- a/ci/test/00_setup_env_native_previous_releases.sh
+++ b/ci/test/00_setup_env_native_previous_releases.sh
@@ -16,5 +16,5 @@ export RUN_UNIT_TESTS_SEQUENTIAL="true"
export RUN_UNIT_TESTS="false"
export GOAL="install"
export DOWNLOAD_PREVIOUS_RELEASES="true"
-export BITCOIN_CONFIG="--enable-zmq --with-gui=qt5 --enable-reduce-exports --enable-debug \
+export BITCOIN_CONFIG="--enable-zmq --with-libs=no --with-gui=qt5 --enable-reduce-exports --enable-debug \
CFLAGS=\"-g0 -O2 -funsigned-char\" CPPFLAGS='-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE' CXXFLAGS=\"-g0 -O2 -funsigned-char\""
diff --git a/configure.ac b/configure.ac
index d26d71f6cc..813958bff6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -602,6 +602,12 @@ AC_ARG_ENABLE([util-util],
build_bitcoin_chainstate=no
build_experimental_kernel_lib=no
+AC_ARG_WITH([libs],
+ [AS_HELP_STRING([--with-libs],
+ [build libraries (default=yes)])],
+ [build_bitcoin_libs=$withval],
+ [build_bitcoin_libs=yes])
+
AC_ARG_WITH([daemon],
[AS_HELP_STRING([--with-daemon],
[build bitcoind daemon (default=yes)])],
@@ -1194,6 +1200,7 @@ if test "$enable_fuzz" = "yes"; then
build_bitcoin_chainstate=no
build_bitcoin_wallet=no
build_bitcoind=no
+ build_bitcoin_libs=no
bitcoin_enable_qt=no
bitcoin_enable_qt_test=no
bitcoin_enable_qt_dbus=no
@@ -1378,7 +1385,7 @@ if test "$use_boost" = "yes"; then
dnl Check for Boost headers
AX_BOOST_BASE([1.73.0],[],[AC_MSG_ERROR([Boost is not available!])])
if test "$want_boost" = "no"; then
- AC_MSG_ERROR([Boost is required])
+ AC_MSG_ERROR([only libbitcoinconsensus can be built without Boost])
fi
dnl we don't use multi_index serialization
@@ -1554,8 +1561,18 @@ fi
AM_CONDITIONAL([BUILD_BITCOIN_CHAINSTATE], [test $build_bitcoin_chainstate = "yes"])
AC_MSG_RESULT($build_bitcoin_chainstate)
+AC_MSG_CHECKING([whether to build libraries])
+AM_CONDITIONAL([BUILD_BITCOIN_LIBS], [test $build_bitcoin_libs = "yes"])
+
+if test "$build_bitcoin_libs" = "yes"; then
+ AC_DEFINE([HAVE_CONSENSUS_LIB], [1], [Define this symbol if the consensus lib has been built])
+ AC_CONFIG_FILES([libbitcoinconsensus.pc:libbitcoinconsensus.pc.in])
+fi
+
AM_CONDITIONAL([BUILD_BITCOIN_KERNEL_LIB], [test "$build_experimental_kernel_lib" != "no" && ( test "$build_experimental_kernel_lib" = "yes" || test "$build_bitcoin_chainstate" = "yes" )])
+AC_MSG_RESULT($build_bitcoin_libs)
+
AC_LANG_POP
if test "$use_ccache" != "no"; then
@@ -1689,8 +1706,8 @@ else
AC_MSG_RESULT([no])
fi
-if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nonononononononono"; then
- AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests])
+if test "$build_bitcoin_wallet$build_bitcoin_cli$build_bitcoin_tx$build_bitcoin_util$build_bitcoin_libs$build_bitcoind$bitcoin_enable_qt$enable_fuzz_binary$use_bench$use_tests" = "nononononononononono"; then
+ AC_MSG_ERROR([No targets! Please specify at least one of: --with-utils --with-libs --with-daemon --with-gui --enable-fuzz(-binary) --enable-bench or --enable-tests])
fi
AM_CONDITIONAL([TARGET_DARWIN], [test "$TARGET_OS" = "darwin"])
@@ -1846,6 +1863,7 @@ echo
echo "Options used to compile and link:"
echo " external signer = $use_external_signer"
echo " multiprocess = $build_multiprocess"
+echo " with libs = $build_bitcoin_libs"
echo " with wallet = $enable_wallet"
if test "$enable_wallet" != "no"; then
echo " with sqlite = $use_sqlite"
diff --git a/doc/README.md b/doc/README.md
index 74a85b04e6..03f330a276 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -58,6 +58,7 @@ The Bitcoin repo's [root README](/README.md) contains relevant information on th
- [Translation Strings Policy](translation_strings_policy.md)
- [JSON-RPC Interface](JSON-RPC-interface.md)
- [Unauthenticated REST Interface](REST-interface.md)
+- [Shared Libraries](shared-libraries.md)
- [BIPS](bips.md)
- [Dnsseed Policy](dnsseed-policy.md)
- [Benchmarking](benchmarking.md)
diff --git a/doc/design/libraries.md b/doc/design/libraries.md
index caf414ac47..946ecee52c 100644
--- a/doc/design/libraries.md
+++ b/doc/design/libraries.md
@@ -4,10 +4,11 @@
|--------------------------|-------------|
| *libbitcoin_cli* | RPC client functionality used by *bitcoin-cli* executable |
| *libbitcoin_common* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_util*, but higher-level (see [Dependencies](#dependencies)). |
-| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet*. |
+| *libbitcoin_consensus* | Stable, backwards-compatible consensus functionality used by *libbitcoin_node* and *libbitcoin_wallet* and also exposed as a [shared library](../shared-libraries.md). |
+| *libbitcoinconsensus* | Shared library build of static *libbitcoin_consensus* library |
| *libbitcoin_crypto* | Hardware-optimized functions for data encryption, hashing, message authentication, and key derivation. |
-| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node*. |
-| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables. |
+| *libbitcoin_kernel* | Consensus engine and support library used for validation by *libbitcoin_node* and also exposed as a [shared library](../shared-libraries.md). |
+| *libbitcoinqt* | GUI functionality used by *bitcoin-qt* and *bitcoin-gui* executables |
| *libbitcoin_ipc* | IPC functionality used by *bitcoin-node*, *bitcoin-wallet*, *bitcoin-gui* executables to communicate when [`--enable-multiprocess`](multiprocess.md) is used. |
| *libbitcoin_node* | P2P and RPC server functionality used by *bitcoind* and *bitcoin-qt* executables. |
| *libbitcoin_util* | Home for common functionality shared by different executables and libraries. Similar to *libbitcoin_common*, but lower-level (see [Dependencies](#dependencies)). |
@@ -17,7 +18,7 @@
## Conventions
-- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. An exception is *libbitcoin_kernel*, which, at some future point, will have a documented external interface.
+- Most libraries are internal libraries and have APIs which are completely unstable! There are few or no restrictions on backwards compatibility or rules about external dependencies. Exceptions are *libbitcoin_consensus* and *libbitcoin_kernel* which have external interfaces documented at [../shared-libraries.md](../shared-libraries.md).
- Generally each library should have a corresponding source directory and namespace. Source code organization is a work in progress, so it is true that some namespaces are applied inconsistently, and if you look at [`libbitcoin_*_SOURCES`](../../src/Makefile.am) lists you can see that many libraries pull in files from outside their source directory. But when working with libraries, it is good to follow a consistent pattern like:
diff --git a/doc/shared-libraries.md b/doc/shared-libraries.md
new file mode 100644
index 0000000000..3a448c6556
--- /dev/null
+++ b/doc/shared-libraries.md
@@ -0,0 +1,78 @@
+Shared Libraries
+================
+
+## bitcoinconsensus
+***This library is deprecated and will be removed in v28***
+
+The purpose of this library is to make the verification functionality that is critical to Bitcoin's consensus available to other applications, e.g. to language bindings.
+
+### API
+
+The interface is defined in the C header `bitcoinconsensus.h` located in `src/script/bitcoinconsensus.h`.
+
+#### Version
+
+`bitcoinconsensus_version` returns an `unsigned int` with the API version *(currently `2`)*.
+
+#### Script Validation
+
+`bitcoinconsensus_verify_script`, `bitcoinconsensus_verify_script_with_amount` and `bitcoinconsensus_verify_script_with_spent_outputs` return an `int` with the status of the verification. It will be `1` if the input script correctly spends the previous output `scriptPubKey`.
+
+##### Parameters
+###### bitcoinconsensus_verify_script
+- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending.
+- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`.
+- `const unsigned char *txTo` - The transaction with the input that is spending the previous output.
+- `unsigned int txToLen` - The number of bytes for the `txTo`.
+- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`.
+- `unsigned int flags` - The script validation flags *(see below)*.
+- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*.
+
+###### bitcoinconsensus_verify_script_with_amount
+- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending.
+- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`.
+- `int64_t amount` - The amount spent in the input
+- `const unsigned char *txTo` - The transaction with the input that is spending the previous output.
+- `unsigned int txToLen` - The number of bytes for the `txTo`.
+- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`.
+- `unsigned int flags` - The script validation flags *(see below)*.
+- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*.
+
+###### bitcoinconsensus_verify_script_with_spent_outputs
+- `const unsigned char *scriptPubKey` - The previous output script that encumbers spending.
+- `unsigned int scriptPubKeyLen` - The number of bytes for the `scriptPubKey`.
+- `int64_t amount` - The amount spent in the input
+- `const unsigned char *txTo` - The transaction with the input that is spending the previous output.
+- `unsigned int txToLen` - The number of bytes for the `txTo`.
+- `UTXO *spentOutputs` - Previous outputs spent in the transaction. `UTXO` is a struct composed by `const unsigned char *scriptPubKey`, `unsigned int scriptPubKeySize` (the number of bytes for the `scriptPubKey`) and `unsigned int value`.
+- `unsigned int spentOutputsLen` - The number of bytes for the `spentOutputs`.
+- `unsigned int nIn` - The index of the input in `txTo` that spends the `scriptPubKey`.
+- `unsigned int flags` - The script validation flags *(see below)*.
+- `bitcoinconsensus_error* err` - Will have the error/success code for the operation *(see below)*.
+
+##### Script Flags
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE`
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH` - Evaluate P2SH ([BIP16](https://github.com/bitcoin/bips/blob/master/bip-0016.mediawiki)) subscripts
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG` - Enforce strict DER ([BIP66](https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki)) compliance
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY` - Enforce NULLDUMMY ([BIP147](https://github.com/bitcoin/bips/blob/master/bip-0147.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY` - Enable CHECKLOCKTIMEVERIFY ([BIP65](https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY` - Enable CHECKSEQUENCEVERIFY ([BIP112](https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS` - Enable WITNESS ([BIP141](https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki))
+- `bitcoinconsensus_SCRIPT_FLAGS_VERIFY_TAPROOT` - Enable TAPROOT ([BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki), [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki), [BIP342](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki))
+
+##### Errors
+- `bitcoinconsensus_ERR_OK` - No errors with input parameters *(see the return value of `bitcoinconsensus_verify_script` for the verification status)*
+- `bitcoinconsensus_ERR_TX_INDEX` - An invalid index for `txTo`
+- `bitcoinconsensus_ERR_TX_SIZE_MISMATCH` - `txToLen` did not match with the size of `txTo`
+- `bitcoinconsensus_ERR_DESERIALIZE` - An error deserializing `txTo`
+- `bitcoinconsensus_ERR_AMOUNT_REQUIRED` - Input amount is required if WITNESS is used
+- `bitcoinconsensus_ERR_INVALID_FLAGS` - Script verification `flags` are invalid (i.e. not part of the libconsensus interface)
+- `bitcoinconsensus_ERR_SPENT_OUTPUTS_REQUIRED` - Spent outputs are required if TAPROOT is used
+- `bitcoinconsensus_ERR_SPENT_OUTPUTS_MISMATCH` - Spent outputs size doesn't match tx inputs size
+
+### Example Implementations
+- [NBitcoin](https://github.com/MetacoSA/NBitcoin/blob/5e1055cd7c4186dee4227c344af8892aea54faec/NBitcoin/Script.cs#L979-#L1031) (.NET Bindings)
+- [node-libbitcoinconsensus](https://github.com/bitpay/node-libbitcoinconsensus) (Node.js Bindings)
+- [java-libbitcoinconsensus](https://github.com/dexX7/java-libbitcoinconsensus) (Java Bindings)
+- [bitcoinconsensus-php](https://github.com/Bit-Wasp/bitcoinconsensus-php) (PHP Bindings)
+- [rust-bitcoinconsensus](https://github.com/rust-bitcoin/rust-bitcoinconsensus) (Rust Bindings)
\ No newline at end of file
diff --git a/libbitcoinconsensus.pc.in b/libbitcoinconsensus.pc.in
new file mode 100644
index 0000000000..1ceab280bb
--- /dev/null
+++ b/libbitcoinconsensus.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @PACKAGE_NAME@ consensus library
+Description: Library for the Bitcoin consensus protocol.
+Version: @PACKAGE_VERSION@
+Libs: -L${libdir} -lbitcoinconsensus
+Cflags: -I${includedir}
diff --git a/src/Makefile.am b/src/Makefile.am
index c1af30d264..bf4dcf8996 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -43,6 +43,9 @@ endif
if ENABLE_ZMQ
LIBBITCOIN_ZMQ=libbitcoin_zmq.a
endif
+if BUILD_BITCOIN_LIBS
+LIBBITCOINCONSENSUS=libbitcoinconsensus.la
+endif
if BUILD_BITCOIN_KERNEL_LIB
LIBBITCOINKERNEL=libbitcoinkernel.la
endif
@@ -663,6 +666,7 @@ libbitcoin_consensus_a_SOURCES = \
primitives/transaction.h \
pubkey.cpp \
pubkey.h \
+ script/bitcoinconsensus.cpp \
script/interpreter.cpp \
script/interpreter.h \
script/script.cpp \
@@ -1009,6 +1013,21 @@ libbitcoinkernel_la-clientversion.l$(OBJEXT): obj/build.h
endif # BUILD_BITCOIN_KERNEL_LIB
#
+# bitcoinconsensus library #
+if BUILD_BITCOIN_LIBS
+lib_LTLIBRARIES += $(LIBBITCOINCONSENSUS)
+
+include_HEADERS = script/bitcoinconsensus.h
+libbitcoinconsensus_la_SOURCES = $(crypto_libbitcoin_crypto_base_la_SOURCES) $(libbitcoin_consensus_a_SOURCES)
+
+libbitcoinconsensus_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined $(RELDFLAGS)
+libbitcoinconsensus_la_LIBADD = $(LIBSECP256K1)
+libbitcoinconsensus_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(builddir)/obj $(libsecp256k1_CFLAGS) -DBUILD_BITCOIN_INTERNAL -DDISABLE_OPTIMIZED_SHA256
+libbitcoinconsensus_la_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
+
+endif
+#
+
CTAES_DIST = crypto/ctaes/bench.c
CTAES_DIST += crypto/ctaes/ctaes.c
CTAES_DIST += crypto/ctaes/ctaes.h
diff --git a/src/Makefile.test.include b/src/Makefile.test.include
index 233f1a1c21..7e6d24d913 100644
--- a/src/Makefile.test.include
+++ b/src/Makefile.test.include
@@ -376,6 +376,7 @@ test_fuzz_fuzz_SOURCES = \
test/fuzz/rpc.cpp \
test/fuzz/script.cpp \
test/fuzz/script_assets_test_minimizer.cpp \
+ test/fuzz/script_bitcoin_consensus.cpp \
test/fuzz/script_descriptor_cache.cpp \
test/fuzz/script_flags.cpp \
test/fuzz/script_format.cpp \
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
index f38aa49a23..81139feb47 100644
--- a/src/bench/verify_script.cpp
+++ b/src/bench/verify_script.cpp
@@ -2,8 +2,15 @@
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+#if defined(HAVE_CONFIG_H)
+#include
+#endif
+
#include
#include
+#if defined(HAVE_CONSENSUS_LIB)
+#include