UltrafastSecp256k1/scripts/generate_traceability.sh

283 lines
9.1 KiB
Bash

#!/usr/bin/env bash
# =============================================================================
# generate_traceability.sh -- Auto-update Audit Traceability Matrix
# =============================================================================
# Scans audit_*.cpp and test_*.cpp files, extracts test function names and
# CHECK() counts, produces a machine-readable JSON report + summary.
#
# Usage:
# ./scripts/generate_traceability.sh [build_dir]
#
# If build_dir is provided and contains executables, runs them to collect
# live pass/fail counts. Otherwise, does static source scan only.
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
TESTS_DIR="$REPO_ROOT/tests"
CPU_TESTS_DIR="$REPO_ROOT/cpu/tests"
DOCS_DIR="$REPO_ROOT/docs"
BUILD_DIR="${1:-$REPO_ROOT/build}"
OUTPUT_JSON="$DOCS_DIR/traceability_report.json"
OUTPUT_SUMMARY="$DOCS_DIR/traceability_summary.txt"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
echo "============================================================"
echo " Audit Traceability Matrix -- Auto-Generation"
echo "============================================================"
echo ""
echo " Repo root: $REPO_ROOT"
echo " Tests dir: $TESTS_DIR"
echo " Build dir: $BUILD_DIR"
echo ""
# -- Phase 1: Static Source Scan ----------------------------------
echo "[Phase 1] Static source scan..."
echo ""
declare -A FILE_CHECKS
declare -A FILE_SECTIONS
scan_file() {
local file="$1"
local basename
basename=$(basename "$file" .cpp)
# Count CHECK() macro invocations
local check_count
check_count=$(grep -c 'CHECK(' "$file" 2>/dev/null || echo 0)
# Count test functions (static void test_*)
local test_count
test_count=$(grep -c 'static void test_' "$file" 2>/dev/null || echo 0)
# Extract section names from g_section =
local sections
sections=$(grep -oP 'g_section\s*=\s*"\K[^"]+' "$file" 2>/dev/null | sort -u | tr '\n' ',' | sed 's/,$//')
FILE_CHECKS[$basename]=$check_count
FILE_SECTIONS[$basename]=$sections
printf " %-40s CHECKs: %-6d Tests: %-3d Sections: %s\n" \
"$basename" "$check_count" "$test_count" "${sections:-N/A}"
}
# Scan audit files
echo "-- Audit Files --"
for f in "$TESTS_DIR"/audit_*.cpp; do
[ -f "$f" ] && scan_file "$f"
done
echo ""
# Scan test files in tests/
echo "-- Test Files (tests/) --"
for f in "$TESTS_DIR"/test_*.cpp; do
[ -f "$f" ] && scan_file "$f"
done
echo ""
# Scan test files in cpu/tests/
if [ -d "$CPU_TESTS_DIR" ]; then
echo "-- Test Files (cpu/tests/) --"
for f in "$CPU_TESTS_DIR"/test_*.cpp; do
[ -f "$f" ] && scan_file "$f"
done
echo ""
fi
# -- Phase 2: Live Execution (if build dir exists) ---------------
declare -A LIVE_PASS
declare -A LIVE_FAIL
if [ -d "$BUILD_DIR" ]; then
echo "[Phase 2] Live execution scan..."
echo ""
run_audit() {
local exe="$1"
local name
name=$(basename "$exe")
if [ ! -x "$exe" ]; then
return
fi
echo " Running $name..."
local output
output=$("$exe" 2>&1) || true
# Extract final pass/fail line: "FIELD AUDIT: 641194 passed, 0 failed"
local pass fail
pass=$(echo "$output" | grep -oP '\d+(?= passed)' | tail -1 || echo "?")
fail=$(echo "$output" | grep -oP '\d+(?= failed)' | tail -1 || echo "?")
LIVE_PASS[$name]=${pass:-0}
LIVE_FAIL[$name]=${fail:-0}
if [ "$fail" = "0" ]; then
printf " ${GREEN}[OK] %s: %s passed, %s failed${NC}\n" "$name" "$pass" "$fail"
else
printf " ${RED}[FAIL] %s: %s passed, %s failed${NC}\n" "$name" "$pass" "$fail"
fi
}
# Look for audit executables in common locations
for dir in "$BUILD_DIR/cpu" "$BUILD_DIR" "$BUILD_DIR/tests"; do
if [ -d "$dir" ]; then
for exe in "$dir"/audit_* "$dir"/test_cross_* "$dir"/test_ct_*; do
[ -f "$exe" ] && [ -x "$exe" ] && run_audit "$exe"
done
fi
done
echo ""
else
echo "[Phase 2] Skipped (no build dir: $BUILD_DIR)"
echo ""
fi
# -- Phase 3: Generate JSON Report -------------------------------
echo "[Phase 3] Generating JSON report..."
mkdir -p "$DOCS_DIR"
cat > "$OUTPUT_JSON" << 'HEADER'
{
"generated": "TIMESTAMP",
"tool": "generate_traceability.sh",
"version": "1.0.0",
"invariant_catalog": "docs/INVARIANTS.md",
"traceability_matrix": "docs/AUDIT_TRACEABILITY.md",
"static_scan": {
HEADER
# Replace timestamp
sed -i "s/TIMESTAMP/$(date -Iseconds)/" "$OUTPUT_JSON"
# Write static scan results
first=true
for key in $(echo "${!FILE_CHECKS[@]}" | tr ' ' '\n' | sort); do
if [ "$first" = true ]; then
first=false
else
echo "," >> "$OUTPUT_JSON"
fi
printf ' "%s": {"checks": %d, "sections": "%s"}' \
"$key" "${FILE_CHECKS[$key]}" "${FILE_SECTIONS[$key]}" >> "$OUTPUT_JSON"
done
echo "" >> "$OUTPUT_JSON"
echo " }," >> "$OUTPUT_JSON"
# Write live results
echo ' "live_execution": {' >> "$OUTPUT_JSON"
first=true
for key in $(echo "${!LIVE_PASS[@]}" | tr ' ' '\n' | sort); do
if [ "$first" = true ]; then
first=false
else
echo "," >> "$OUTPUT_JSON"
fi
printf ' "%s": {"passed": %s, "failed": %s}' \
"$key" "${LIVE_PASS[$key]}" "${LIVE_FAIL[$key]}" >> "$OUTPUT_JSON"
done
echo "" >> "$OUTPUT_JSON"
echo " }" >> "$OUTPUT_JSON"
echo "}" >> "$OUTPUT_JSON"
echo " -> $OUTPUT_JSON"
# -- Phase 4: Generate Summary -----------------------------------
echo "[Phase 4] Generating summary..."
{
echo "============================================================"
echo " Audit Traceability Summary"
echo " Generated: $(date)"
echo "============================================================"
echo ""
echo "INVARIANT CATALOG: 108 invariants (docs/INVARIANTS.md)"
echo ""
echo "STATIC SOURCE SCAN:"
echo "-------------------------------------------------------------"
total_checks=0
for key in $(echo "${!FILE_CHECKS[@]}" | tr ' ' '\n' | sort); do
printf " %-35s %6d CHECK() calls\n" "$key" "${FILE_CHECKS[$key]}"
total_checks=$((total_checks + ${FILE_CHECKS[$key]}))
done
echo "-------------------------------------------------------------"
printf " %-35s %6d total\n" "TOTAL" "$total_checks"
echo ""
if [ ${#LIVE_PASS[@]} -gt 0 ]; then
echo "LIVE EXECUTION RESULTS:"
echo "-------------------------------------------------------------"
total_pass=0
total_fail=0
for key in $(echo "${!LIVE_PASS[@]}" | tr ' ' '\n' | sort); do
status="[OK]"
[ "${LIVE_FAIL[$key]}" != "0" ] && status="[FAIL]"
printf " %s %-30s %s passed, %s failed\n" \
"$status" "$key" "${LIVE_PASS[$key]}" "${LIVE_FAIL[$key]}"
total_pass=$((total_pass + ${LIVE_PASS[$key]:-0}))
total_fail=$((total_fail + ${LIVE_FAIL[$key]:-0}))
done
echo "-------------------------------------------------------------"
printf " TOTAL: %d passed, %d failed\n" "$total_pass" "$total_fail"
echo ""
fi
echo "VERIFICATION METHODS EMPLOYED:"
echo " [OK] Deterministic algebraic checks (100K+ random per category)"
echo " [OK] Official test vectors (BIP-340, RFC 6979, BIP-32 TV1-5)"
echo " [OK] Differential testing (vs libsecp256k1 v0.6.0, 1.3M nightly)"
echo " [OK] dudect statistical side-channel (Welch t-test, |t| < 4.5)"
echo " [OK] Fuzzing (libFuzzer harnesses for field/scalar/point/DER/address)"
echo " [OK] Adversarial inputs (zero keys, infinity, off-curve, bit-flips)"
echo " [OK] Boundary values (0, 1, p-1, p, p+1, n-1, n, n+1, 2^255)"
echo " [OK] Sanitizers (ASan, UBSan, TSan in CI)"
echo ""
echo "PLATFORMS VERIFIED:"
echo " [OK] x86-64 (Linux, Windows, macOS)"
echo " [OK] ARM64 (macOS, Linux, iOS, Android)"
echo " [OK] RISC-V 64 (StarFive VisionFive 2, QEMU)"
echo " [OK] ESP32-S3 (Xtensa LX7)"
echo " [OK] WASM (Emscripten)"
echo ""
echo "REMAINING GAPS (3/108):"
echo " [OK] C7 -- Thread-safety: TSan in CI + dedicated C ABI thread-stress harness"
echo " [!] CT5 -- No secret-dependent branches: code review only"
echo " [!] CT6 -- No secret-dependent memory access: code review only"
echo ""
echo "ARTIFACTS:"
echo " docs/INVARIANTS.md -- Full 108-invariant catalog"
echo " docs/AUDIT_TRACEABILITY.md -- Invariant->test mapping"
echo " docs/INTERNAL_AUDIT.md -- Full internal audit results"
echo " docs/CT_VERIFICATION.md -- CT layer methodology"
echo " docs/SECURITY_CLAIMS.md -- FAST/CT security contract"
echo " docs/DIFFERENTIAL_TESTING.md -- Cross-library protocol"
} > "$OUTPUT_SUMMARY"
echo " -> $OUTPUT_SUMMARY"
echo ""
echo "============================================================"
echo " Done. Review:"
echo " $OUTPUT_JSON"
echo " $OUTPUT_SUMMARY"
echo "============================================================"