#!/bin/bash # Formal verification runner for libsoliton. # Run after editing any .spthy or .cv file. Results should match the # expected outcomes in tamarin/README.md and cryptoverif/README.md. # # Requirements: # tamarin-prover 1.12.0+ with maude 3.5.1+ on PATH # cryptoverif 2.12+ on PATH # # Usage: # ./verify.sh # run everything # ./verify.sh tamarin # tamarin only # ./verify.sh cryptoverif # cryptoverif only # ./verify.sh tamarin/LO_Auth.spthy # single file # # Environment: # CV_LIB Path to CryptoVerif pq library (without .cvl extension). # Example: CV_LIB=/usr/share/cryptoverif/pq ./verify.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" TAMARIN_DIR="$SCRIPT_DIR/tamarin" CV_DIR="$SCRIPT_DIR/cryptoverif" CV_LIB="${CV_LIB:-}" if [ -t 1 ]; then GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[0;33m' BOLD='\033[1m'; RESET='\033[0m' else GREEN=''; RED=''; YELLOW=''; BOLD=''; RESET='' fi # Global counters T_VERIFIED=0; T_FALSIFIED=0; T_ERRORS=0; T_FILES=0 CV_PROVED=0; CV_FAILED=0; CV_FILES=0 print_header() { echo "" echo -e "${BOLD}=== $1 ===${RESET}" echo "" } run_tamarin() { local file="$1" local name name="$(basename "$file" .spthy)" T_FILES=$((T_FILES + 1)) echo -e "${BOLD}--- $name ---${RESET}" local output if ! output=$(tamarin-prover "$file" --prove 2>&1); then echo -e " ${RED}ERROR: tamarin-prover failed${RESET}" echo "$output" | tail -5 | sed 's/^/ /' T_ERRORS=$((T_ERRORS + 1)) return fi # Check for wellformedness warnings if echo "$output" | grep -q "WARNING"; then echo -e " ${RED}WARNING: wellformedness check failed${RESET}" T_ERRORS=$((T_ERRORS + 1)) fi local time time=$(echo "$output" | grep "processing time:" | sed 's/.*processing time: //') # Parse each result line — avoid subshell pipe by using process substitution while IFS= read -r line; do local lemma steps lemma=$(echo "$line" | sed 's/ (.*//') steps=$(echo "$line" | grep -oP '\d+ steps' || echo "? steps") if echo "$line" | grep -q "verified"; then echo -e " ${GREEN}PASS${RESET} $lemma ($steps)" T_VERIFIED=$((T_VERIFIED + 1)) elif echo "$line" | grep -q "falsified"; then echo -e " ${YELLOW}FALSE${RESET} $lemma ($steps)" T_FALSIFIED=$((T_FALSIFIED + 1)) fi done < <(echo "$output" | grep -E "verified|falsified") echo " ($time)" } run_cryptoverif() { local file="$1" local name name="$(basename "$file" .cv)" CV_FILES=$((CV_FILES + 1)) echo -e "${BOLD}--- $name ---${RESET}" if [ -z "$CV_LIB" ]; then echo -e " ${YELLOW}SKIP${RESET} CV_LIB not set. Run: CV_LIB=/path/to/pq $0 cryptoverif" CV_FILES=$((CV_FILES - 1)) return fi local output output=$(cryptoverif -lib "$CV_LIB" "$file" 2>&1) || true if echo "$output" | grep -q "^File.*Error:"; then echo -e " ${RED}ERROR${RESET}" echo "$output" | grep "Error:" | sed 's/^/ /' CV_FAILED=$((CV_FAILED + 1)) return fi while IFS= read -r line; do if echo "$line" | grep -q "Proved"; then local prop bound prop=$(echo "$line" | sed 's/RESULT Proved //' | sed 's/ up to.*//') bound=$(echo "$line" | grep -oP 'up to probability .*' || echo "") echo -e " ${GREEN}PROVED${RESET} $prop" [ -n "$bound" ] && echo " $bound" CV_PROVED=$((CV_PROVED + 1)) elif echo "$line" | grep -q "Could not prove"; then local prop prop=$(echo "$line" | sed 's/RESULT Could not prove //') echo -e " ${RED}FAILED${RESET} $prop" CV_FAILED=$((CV_FAILED + 1)) fi done < <(echo "$output" | grep "^RESULT" | grep -v "^RESULT time") if echo "$output" | grep -q "All queries proved"; then echo -e " ${GREEN}All queries proved.${RESET}" fi } run_all_tamarin() { print_header "Tamarin Prover" for f in "$TAMARIN_DIR"/*.spthy; do run_tamarin "$f" echo "" done } run_all_cryptoverif() { print_header "CryptoVerif" for f in "$CV_DIR"/*.cv; do run_cryptoverif "$f" echo "" done } case "${1:-all}" in tamarin) run_all_tamarin ;; cryptoverif) run_all_cryptoverif ;; *.spthy) run_tamarin "$1" ;; *.cv) run_cryptoverif "$1" ;; all) run_all_tamarin; run_all_cryptoverif ;; *) echo "Usage: $0 [all|tamarin|cryptoverif|]"; exit 1 ;; esac # Summary echo "" echo -e "${BOLD}=== Summary ===${RESET}" T_TOTAL=$((T_VERIFIED + T_FALSIFIED)) if [ "$T_FILES" -gt 0 ]; then echo -e " Tamarin: ${T_FILES} files, ${T_TOTAL} lemmas (${T_VERIFIED} verified, ${T_FALSIFIED} falsified, ${T_ERRORS} errors)" fi CV_TOTAL=$((CV_PROVED + CV_FAILED)) if [ "$CV_FILES" -gt 0 ]; then echo -e " CryptoVerif: ${CV_FILES} files, ${CV_TOTAL} queries (${CV_PROVED} proved, ${CV_FAILED} failed)" fi GRAND_TOTAL=$((T_TOTAL + CV_TOTAL)) GRAND_PASS=$((T_VERIFIED + T_FALSIFIED + CV_PROVED)) GRAND_FAIL=$((T_ERRORS + CV_FAILED)) echo -e " Total: ${GRAND_TOTAL} checks, ${GRAND_FAIL} failures" if [ "$GRAND_FAIL" -gt 0 ]; then echo -e " ${RED}Some checks failed.${RESET}" exit 1 else echo -e " ${GREEN}All checks passed.${RESET}" fi