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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
277 changes: 277 additions & 0 deletions bench/check_diamond_io_csv_logs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
#!/usr/bin/env python3
"""Check DiamondIO CSV rows against their simulation and benchmark logs."""

from __future__ import annotations

import argparse
import csv
import re
import sys
from decimal import Decimal, InvalidOperation
from pathlib import Path


BENCHMARK_FIELDS = [
"obfuscate_latency",
"obfuscate_total_time_nanos",
"obfuscate_max_parallelism",
"eval_latency",
"eval_total_time_nanos",
"eval_max_parallelism",
"obfuscate_input_injection_latency_percent",
"obfuscate_input_injection_total_time_percent",
"eval_input_injection_latency_percent",
"eval_input_injection_total_time_percent",
"obfuscated_circuit_bytes",
"input_injection_bytes",
]

CONFIG_CHECKS = [
("ring_dim_config", "ring_dim"),
("min_log_ring_dim", "min_log_ring_dim"),
("max_log_ring_dim", "max_log_ring_dim"),
("input_size", "input_size"),
("injector_batch_bits", "injector_batch_bits"),
("output_size", "output_size"),
("crt_bits", "crt_bits"),
("base_bits", "base_bits"),
("p_moduli_bits", "p_moduli_bits"),
("max_unreduced_muls", "max_unreduced_muls"),
("scale", "scale"),
("min_crt_depth", "min_crt_depth"),
("max_crt_depth", "max_crt_depth"),
("security_bits", "security_bits"),
("noise_refresh_cbd_n", "noise_refresh_cbd_n"),
("error_sigma", "error_sigma"),
("trapdoor_sigma", "trapdoor_sigma"),
("d_secret", "d_secret"),
]

SELECTED_CHECKS = [
("selected_crt_depth", "crt_depth"),
("selected_log_ring_dim", "log_ring_dim"),
("selected_ring_dim", "ring_dim"),
("achieved_secpar_for_gauss_in_run", "achieved_secpar_for_gauss"),
("achieved_secpar_for_cbd_in_run", "achieved_secpar_for_cbd"),
("prf_mask_output_coeff_bits", "prf_mask_output_coeff_bits"),
("noise_refresh_v_bits", "noise_refresh_v_bits"),
("final_seed_bits", "final_seed_bits"),
("noisy_plaintext_error_bits", "noisy_plaintext_error_bits"),
("input_injection_error_bits", "input_injection_error_bits"),
]

ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
CONFIG_RE = re.compile(r"DiamondIOGpuBenchConfig \{([^}]*)\}")
KV_RE = re.compile(r"\b([A-Za-z_][A-Za-z0-9_]*)=([^\s]+)")


def strip_ansi(text: str) -> str:
return ANSI_RE.sub("", text)


def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(
description="Check DiamondIO simulation and benchmark-estimation CSV values against logs."
)
parser.add_argument(
"csv_path",
nargs="?",
default="bench/security_bits_100_diamond_io_simulation_parameters.csv",
help="CSV file to check",
)
return parser.parse_args()


def repo_root() -> Path:
return Path(__file__).resolve().parents[1]


def resolve_log_path(raw_path: str, root: Path) -> Path:
path = Path(raw_path)
if path.exists():
return path

workspace_prefix = "/workspace/logs/"
if raw_path.startswith(workspace_prefix):
local_path = root / "logs" / raw_path[len(workspace_prefix) :]
if local_path.exists():
return local_path

matches = sorted((root / "logs").rglob(path.name)) if (root / "logs").exists() else []
if len(matches) == 1:
return matches[0]

return path


def read_log(raw_path: str, root: Path) -> tuple[Path, str]:
path = resolve_log_path(raw_path, root)
if not path.exists():
raise ValueError(f"log file not found: {raw_path}")
return path, strip_ansi(path.read_text(errors="replace"))


def last_line_with(text: str, needle: str) -> str:
matches = [line for line in text.splitlines() if needle in line]
if not matches:
raise ValueError(f"missing log line containing {needle!r}")
return matches[-1]


def parse_config(line: str) -> dict[str, str]:
match = CONFIG_RE.search(line)
if not match:
raise ValueError("missing DiamondIOGpuBenchConfig payload")
result: dict[str, str] = {}
for item in match.group(1).split(","):
key, value = item.strip().split(":", 1)
result[key.strip()] = value.strip()
return result


def parse_kv_line(line: str) -> dict[str, str]:
return {key: value.strip('"') for key, value in KV_RE.findall(line)}


def is_decimal(value: str) -> bool:
try:
Decimal(value)
return True
except (InvalidOperation, ValueError):
return False


def values_match(csv_value: str, log_value: str) -> bool:
left = csv_value.strip().strip('"')
right = log_value.strip().strip('"')
if left == "" or right == "":
return left == right
if left.lower() in {"true", "false"} or right.lower() in {"true", "false"}:
return left.lower() == right.lower()
if is_decimal(left) and is_decimal(right):
return Decimal(left) == Decimal(right)
return left == right


def require_match(
errors: list[str],
data_no: str,
source: str,
column: str,
csv_value: str,
log_key: str,
log_values: dict[str, str],
) -> None:
if log_key not in log_values:
if csv_value == "":
return
errors.append(f"row {data_no} {source}: log key {log_key!r} missing, CSV {column}={csv_value!r}")
return

log_value = log_values[log_key]
if not values_match(csv_value, log_value):
errors.append(
f"row {data_no} {source}: {column}={csv_value!r} does not match "
f"log {log_key}={log_value!r}"
)


def check_simulation(row: dict[str, str], root: Path, errors: list[str]) -> int:
data_no = row["data_no"]
_, text = read_log(row["simulation_log_file"], root)
checks = 0

config = parse_config(last_line_with(text, "DiamondIO GPU bench config:"))
for csv_column, log_key in CONFIG_CHECKS:
require_match(errors, data_no, "simulation config", csv_column, row[csv_column], log_key, config)
checks += 1
require_match(errors, data_no, "simulation config", "bench_iterations", row["bench_iterations"], "bench_iterations", config)
require_match(errors, data_no, "simulation config", "search_only", row["search_only"], "search_only", config)
checks += 2

selected = parse_kv_line(last_line_with(text, "DiamondIO CRT-depth search selected parameters"))
for csv_column, log_key in SELECTED_CHECKS:
require_match(errors, data_no, "simulation selected", csv_column, row[csv_column], log_key, selected)
checks += 1

return checks


def check_benchmark(row: dict[str, str], root: Path, errors: list[str]) -> int:
data_no = row["data_no"]
_, text = read_log(row["benchmark_estimation_log_file"], root)
checks = 0

config = parse_config(last_line_with(text, "DiamondIO GPU bench config:"))
for csv_column, log_key in CONFIG_CHECKS:
require_match(
errors,
data_no,
"benchmark config",
csv_column,
row[csv_column],
log_key,
config,
)
checks += 1
require_match(
errors,
data_no,
"benchmark config",
"benchmark_estimation_bench_iterations",
row["benchmark_estimation_bench_iterations"],
"bench_iterations",
config,
)
require_match(errors, data_no, "benchmark config", "expected_search_only", "false", "search_only", config)
checks += 2

selected = parse_kv_line(
last_line_with(text, "DiamondIO selected simulation parameters provided; skipping error simulation")
)
for csv_column, log_key in SELECTED_CHECKS:
if csv_column.startswith("achieved_secpar_"):
continue
require_match(errors, data_no, "benchmark selected", csv_column, row[csv_column], log_key, selected)
checks += 1

estimate = parse_kv_line(last_line_with(text, "DiamondIO GPU benchmark estimate"))
for field in BENCHMARK_FIELDS:
csv_column = f"benchmark_estimation_{field}"
require_match(errors, data_no, "benchmark estimate", csv_column, row[csv_column], field, estimate)
checks += 1

return checks


def main() -> int:
args = parse_args()
root = repo_root()
csv_path = Path(args.csv_path)
if not csv_path.is_absolute():
csv_path = root / csv_path

with csv_path.open(newline="") as f:
rows = list(csv.DictReader(f))

errors: list[str] = []
check_count = 0
for row in rows:
try:
check_count += check_simulation(row, root, errors)
check_count += check_benchmark(row, root, errors)
except ValueError as exc:
errors.append(f"row {row.get('data_no', '<unknown>')}: {exc}")

if errors:
print("CSV/log consistency check failed:", file=sys.stderr)
for error in errors:
print(f"- {error}", file=sys.stderr)
return 1

print(f"CSV/log consistency check ok: {len(rows)} rows, {check_count} field checks")
return 0


if __name__ == "__main__":
raise SystemExit(main())
5 changes: 5 additions & 0 deletions bench/security_bits_100_diamond_io_simulation_parameters.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data_no,protocol,implementation,test_target,security_bits,input_count,input_size,injector_batch_bits,output_size,ring_dim_config,min_log_ring_dim,max_log_ring_dim,selected_log_ring_dim,selected_ring_dim,min_crt_depth,max_crt_depth,selected_crt_depth,crt_bits,base_bits,p_moduli_bits,max_unreduced_muls,scale,noise_refresh_cbd_n,error_sigma,trapdoor_sigma,d_secret,bench_iterations,search_only,lattice_estimator_check,lattice_reference_gauss_secpar,lattice_reference_cbd_secpar,lattice_reference_log_file,max_prf_mask_output_coeff_bits,achieved_secpar_for_gauss_in_run,achieved_secpar_for_cbd_in_run,prf_mask_output_coeff_bits,noise_refresh_v_bits,final_seed_bits,noisy_plaintext_error_bits,input_injection_error_bits,git_commit,git_worktree_dirty,simulation_log_file,benchmark_estimation_git_commit,benchmark_estimation_bench_iterations,benchmark_estimation_log_file,benchmark_estimation_obfuscate_latency,benchmark_estimation_obfuscate_total_time_nanos,benchmark_estimation_obfuscate_max_parallelism,benchmark_estimation_eval_latency,benchmark_estimation_eval_total_time_nanos,benchmark_estimation_eval_max_parallelism,benchmark_estimation_obfuscate_input_injection_latency_percent,benchmark_estimation_obfuscate_input_injection_total_time_percent,benchmark_estimation_eval_input_injection_latency_percent,benchmark_estimation_eval_input_injection_total_time_percent,benchmark_estimation_obfuscated_circuit_bytes,benchmark_estimation_input_injection_bytes
1,DiamondIO,tests/test_gpu_diamond_io.rs,test_gpu_diamond_io_error_search_and_bench_estimate,100,10,100,10,6,65536,15,17,16,65536,45,55,53,28,14,7,4,256,2,4.0,4.578,1,1,true,measured,120,120,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input100_batch10_crt45_55_log15_17_sec100_sigma4p0_cbd2_release.log,1540,120,120,1474,756,149531758,1274,512,7bab63d0dcb8e75cd41cb9a140f49b19fb0a093f,true,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input100_batch10_crt45_55_log15_17_sec100_sigma4p0_cbd2_release.log,d5ade121f9f09eafa4faa2f9cae1bb6e8dfbb7d8,5,/workspace/logs/diamond_io_sec100_h200_iter5_d5ade121_20260517T070013JST/mxx-h200-diamond-io-sec100-est-20260517_1gpu_d5ade121f9f0_20260517T070013JST_diamond_io_row1.log,6116.0162626537995,4147712288836272546518676036861137818135063392704860629750,24170928207324098131482568296628771565212991810,2081.6366215446014,350048464264823037952904676103997678563435289528,10760822874598810008199153238566502400,0.8956872261884774,1.0219173976262904e-57,2.6697915314711547,9.47236296456918e-55,7485461781551070670753632832559405143329441533839620640,718912573794748064

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use relative paths in committed CSV logs

The repository guideline in AGENTS.md says documented file paths must be relative to the repo root, but these committed rows record machine-specific absolute paths such as /home/sora/... and /workspace/logs/.... Since bench/check_diamond_io_csv_logs.py defaults to this CSV, a fresh checkout cannot use the committed data without reproducing the original author's filesystem layout or relying on filename-only fallbacks; store these log references relative to the repo (for example under logs/...) instead.

Useful? React with 👍 / 👎.

2,DiamondIO,tests/test_gpu_diamond_io.rs,test_gpu_diamond_io_error_search_and_bench_estimate,100,8,80,10,6,65536,15,16,16,65536,45,53,50,28,14,7,4,256,2,4.0,4.578,1,1,true,measured,127,126,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input80_batch10_crt45_53_log15_16_sec100_sigma4p0_cbd2_release.log,1484,127,126,1391,1364,209717927,1180,419,7bab63d0dcb8e75cd41cb9a140f49b19fb0a093f,true,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input80_batch10_crt45_53_log15_16_sec100_sigma4p0_cbd2_release.log,d5ade121f9f09eafa4faa2f9cae1bb6e8dfbb7d8,5,/workspace/logs/diamond_io_sec100_h200_iter5_d5ade121_20260517T070013JST/mxx-h200-diamond-io-sec100-est-20260517_1gpu_d5ade121f9f0_20260517T070013JST_diamond_io_row2.log,4349.6224037724,3836841739399026528152604705114678011389011875781363121354,32587915154499688797348521447948292278419194160,1468.1229864235997,341613749629540640175700214725577743401185388204,14508039569129696930725625856000000000,1.1022438788346078,2.9360011137019488e-58,2.717653758176907,2.7019852806084382e-55,7624833700145137182585102700577477768380423660987821856,397407508418856352
3,DiamondIO,tests/test_gpu_diamond_io.rs,test_gpu_diamond_io_error_search_and_bench_estimate,100,11,110,10,6,65536,16,16,16,65536,53,57,55,28,14,7,4,256,2,4.0,4.578,1,1,true,skipped_explicit_log_ring_dim,114,113,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_cbd_failure_signal_input110_crt55_log16_17_sec100_sigma4p0_cbd2_release_sage.log,1596,,,1529,1502,257431460,1322,559,7bab63d0dcb8e75cd41cb9a140f49b19fb0a093f,true,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input110_batch10_crt53_57_log16_skip_lattice_sec100_sigma4p0_cbd2_release.log,d5ade121f9f09eafa4faa2f9cae1bb6e8dfbb7d8,5,/workspace/logs/diamond_io_sec100_h200_iter5_d5ade121_20260517T070013JST/mxx-h200-diamond-io-sec100-est-20260517_1gpu_d5ade121f9f0_20260517T070013JST_diamond_io_row3.log,7399.590372858398,11930376493455871470406567902825851008219256031267012708341,57793043386862822091653196282952132383198646606,2410.690358383399,981775308414456655348040561656065723072848751182,25729285111001160633634326891724800000,0.7935629742503815,4.696228574913229e-58,2.716362625862607,8.992567525973156e-55,20415755416907562105218484551666158918758500258495823776,961347918662682400
4,DiamondIO,tests/test_gpu_diamond_io.rs,test_gpu_diamond_io_error_search_and_bench_estimate,100,9,90,10,6,65536,16,16,16,65536,45,53,51,28,14,7,4,256,2,4.0,4.578,1,1,true,skipped_explicit_log_ring_dim,127,126,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input80_batch10_crt45_53_log15_16_sec100_sigma4p0_cbd2_release.log,1484,,,1418,2,33554433,1226,466,7bab63d0dcb8e75cd41cb9a140f49b19fb0a093f,true,/home/sora/.codex/worktrees/cedf/mxx/logs/test_gpu_diamond_io_input90_batch10_crt45_53_log16_skip_lattice_sec100_sigma4p0_cbd2_release.log,d5ade121f9f09eafa4faa2f9cae1bb6e8dfbb7d8,5,/workspace/logs/diamond_io_sec100_h200_iter5_d5ade121_20260517T070013JST/mxx-h200-diamond-io-sec100-est-20260517_1gpu_d5ade121f9f0_20260517T070013JST_diamond_io_row4.log,4894.2426108754,7639382038511751738891498139277151987051670594948741135,52756145950723562417943453342737232677474614,1728.1414876762003,670118290141931697811944482735822187500197972,23486873870902651209564816534405120,1.0182274534217755,1.967355999722658e-55,2.5708449391919452,3.468134372643018e-52,14713401305553361283670823025996689180981295518659744,525429407875401248
Loading
Loading