Skip to content

Commit a0b9fab

Browse files
authored
Merge pull request #7 from jbride/p2tsh-pqc
BIP360: P2TSH & PQC functionality
2 parents d1b5831 + ed3e0ff commit a0b9fab

495 files changed

Lines changed: 44335 additions & 34 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ target/
2626
/guix-build-*
2727

2828
/ci/scratch/
29+
30+
libbitcoinpqc

src/CMakeLists.txt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,25 @@ set_target_properties(secp256k1 PROPERTIES
7272
)
7373
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
7474

75+
#=============================
76+
# libbitcoinpqc subtree
77+
#=============================
78+
message("")
79+
message("Configuring libbitcoinpqc subtree...")
80+
81+
# Configure libbitcoinpqc build options
82+
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
83+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
84+
85+
# Add the libbitcoinpqc subdirectory
86+
add_subdirectory(libbitcoinpqc)
87+
88+
# Set target properties
89+
# Note: EXCLUDE_FROM_ALL removed to ensure bitcoinpqc is built when needed
90+
91+
# Add libbitcoinpqc include directories to the main include path
92+
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libbitcoinpqc/include)
93+
7594
# Set top-level target output locations.
7695
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
7796
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
@@ -117,11 +136,13 @@ add_library(bitcoin_consensus STATIC EXCLUDE_FROM_ALL
117136
script/script_error.cpp
118137
uint256.cpp
119138
)
139+
120140
target_link_libraries(bitcoin_consensus
121141
PRIVATE
122142
core_interface
123143
bitcoin_crypto
124144
secp256k1
145+
bitcoinpqc
125146
)
126147

127148
if(WITH_ZMQ)

src/addresstype.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
4646
CSHA256().Write(in.data(), in.size()).Finalize(begin());
4747
}
4848

49+
WitnessV2P2TSH::WitnessV2P2TSH(const CScript& in)
50+
{
51+
CSHA256().Write(in.data(), in.size()).Finalize(begin());
52+
}
53+
4954
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
5055
{
5156
std::vector<valtype> vSolutions;
@@ -87,6 +92,12 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
8792
addressRet = tap;
8893
return true;
8994
}
95+
case TxoutType::WITNESS_V2_P2TSH: {
96+
WitnessV2P2TSH p2tsh;
97+
std::copy(vSolutions[0].begin(), vSolutions[0].end(), p2tsh.begin());
98+
addressRet = p2tsh;
99+
return true;
100+
}
90101
case TxoutType::ANCHOR: {
91102
addressRet = PayToAnchor();
92103
return true;
@@ -147,6 +158,12 @@ class CScriptVisitor
147158
{
148159
return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram();
149160
}
161+
162+
CScript operator()(const WitnessV2P2TSH& id) const
163+
{
164+
// P2TSH is version 2
165+
return CScript() << CScript::EncodeOP_N(2) << ToByteVector(id);
166+
}
150167
};
151168

152169
class ValidDestinationVisitor
@@ -160,6 +177,7 @@ class ValidDestinationVisitor
160177
bool operator()(const WitnessV0ScriptHash& dest) const { return true; }
161178
bool operator()(const WitnessV1Taproot& dest) const { return true; }
162179
bool operator()(const WitnessUnknown& dest) const { return true; }
180+
bool operator()(const WitnessV2P2TSH& dest) const { return true; }
163181
};
164182
} // namespace
165183

src/addresstype.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ struct WitnessV1Taproot : public XOnlyPubKey
9191
explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
9292
};
9393

94+
struct WitnessV2P2TSH : public BaseHash<uint256>
95+
{
96+
WitnessV2P2TSH() : BaseHash() {}
97+
explicit WitnessV2P2TSH(const uint256& hash) : BaseHash(hash) {}
98+
explicit WitnessV2P2TSH(const CScript& script);
99+
};
100+
94101
//! CTxDestination subtype to encode any future Witness version
95102
struct WitnessUnknown
96103
{
@@ -138,9 +145,10 @@ struct PayToAnchor : public WitnessUnknown
138145
* * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR address)
139146
* * PayToAnchor: TxoutType::ANCHOR destination (P2A address)
140147
* * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W??? address)
148+
* * WitnessV2P2TSH: TxoutType::WITNESS_V2_P2TSH destination (P2TSH address)
141149
* A CTxDestination is the internal data type encoded in a bitcoin address
142150
*/
143-
using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown>;
151+
using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown, WitnessV2P2TSH>;
144152

145153
/** Check whether a CTxDestination corresponds to one with an address. */
146154
bool IsValidDestination(const CTxDestination& dest);

src/key_io.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,14 @@ class DestinationEncoder
7777
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
7878
}
7979

80+
std::string operator()(const WitnessV2P2TSH& id) const
81+
{
82+
std::vector<unsigned char> data = {2}; // Version 2
83+
data.reserve(53); // Reserve space for the hash
84+
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
85+
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
86+
}
87+
8088
std::string operator()(const CNoDestination& no) const { return {}; }
8189
std::string operator()(const PubKeyDestination& pk) const { return {}; }
8290
};
@@ -181,6 +189,16 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
181189
return tap;
182190
}
183191

192+
if (version == 2 && data.size() == WITNESS_V2_P2TSH_SIZE) {
193+
WitnessV2P2TSH tsh;
194+
if (data.size() == tsh.size()) {
195+
std::copy(data.begin(), data.end(), tsh.begin());
196+
return tsh;
197+
}
198+
error_str = strprintf("Invalid P2TSH address program size (%d %s)", data.size(), byte_str);
199+
return CNoDestination();
200+
}
201+
184202
if (CScript::IsPayToAnchor(version, data)) {
185203
return PayToAnchor();
186204
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
name: Rust CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
env:
10+
CARGO_TERM_COLOR: always
11+
12+
jobs:
13+
test:
14+
name: Test
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v3
18+
19+
- name: Install dependencies
20+
run: |
21+
sudo apt-get update
22+
sudo apt-get install -y build-essential cmake libssl-dev
23+
24+
- name: Install Rust
25+
uses: dtolnay/rust-toolchain@stable
26+
with:
27+
components: clippy, rustfmt
28+
29+
- name: Cache dependencies
30+
uses: Swatinem/rust-cache@v2
31+
32+
- name: Check code format
33+
run: cargo fmt -- --check
34+
35+
- name: Clippy
36+
run: cargo clippy -- -D warnings
37+
38+
- name: Build
39+
run: cargo build --verbose
40+
41+
- name: Run tests
42+
run: cargo test --verbose
43+
44+
build-matrix:
45+
name: Build on ${{ matrix.os }}
46+
runs-on: ${{ matrix.os }}
47+
strategy:
48+
matrix:
49+
os: [ubuntu-latest]
50+
# os: [ubuntu-latest, macos-latest]
51+
rust: [stable]
52+
fail-fast: false
53+
steps:
54+
- uses: actions/checkout@v3
55+
56+
- name: Install dependencies (Ubuntu)
57+
if: matrix.os == 'ubuntu-latest'
58+
run: |
59+
sudo apt-get update
60+
sudo apt-get install -y build-essential cmake libssl-dev
61+
62+
- name: Install dependencies (macOS)
63+
if: matrix.os == 'macos-latest'
64+
run: |
65+
brew install cmake
66+
67+
- name: Install Rust
68+
uses: dtolnay/rust-toolchain@stable
69+
with:
70+
toolchain: ${{ matrix.rust }}
71+
components: clippy, rustfmt
72+
73+
- name: Cache dependencies
74+
uses: Swatinem/rust-cache@v2
75+
76+
- name: Check code format
77+
run: cargo fmt -- --check
78+
79+
- name: Clippy
80+
run: cargo clippy -- -D warnings
81+
82+
- name: Build
83+
run: cargo build --verbose
84+
85+
- name: Run tests
86+
run: cargo test --verbose
87+
88+
# benchmark:
89+
# name: Benchmark
90+
# runs-on: ubuntu-latest
91+
# needs: test
92+
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
93+
# steps:
94+
# - uses: actions/checkout@v3
95+
96+
# - name: Install dependencies
97+
# run: |
98+
# sudo apt-get update
99+
# sudo apt-get install -y build-essential cmake libssl-dev
100+
101+
# - name: Install Rust
102+
# uses: dtolnay/rust-toolchain@stable
103+
104+
# - name: Cache dependencies
105+
# uses: Swatinem/rust-cache@v2
106+
107+
# - name: Run benchmarks
108+
# run: cargo bench

src/libbitcoinpqc/.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
build/
2+
dist/
3+
*.o
4+
benchmark_results.txt
5+
__pycache__
6+
python/build/
7+
*.egg-info/
8+
node_modules/
9+
**.gcno
10+
**.lcov
11+
**/target/
12+
tags
13+
TAGS
14+
rust-toolchain.toml
15+
Cargo.lock
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"rust-analyzer.cargo.features": ["ide"],
3+
"editor.formatOnSave": true,
4+
"rust-analyzer.check.command": "clippy",
5+
"rust-analyzer.check.extraArgs": ["--all-targets"]
6+
}

src/libbitcoinpqc/CMakeLists.txt

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project(libbitcoinpqc C)
3+
4+
set(CMAKE_C_STANDARD 99)
5+
set(CMAKE_C_STANDARD_REQUIRED ON)
6+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
7+
8+
# Set version
9+
set(BITCOINPQC_VERSION_MAJOR 0)
10+
set(BITCOINPQC_VERSION_MINOR 1)
11+
set(BITCOINPQC_VERSION_PATCH 0)
12+
13+
# Library output settings
14+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
15+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
16+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
17+
18+
# Include directories
19+
include_directories(
20+
${CMAKE_CURRENT_SOURCE_DIR}/include
21+
${CMAKE_CURRENT_SOURCE_DIR}/dilithium/ref
22+
${CMAKE_CURRENT_SOURCE_DIR}/sphincsplus/ref
23+
)
24+
25+
# Custom randombytes implementation
26+
set(CUSTOM_RANDOMBYTES
27+
dilithium/ref/randombytes_custom.c
28+
sphincsplus/ref/randombytes_custom.c
29+
)
30+
31+
# ML-DSA-44 (Dilithium) source files
32+
set(ML_DSA_SOURCES
33+
dilithium/ref/sign.c
34+
dilithium/ref/packing.c
35+
dilithium/ref/polyvec.c
36+
dilithium/ref/poly.c
37+
dilithium/ref/ntt.c
38+
dilithium/ref/reduce.c
39+
dilithium/ref/rounding.c
40+
dilithium/ref/fips202.c
41+
dilithium/ref/symmetric-shake.c
42+
)
43+
44+
# SLH-DSA-Shake-128s (SPHINCS+) source files
45+
set(SLH_DSA_SOURCES
46+
sphincsplus/ref/address.c
47+
sphincsplus/ref/fors.c
48+
sphincsplus/ref/hash_shake.c
49+
sphincsplus/ref/merkle.c
50+
sphincsplus/ref/sign.c
51+
sphincsplus/ref/thash_shake_simple.c
52+
sphincsplus/ref/utils.c
53+
sphincsplus/ref/utilsx1.c
54+
sphincsplus/ref/wots.c
55+
sphincsplus/ref/wotsx1.c
56+
sphincsplus/ref/fips202.c
57+
)
58+
59+
# libbitcoinpqc source files
60+
set(BITCOINPQC_SOURCES
61+
src/bitcoinpqc.c
62+
src/ml_dsa/utils.c
63+
src/ml_dsa/keygen.c
64+
src/ml_dsa/sign.c
65+
src/ml_dsa/verify.c
66+
src/slh_dsa/utils.c
67+
src/slh_dsa/keygen.c
68+
src/slh_dsa/sign.c
69+
src/slh_dsa/verify.c
70+
)
71+
72+
# Define the main library target
73+
add_library(bitcoinpqc STATIC
74+
${BITCOINPQC_SOURCES}
75+
${ML_DSA_SOURCES}
76+
${SLH_DSA_SOURCES}
77+
${CUSTOM_RANDOMBYTES}
78+
)
79+
80+
# Set include directories for the library
81+
target_include_directories(bitcoinpqc PUBLIC
82+
${CMAKE_CURRENT_SOURCE_DIR}/include
83+
)
84+
85+
# Set compile definitions for the library
86+
target_compile_definitions(bitcoinpqc PRIVATE
87+
DILITHIUM_MODE=2 # ML-DSA-44 (Dilithium2)
88+
PARAMS=sphincs-shake-128s
89+
CUSTOM_RANDOMBYTES=1
90+
)
91+
92+
# Configure install paths
93+
install(TARGETS bitcoinpqc
94+
ARCHIVE DESTINATION lib
95+
LIBRARY DESTINATION lib
96+
RUNTIME DESTINATION bin
97+
)
98+
99+
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
100+
DESTINATION include
101+
FILES_MATCHING PATTERN "*.h"
102+
)

0 commit comments

Comments
 (0)