Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,5 @@ target/
/guix-build-*

/ci/scratch/

libbitcoinpqc
21 changes: 21 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,25 @@ set_target_properties(secp256k1 PROPERTIES
)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

#=============================
# libbitcoinpqc subtree
#=============================
message("")
message("Configuring libbitcoinpqc subtree...")

# Configure libbitcoinpqc build options
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Add the libbitcoinpqc subdirectory
add_subdirectory(libbitcoinpqc)

# Set target properties
# Note: EXCLUDE_FROM_ALL removed to ensure bitcoinpqc is built when needed

# Add libbitcoinpqc include directories to the main include path
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libbitcoinpqc/include)

# Set top-level target output locations.
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
Expand Down Expand Up @@ -117,11 +136,13 @@ add_library(bitcoin_consensus STATIC EXCLUDE_FROM_ALL
script/script_error.cpp
uint256.cpp
)

target_link_libraries(bitcoin_consensus
PRIVATE
core_interface
bitcoin_crypto
secp256k1
bitcoinpqc
)

if(WITH_ZMQ)
Expand Down
18 changes: 18 additions & 0 deletions src/addresstype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ WitnessV0ScriptHash::WitnessV0ScriptHash(const CScript& in)
CSHA256().Write(in.data(), in.size()).Finalize(begin());
}

WitnessV2P2TSH::WitnessV2P2TSH(const CScript& in)
{
CSHA256().Write(in.data(), in.size()).Finalize(begin());
}

bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
{
std::vector<valtype> vSolutions;
Expand Down Expand Up @@ -87,6 +92,12 @@ bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
addressRet = tap;
return true;
}
case TxoutType::WITNESS_V2_P2TSH: {
WitnessV2P2TSH p2tsh;
std::copy(vSolutions[0].begin(), vSolutions[0].end(), p2tsh.begin());
addressRet = p2tsh;
return true;
}
case TxoutType::ANCHOR: {
addressRet = PayToAnchor();
return true;
Expand Down Expand Up @@ -147,6 +158,12 @@ class CScriptVisitor
{
return CScript() << CScript::EncodeOP_N(id.GetWitnessVersion()) << id.GetWitnessProgram();
}

CScript operator()(const WitnessV2P2TSH& id) const
{
// P2TSH is version 2
return CScript() << CScript::EncodeOP_N(2) << ToByteVector(id);
}
};

class ValidDestinationVisitor
Expand All @@ -160,6 +177,7 @@ class ValidDestinationVisitor
bool operator()(const WitnessV0ScriptHash& dest) const { return true; }
bool operator()(const WitnessV1Taproot& dest) const { return true; }
bool operator()(const WitnessUnknown& dest) const { return true; }
bool operator()(const WitnessV2P2TSH& dest) const { return true; }
};
} // namespace

Expand Down
10 changes: 9 additions & 1 deletion src/addresstype.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ struct WitnessV1Taproot : public XOnlyPubKey
explicit WitnessV1Taproot(const XOnlyPubKey& xpk) : XOnlyPubKey(xpk) {}
};

struct WitnessV2P2TSH : public BaseHash<uint256>
{
WitnessV2P2TSH() : BaseHash() {}
explicit WitnessV2P2TSH(const uint256& hash) : BaseHash(hash) {}
explicit WitnessV2P2TSH(const CScript& script);
};

//! CTxDestination subtype to encode any future Witness version
struct WitnessUnknown
{
Expand Down Expand Up @@ -138,9 +145,10 @@ struct PayToAnchor : public WitnessUnknown
* * WitnessV1Taproot: TxoutType::WITNESS_V1_TAPROOT destination (P2TR address)
* * PayToAnchor: TxoutType::ANCHOR destination (P2A address)
* * WitnessUnknown: TxoutType::WITNESS_UNKNOWN destination (P2W??? address)
* * WitnessV2P2TSH: TxoutType::WITNESS_V2_P2TSH destination (P2TSH address)
* A CTxDestination is the internal data type encoded in a bitcoin address
*/
using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown>;
using CTxDestination = std::variant<CNoDestination, PubKeyDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, PayToAnchor, WitnessUnknown, WitnessV2P2TSH>;

/** Check whether a CTxDestination corresponds to one with an address. */
bool IsValidDestination(const CTxDestination& dest);
Expand Down
18 changes: 18 additions & 0 deletions src/key_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ class DestinationEncoder
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
}

std::string operator()(const WitnessV2P2TSH& id) const
{
std::vector<unsigned char> data = {2}; // Version 2
data.reserve(53); // Reserve space for the hash
ConvertBits<8, 5, true>([&](unsigned char c) { data.push_back(c); }, id.begin(), id.end());
return bech32::Encode(bech32::Encoding::BECH32M, m_params.Bech32HRP(), data);
}

std::string operator()(const CNoDestination& no) const { return {}; }
std::string operator()(const PubKeyDestination& pk) const { return {}; }
};
Expand Down Expand Up @@ -181,6 +189,16 @@ CTxDestination DecodeDestination(const std::string& str, const CChainParams& par
return tap;
}

if (version == 2 && data.size() == WITNESS_V2_P2TSH_SIZE) {
WitnessV2P2TSH tsh;
if (data.size() == tsh.size()) {
std::copy(data.begin(), data.end(), tsh.begin());
return tsh;
}
error_str = strprintf("Invalid P2TSH address program size (%d %s)", data.size(), byte_str);
return CNoDestination();
}

if (CScript::IsPayToAnchor(version, data)) {
return PayToAnchor();
}
Expand Down
108 changes: 108 additions & 0 deletions src/libbitcoinpqc/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Rust CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]

env:
CARGO_TERM_COLOR: always

jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt

- name: Cache dependencies
uses: Swatinem/rust-cache@v2

- name: Check code format
run: cargo fmt -- --check

- name: Clippy
run: cargo clippy -- -D warnings

- name: Build
run: cargo build --verbose

- name: Run tests
run: cargo test --verbose

build-matrix:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
# os: [ubuntu-latest, macos-latest]
rust: [stable]
fail-fast: false
steps:
- uses: actions/checkout@v3

- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev

- name: Install dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew install cmake

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
components: clippy, rustfmt

- name: Cache dependencies
uses: Swatinem/rust-cache@v2

- name: Check code format
run: cargo fmt -- --check

- name: Clippy
run: cargo clippy -- -D warnings

- name: Build
run: cargo build --verbose

- name: Run tests
run: cargo test --verbose

# benchmark:
# name: Benchmark
# runs-on: ubuntu-latest
# needs: test
# if: github.event_name == 'push' && github.ref == 'refs/heads/main'
# steps:
# - uses: actions/checkout@v3

# - name: Install dependencies
# run: |
# sudo apt-get update
# sudo apt-get install -y build-essential cmake libssl-dev

# - name: Install Rust
# uses: dtolnay/rust-toolchain@stable

# - name: Cache dependencies
# uses: Swatinem/rust-cache@v2

# - name: Run benchmarks
# run: cargo bench
15 changes: 15 additions & 0 deletions src/libbitcoinpqc/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
build/
dist/
*.o
benchmark_results.txt
__pycache__
python/build/
*.egg-info/
node_modules/
**.gcno
**.lcov
**/target/
tags
TAGS
rust-toolchain.toml
Cargo.lock
6 changes: 6 additions & 0 deletions src/libbitcoinpqc/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"rust-analyzer.cargo.features": ["ide"],
"editor.formatOnSave": true,
"rust-analyzer.check.command": "clippy",
"rust-analyzer.check.extraArgs": ["--all-targets"]
}
102 changes: 102 additions & 0 deletions src/libbitcoinpqc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
cmake_minimum_required(VERSION 3.10)
project(libbitcoinpqc C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Set version
set(BITCOINPQC_VERSION_MAJOR 0)
set(BITCOINPQC_VERSION_MINOR 1)
set(BITCOINPQC_VERSION_PATCH 0)

# Library output settings
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)

# Include directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/dilithium/ref
${CMAKE_CURRENT_SOURCE_DIR}/sphincsplus/ref
)

# Custom randombytes implementation
set(CUSTOM_RANDOMBYTES
dilithium/ref/randombytes_custom.c
sphincsplus/ref/randombytes_custom.c
)

# ML-DSA-44 (Dilithium) source files
set(ML_DSA_SOURCES
dilithium/ref/sign.c
dilithium/ref/packing.c
dilithium/ref/polyvec.c
dilithium/ref/poly.c
dilithium/ref/ntt.c
dilithium/ref/reduce.c
dilithium/ref/rounding.c
dilithium/ref/fips202.c
dilithium/ref/symmetric-shake.c
)

# SLH-DSA-Shake-128s (SPHINCS+) source files
set(SLH_DSA_SOURCES
sphincsplus/ref/address.c
sphincsplus/ref/fors.c
sphincsplus/ref/hash_shake.c
sphincsplus/ref/merkle.c
sphincsplus/ref/sign.c
sphincsplus/ref/thash_shake_simple.c
sphincsplus/ref/utils.c
sphincsplus/ref/utilsx1.c
sphincsplus/ref/wots.c
sphincsplus/ref/wotsx1.c
sphincsplus/ref/fips202.c
)

# libbitcoinpqc source files
set(BITCOINPQC_SOURCES
src/bitcoinpqc.c
src/ml_dsa/utils.c
src/ml_dsa/keygen.c
src/ml_dsa/sign.c
src/ml_dsa/verify.c
src/slh_dsa/utils.c
src/slh_dsa/keygen.c
src/slh_dsa/sign.c
src/slh_dsa/verify.c
)

# Define the main library target
add_library(bitcoinpqc STATIC
${BITCOINPQC_SOURCES}
${ML_DSA_SOURCES}
${SLH_DSA_SOURCES}
${CUSTOM_RANDOMBYTES}
)

# Set include directories for the library
target_include_directories(bitcoinpqc PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Set compile definitions for the library
target_compile_definitions(bitcoinpqc PRIVATE
DILITHIUM_MODE=2 # ML-DSA-44 (Dilithium2)
PARAMS=sphincs-shake-128s
CUSTOM_RANDOMBYTES=1
)

# Configure install paths
install(TARGETS bitcoinpqc
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
)

install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/
DESTINATION include
FILES_MATCHING PATTERN "*.h"
)
Loading
Loading