* feat: v3.16.0 -- BIP-340 strict parsing, CT erasure, local Docker CI Security: - BIP-340 strict parsing: Scalar::parse_bytes_strict, FieldElement::parse_bytes_strict, SchnorrSignature::parse_strict - CT buffer erasure via volatile function-pointer trick in schnorr_sign/ecdsa_sign - lift_x deduplication, Y-parity fix (limbs()[0] & 1), pragma balance fix - C ABI functions now use strict parsing internally Audit: - ct_sidechannel_smoke marked advisory (timing flakes on shared CI runners) - carry_propagation test: cross-validation (generator vs generic path) + hex diagnostics for ARM64 - 31-test BIP-340 strict suite (test_bip340_strict.cpp) Local CI (Docker): - docker-compose.ci.yml: single-command orchestration for 14 CI jobs - pre-push target: warnings + tests + ASan + audit in ~5 min - audit job mirrors audit-report.yml (GCC-13 + Clang-17) - ccache volume for fast rebuilds - scripts/hooks/pre-push + scripts/pre-push-ci.ps1 Docs: - COMPATIBILITY.md, BINDINGS_ERROR_MODEL.md updates - SECURITY.md: library-side erasure, planned items checklist, API stability refs - UFSECP_BITCOIN_STRICT CMake option - packaging.yml release workflow race fix Tests: 26/26 pass locally (0 failures) * feat: ARM64 native dudect CI + ct-verif LLVM pass CI, docs update CI: - ct-arm64.yml: native Apple Silicon (M1) dudect -- smoke per-PR, full nightly - ct-verif.yml: compile-time CT verification via LLVM pass (deterministic) Docs: - SECURITY.md: mark ARM64 dudect + ct-verif as done, update version table - CT_VERIFICATION.md: update known limitations, planned improvements, v3.16.0 - CHANGELOG.md: add CT Verification CI section - README.md: add CT ARM64 + CT-Verif badges * audit: MuSig2/FROST dudect, Valgrind CT CI, SARIF output, perf regression gate - test_ct_sidechannel.cpp: add group [9] MuSig2/FROST protocol timing tests (musig2_partial_sign, frost_sign, frost_lagrange_coefficient) - unified_audit_runner.cpp: add write_sarif_report() + --sarif CLI flag for GitHub Code Scanning integration (SARIF v2.1.0) - valgrind-ct.yml: new CI workflow wrapping scripts/valgrind_ct_check.sh (nightly + on push to main/dev) - bench-regression.yml: per-commit benchmark regression gate (120% threshold, fail-on-alert: true) - audit-report.yml: add --sarif flag + SARIF upload step for linux-gcc job, security-events:write permission - SECURITY.md: check off Valgrind CT, MuSig2/FROST dudect, SARIF, perf gate - CHANGELOG.md: document all new items under v3.16.0 - README.md: add Valgrind CT + Perf Gate workflow badges - CT_VERIFICATION.md: check off dudect expansion + Valgrind CT taint * v3.16.1: OpenSSF Scorecard hardening, FROST RFC 9591 tests, audit progress bar, community files OpenSSF Scorecard (7.3 -> 9+ target): - Pin all GitHub Actions to full SHA (codeql-action v4.32.4, upload-artifact v6.0.0) - Add harden-runner to discord-commits, packaging RPM jobs - Add persist-credentials: false to all checkout steps with write permissions - Standardize action versions across 13 workflow files FROST RFC 9591 Protocol Invariant Tests: - test_rfc9591_invariants: 7 invariants (verification share, Lagrange interpolation, Feldman VSS, partial sig linearity, partial sig verification, wrong share rejection, nonce commitment consistency) - test_rfc9591_3of5: exhaustive 3-of-5 signing over all C(5,3)=10 subsets Audit Sub-test Progress Visibility: - New audit_check.hpp: centralized CHECK macro with 20-char ASCII progress bar - Migrated all 22 audit .cpp files to use shared CHECK macro - Windows-safe unbuffered stdout (setvbuf _IONBF) New Audit Modules: - test_musig2_bip327_vectors.cpp: 35 BIP-327 reference tests - test_ffi_round_trip.cpp: 103 FFI boundary tests - test_fiat_crypto_vectors.cpp: expanded to 752 checks Community Files: - ADOPTERS.md with production/development/hobby categories - 4 GitHub Discussion templates (Q&A, Show-and-Tell, Ideas, Integration Help) Build: 24/26 CTest pass (2 ct_sidechannel = known Windows timing noise) Audit: 48/49 AUDIT-READY (1 advisory dudect smoke) * fix: valgrind_ct_check.sh binary path (audit/ not cpu/), update CHANGELOG for v3.16.0 * fix: valgrind_ct_check.sh grep -c double-zero bug (0\\n0 integer parse failure) grep -c prints '0' on no match but exits 1. The || echo '0' fallback appended a second '0', producing '0\n0' which broke bash [[ -eq 0 ]] comparisons. Changed to || true with default.
166 lines
5.6 KiB
Bash
166 lines
5.6 KiB
Bash
#!/usr/bin/env bash
|
|
# ============================================================================
|
|
# Valgrind Memcheck CT Analysis
|
|
# Phase IV, Task 4.3.3 -- Detect secret-dependent branches via uninit tracking
|
|
# ============================================================================
|
|
# Uses Valgrind's --track-origins=yes to detect control flow that depends on
|
|
# uninitialized / "secret-tainted" memory. We mark secret key material as
|
|
# undefined, then check if any branches depend on it.
|
|
#
|
|
# Approach: Build with special VALGRIND_CT_CHECK define that:
|
|
# 1. Marks secret scalars as UNDEFINED via VALGRIND_MAKE_MEM_UNDEFINED
|
|
# 2. Runs CT operations (scalar_mul, ecdsa_sign, schnorr_sign)
|
|
# 3. Valgrind reports any "Conditional jump depends on uninitialised value"
|
|
# 4. Zero reports = CT proven at binary level
|
|
#
|
|
# Usage:
|
|
# ./scripts/valgrind_ct_check.sh [build_dir]
|
|
#
|
|
# Prerequisites:
|
|
# apt-get install valgrind
|
|
# Build with: -DCMAKE_BUILD_TYPE=Debug (no optimizations strip the checks)
|
|
#
|
|
# Exit codes:
|
|
# 0 = no secret-dependent branches detected
|
|
# 1 = potential CT violation found
|
|
# 2 = build/setup error
|
|
# ============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
BUILD_DIR="${1:-build/valgrind-ct}"
|
|
SRC_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
REPORT_DIR="$BUILD_DIR/valgrind_reports"
|
|
VALGRIND_LOG="$REPORT_DIR/valgrind_ct.log"
|
|
VALGRIND_XML="$REPORT_DIR/valgrind_ct.xml"
|
|
|
|
echo "==========================================================="
|
|
echo " Valgrind CT Analysis"
|
|
echo "==========================================================="
|
|
echo " Source: $SRC_DIR"
|
|
echo " Build: $BUILD_DIR"
|
|
echo " Reports: $REPORT_DIR"
|
|
echo ""
|
|
|
|
# -- Check prerequisites ---------------------------------------------------
|
|
|
|
if ! command -v valgrind &>/dev/null; then
|
|
echo "ERROR: valgrind not found. Install with: apt-get install valgrind"
|
|
exit 2
|
|
fi
|
|
|
|
VALGRIND_VERSION=$(valgrind --version 2>/dev/null || echo "unknown")
|
|
echo " Valgrind: $VALGRIND_VERSION"
|
|
echo ""
|
|
|
|
# -- Build test binary with Valgrind CT checks ----------------------------
|
|
|
|
echo "[1/4] Configuring (Debug + Valgrind CT markers)..."
|
|
cmake -S "$SRC_DIR" -B "$BUILD_DIR" -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Debug \
|
|
-DSECP256K1_BUILD_TESTS=ON \
|
|
-DSECP256K1_USE_ASM=OFF \
|
|
-DCMAKE_CXX_FLAGS="-DVALGRIND_CT_CHECK=1 -g -O0" \
|
|
2>&1 | tail -5
|
|
|
|
echo "[2/4] Building test binary..."
|
|
cmake --build "$BUILD_DIR" --target test_ct_sidechannel_standalone -j"$(nproc)" 2>&1 | tail -3
|
|
|
|
TEST_BIN="$BUILD_DIR/audit/test_ct_sidechannel_standalone"
|
|
if [[ ! -x "$TEST_BIN" ]]; then
|
|
# Fallback: some CMake configs place it under cpu/
|
|
TEST_BIN="$BUILD_DIR/cpu/test_ct_sidechannel_standalone"
|
|
fi
|
|
if [[ ! -x "$TEST_BIN" ]]; then
|
|
echo "ERROR: Test binary not found in audit/ or cpu/ under $BUILD_DIR"
|
|
exit 2
|
|
fi
|
|
|
|
# -- Run under Valgrind ----------------------------------------------------
|
|
|
|
mkdir -p "$REPORT_DIR"
|
|
|
|
echo "[3/4] Running under Valgrind (this takes several minutes)..."
|
|
echo " Tracking: secret-dependent branches + memory errors"
|
|
echo ""
|
|
|
|
set +e
|
|
valgrind \
|
|
--tool=memcheck \
|
|
--track-origins=yes \
|
|
--leak-check=no \
|
|
--show-reachable=no \
|
|
--error-exitcode=42 \
|
|
--xml=yes \
|
|
--xml-file="$VALGRIND_XML" \
|
|
--log-file="$VALGRIND_LOG" \
|
|
--num-callers=20 \
|
|
--suppressions=/dev/null \
|
|
"$TEST_BIN" 2>&1 | tee "$REPORT_DIR/stdout.log"
|
|
|
|
VG_EXIT=$?
|
|
set -e
|
|
|
|
# -- Analyze results ------------------------------------------------------
|
|
|
|
echo ""
|
|
echo "[4/4] Analyzing Valgrind output..."
|
|
echo ""
|
|
|
|
# Count "Conditional jump or move depends on uninitialised value(s)"
|
|
# NOTE: grep -c prints "0" on no match but exits 1; use || true to avoid
|
|
# the fallback echo which would produce "0\n0" and break integer comparisons.
|
|
CT_ERRORS=$(grep -c "Conditional jump or move depends on uninitialised" "$VALGRIND_LOG" 2>/dev/null || true)
|
|
CT_ERRORS=${CT_ERRORS:-0}
|
|
|
|
# Count "Use of uninitialised value of size"
|
|
UNINIT_ERRORS=$(grep -c "Use of uninitialised value" "$VALGRIND_LOG" 2>/dev/null || true)
|
|
UNINIT_ERRORS=${UNINIT_ERRORS:-0}
|
|
|
|
# Count total errors
|
|
TOTAL_ERRORS=$(grep -c "ERROR SUMMARY:" "$VALGRIND_LOG" 2>/dev/null || true)
|
|
TOTAL_ERRORS=${TOTAL_ERRORS:-0}
|
|
ERROR_SUMMARY=$(grep "ERROR SUMMARY:" "$VALGRIND_LOG" 2>/dev/null | tail -1 || echo "N/A")
|
|
|
|
echo "-----------------------------------------------------------"
|
|
echo " Valgrind CT Analysis Results"
|
|
echo "-----------------------------------------------------------"
|
|
echo " Conditional branch on uninit: $CT_ERRORS"
|
|
echo " Use of uninit value: $UNINIT_ERRORS"
|
|
echo " $ERROR_SUMMARY"
|
|
echo ""
|
|
echo " Full log: $VALGRIND_LOG"
|
|
echo " XML report: $VALGRIND_XML"
|
|
echo "-----------------------------------------------------------"
|
|
|
|
# -- Generate JSON report -------------------------------------------------
|
|
|
|
cat > "$REPORT_DIR/valgrind_ct_report.json" <<EOF
|
|
{
|
|
"tool": "valgrind_ct_check",
|
|
"valgrind_version": "$VALGRIND_VERSION",
|
|
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
"binary": "$TEST_BIN",
|
|
"ct_branch_errors": $CT_ERRORS,
|
|
"uninit_value_errors": $UNINIT_ERRORS,
|
|
"valgrind_exit_code": $VG_EXIT,
|
|
"verdict": "$([ "$CT_ERRORS" -eq 0 ] && echo "PASS" || echo "FAIL")"
|
|
}
|
|
EOF
|
|
|
|
echo " JSON report: $REPORT_DIR/valgrind_ct_report.json"
|
|
echo ""
|
|
|
|
# -- Verdict --------------------------------------------------------------
|
|
|
|
if [[ "$CT_ERRORS" -eq 0 ]]; then
|
|
echo " OK No secret-dependent branches detected by Valgrind"
|
|
exit 0
|
|
else
|
|
echo " X POTENTIAL CT VIOLATION: $CT_ERRORS conditional branches on uninit data"
|
|
echo ""
|
|
echo " Offending locations:"
|
|
grep -A5 "Conditional jump or move depends on uninitialised" "$VALGRIND_LOG" | head -30
|
|
exit 1
|
|
fi
|