diff --git a/run_tb.sh b/run_tb.sh index 5815199..4e46698 100755 --- a/run_tb.sh +++ b/run_tb.sh @@ -3,14 +3,14 @@ # # Usage: ./run_tb.sh [K] [CASE] # ./run_tb.sh ntt # run the module's full xsim_run.tcl -# ./run_tb.sh top # ML-KEM KeyGen: all K, all cases -# ./run_tb.sh top 2 # only K=2 (ML-KEM-512), all its cases +# ./run_tb.sh top # ML-KEM KeyGen: all K, all KAT vectors +# ./run_tb.sh top 2 # only K=2 (ML-KEM-512), all KAT vectors # ./run_tb.sh top 2 3 # only K=2, only CASE=3 # ./run_tb.sh top 4 0 # only K=4 (ML-KEM-1024), CASE=0 -# ./run_tb.sh enc # ML-KEM Encaps: all K, all cases (0..2) -# ./run_tb.sh enc 2 # Encaps K=2, all its cases +# ./run_tb.sh enc # ML-KEM Encaps: all K, all KAT vectors +# ./run_tb.sh enc 2 # Encaps K=2, all KAT vectors # ./run_tb.sh enc 4 1 # Encaps K=4, only CASE=1 -# ./run_tb.sh dec # ML-KEM Decaps: all K, all cases (0..2) +# ./run_tb.sh dec # ML-KEM Decaps: all K, all KAT vectors # ./run_tb.sh dec 2 0 # Decaps K=2, only CASE=0 # ./run_tb.sh hello [K] # hello_world end-to-end (single instance; K=2/3/4) # ./run_tb.sh hello two [K] # hello_world end-to-end (two instances; K=2/3/4) @@ -20,8 +20,10 @@ # all compile the xvlog lines from sync_rtl/top/TB/xsim_run.tcl. They differ only # in the testbench: top -> tb_mlkem_kg_katK_xsim, enc -> tb_mlkem_enc_katK_xsim, # dec -> tb_mlkem_dec_katK_xsim. -# For these, K (2/3/4) and CASE select a single KAT run so you can iterate -# quickly. Other modules ignore the extra args and run their xsim_run.tcl verbatim. +# For these, K (2/3/4) and CASE select a subset of the KAT run so you can +# iterate quickly. Without CASE the script generates/enumerates every vector in +# test_data/kat_MLKEM_{512,768,1024}.rsp. Limit xsim parallelism with +# RUN_TB_JOBS=N (default: min(nproc, 4)). # # Prerequisites: # Vivado 2019.2 at /opt/Xilinx/Vivado/2019.2/ @@ -30,6 +32,8 @@ set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" VIVADO_SETTINGS="/opt/Xilinx/Vivado/2019.2/settings64.sh" +KAT_VECTOR_DIR="$SCRIPT_DIR/sync_rtl/top/TB/vectors" +KAT_RUN_VECTOR_DIR="" if [ "$1" = "--list" ]; then echo "Available modules:" @@ -117,114 +121,240 @@ execute_tcl() { # the shared xsim.dir BEFORE any parallel run starts). # # run_xsim_jobs ... -# each = "snapshot:K:CASE". Launches all specs in parallel, waits, -# then prints an ordered summary and returns nonzero if any job failed. +# each = "snapshot:K:CASE". Launches specs with bounded parallelism, +# waits, then prints an ordered summary and returns nonzero if any job failed. PAR_BASE="${TMPDIR:-/tmp}/run_tb_par_$$" +KAT_TMP_BASE="${TMPDIR:-/tmp}/run_tb_vectors_$$" +trap 'rm -rf "$PAR_BASE" "$KAT_TMP_BASE"' EXIT print_timing_summary() { local logs=("$@") - local found=0 log - - for log in "${logs[@]}"; do - if [ -f "$log" ] && grep -q '^TIME ' "$log"; then - found=1 - fi - done - [ "$found" -eq 0 ] && return 0 echo "" - echo "Timing summary (clk=20MHz, period=50ns)" - printf " %-7s %-3s %-5s %10s %12s %12s %s\n" "OP" "K" "CASE" "cycles" "time_us" "time_ms" "log" - for log in "${logs[@]}"; do - [ -f "$log" ] || continue - awk -v logfile="$log" ' - /^TIME / { - k = ""; c = ""; op = ""; cycles = ""; runtime = ""; - for (i = 1; i <= NF; i++) { - split($i, a, "="); - if (a[1] == "K") k = a[2]; - else if (a[1] == "CASE") c = a[2]; - else if (a[1] == "OP") op = a[2]; - else if (a[1] == "cycles") cycles = a[2]; - else if (a[1] == "runtime") runtime = a[2]; - } - if (runtime != "") { - printf " %-7s %-3s %-5s %10d %12.3f %12.3f %s\n", - op, k, c, cycles, runtime / 1000.0, runtime / 1000000.0, logfile; - } + awk ' + /^TIME / { + cycles = ""; runtime = ""; + for (i = 1; i <= NF; i++) { + split($i, a, "="); + if (a[1] == "cycles") cycles = a[2]; + else if (a[1] == "runtime") runtime = a[2]; } - ' "$log" - done + if (cycles != "") { + n++; + sum_cycles += cycles; + if (runtime != "") sum_runtime += runtime; + } + } + END { + if (n == 0) { + print "Timing average: no TIME records found"; + } else { + printf "Timing average (clk=20MHz, period=50ns): runs=%d avg_cycles=%.1f avg_time_us=%.3f avg_time_ms=%.3f\n", + n, sum_cycles / n, (sum_runtime / n) / 1000.0, (sum_runtime / n) / 1000000.0; + } + } + ' "${logs[@]}" +} - local found_state=0 - for log in "${logs[@]}"; do - if [ -f "$log" ] && grep -q '^ STATE ' "$log"; then - found_state=1 - fi - done - [ "$found_state" -eq 0 ] && return 0 +validate_kat_selection() { + local ksel="$1" csel="$2" + case "$ksel" in + ""|2|3|4) ;; + *) echo "ERROR: K must be 2, 3, or 4 (got '$ksel')"; return 1 ;; + esac + if [ -n "$csel" ] && ! [[ "$csel" =~ ^[0-9]+$ ]]; then + echo "ERROR: CASE must be a non-negative integer (got '$csel')" + return 1 + fi +} - echo "" - echo "State timing breakdown (clk=20MHz, period=50ns)" - printf " %-7s %-3s %-5s %-12s %10s %12s\n" "OP" "K" "CASE" "STATE" "cycles" "time_us" - for log in "${logs[@]}"; do - [ -f "$log" ] || continue - awk ' - /^TIME_BREAKDOWN / { - k = ""; c = ""; op = ""; - for (i = 1; i <= NF; i++) { - split($i, a, "="); - if (a[1] == "K") k = a[2]; - else if (a[1] == "CASE") c = a[2]; - else if (a[1] == "OP") op = a[2]; - } - next; - } - /^ STATE / { - state = $2; - cycles = ""; - time_ns = ""; - for (i = 1; i <= NF; i++) { - split($i, a, "="); - if (a[1] == "cycles") cycles = a[2]; - else if (a[1] == "time_ns") time_ns = a[2]; - } - if (time_ns != "") { - printf " %-7s %-3s %-5s %-12s %10d %12.3f\n", - op, k, c, state, cycles, time_ns / 1000.0; - } - } - ' "$log" - done +generate_kat_vectors() { + local op="$1" ksel="${2:-}" csel="${3:-}" + + validate_kat_selection "$ksel" "$csel" || return 1 + KAT_RUN_VECTOR_DIR="$KAT_TMP_BASE/$op" + rm -rf "$KAT_RUN_VECTOR_DIR" + mkdir -p "$KAT_RUN_VECTOR_DIR" + [ -d "$KAT_VECTOR_DIR/encgold" ] && ln -s "$KAT_VECTOR_DIR/encgold" "$KAT_RUN_VECTOR_DIR/encgold" + [ -d "$KAT_VECTOR_DIR/decgold" ] && ln -s "$KAT_VECTOR_DIR/decgold" "$KAT_RUN_VECTOR_DIR/decgold" + + python3 - "$SCRIPT_DIR" "$op" "${ksel:-all}" "${csel:-all}" "$KAT_RUN_VECTOR_DIR" <<'PY' +import pathlib +import sys + +root = pathlib.Path(sys.argv[1]) +op = sys.argv[2] +ksel = sys.argv[3] +csel = sys.argv[4] +out_dir = pathlib.Path(sys.argv[5]) + +ks = [2, 3, 4] if ksel == "all" else [int(ksel)] +case_filter = None if csel == "all" else int(csel) +rsp_by_k = { + 2: root / "test_data" / "kat_MLKEM_512.rsp", + 3: root / "test_data" / "kat_MLKEM_768.rsp", + 4: root / "test_data" / "kat_MLKEM_1024.rsp", +} + +def parse_rsp(path): + records = [] + cur = {} + with path.open("r", encoding="ascii") as f: + for raw in f: + line = raw.strip() + if not line or line.startswith("#") or " = " not in line: + continue + key, val = line.split(" = ", 1) + if key == "count": + if cur: + records.append(cur) + cur = {"count": int(val)} + else: + cur[key] = val.lower() + if cur: + records.append(cur) + return records + +def bytes_of(hexstr, field, count, k): + if len(hexstr) % 2: + raise SystemExit(f"odd hex length for {field}, K={k}, count={count}") + return [hexstr[i:i + 2] for i in range(0, len(hexstr), 2)] + +def write_bytes(path, hexstr, field, count, k): + data = bytes_of(hexstr, field, count, k) + path.write_text("".join(b + "\n" for b in data), encoding="ascii") + +def write_word256_reversed(path, hexstr, field, count, k): + data = bytes_of(hexstr, field, count, k) + if len(data) != 32: + raise SystemExit(f"{field} must be 32 bytes, got {len(data)}, K={k}, count={count}") + path.write_text("".join(reversed(data)) + "\n", encoding="ascii") + +def require(rec, keys, k): + missing = [key for key in keys if key not in rec] + if missing: + raise SystemExit(f"missing {','.join(missing)} in K={k}, count={rec.get('count')}") + +summary = [] +for k in ks: + records = parse_rsp(rsp_by_k[k]) + wrote = 0 + for rec in records: + count = rec["count"] + if case_filter is not None and count != case_filter: + continue + tag = f"k{k}" + if op == "top": + require(rec, ["d", "z", "pk", "sk"], k) + base = out_dir / f"kat_{tag}_c{count}" + write_word256_reversed(base.with_name(base.name + "_d.hex"), rec["d"], "d", count, k) + write_word256_reversed(base.with_name(base.name + "_z.hex"), rec["z"], "z", count, k) + write_bytes(base.with_name(base.name + "_ek.hex"), rec["pk"], "pk", count, k) + write_bytes(base.with_name(base.name + "_dk.hex"), rec["sk"], "sk", count, k) + elif op == "enc": + require(rec, ["pk", "msg", "ct", "ss"], k) + base = out_dir / f"enc_{tag}_c{count}" + write_bytes(base.with_name(base.name + "_ek.hex"), rec["pk"], "pk", count, k) + write_bytes(base.with_name(base.name + "_m.hex"), rec["msg"], "msg", count, k) + write_bytes(base.with_name(base.name + "_ct.hex"), rec["ct"], "ct", count, k) + write_bytes(base.with_name(base.name + "_ss.hex"), rec["ss"], "ss", count, k) + elif op == "dec": + require(rec, ["sk", "ct", "ss", "ct_n", "ss_n"], k) + base = out_dir / f"dec_{tag}_c{count}" + write_bytes(base.with_name(base.name + "_dk.hex"), rec["sk"], "sk", count, k) + write_bytes(base.with_name(base.name + "_ct.hex"), rec["ct"], "ct", count, k) + write_bytes(base.with_name(base.name + "_ss.hex"), rec["ss"], "ss", count, k) + write_bytes(base.with_name(base.name + "_ctn.hex"), rec["ct_n"], "ct_n", count, k) + write_bytes(base.with_name(base.name + "_ssn.hex"), rec["ss_n"], "ss_n", count, k) + else: + raise SystemExit(f"unknown KAT op: {op}") + wrote += 1 + if case_filter is not None and wrote == 0: + raise SystemExit(f"CASE={case_filter} not found in {rsp_by_k[k]}") + summary.append(f"K={k}:{wrote}") + +print(f" generated {op} KAT vector files ({', '.join(summary)})") +PY +} + +kat_cases_for() { + local op="$1" k="$2" prefix suffix + local dir="${KAT_RUN_VECTOR_DIR:-$KAT_VECTOR_DIR}" + case "$op" in + top) prefix="kat_k${k}_c"; suffix="_d\\.hex" ;; + enc) prefix="enc_k${k}_c"; suffix="_ek\\.hex" ;; + dec) prefix="dec_k${k}_c"; suffix="_dk\\.hex" ;; + *) echo "ERROR: unknown KAT op '$op'" >&2; return 1 ;; + esac + + find "$dir" -maxdepth 1 -type f -printf '%f\n' \ + | sed -n "s/^${prefix}\([0-9][0-9]*\)${suffix}$/\1/p" \ + | sort -n \ + | tr '\n' ' ' } run_xsim_jobs() { local mtag="$1" pgrep="$2" pmatch="$3"; shift 3 local specs=("$@") local repo; repo="$(pwd)" + local max_jobs="${RUN_TB_JOBS:-}" + if [ -z "$max_jobs" ]; then + if command -v nproc >/dev/null 2>&1; then + max_jobs="$(nproc)" + [ "$max_jobs" -gt 4 ] && max_jobs=4 + else + max_jobs=4 + fi + fi + case "$max_jobs" in + ''|*[!0-9]*|0) echo "ERROR: RUN_TB_JOBS must be a positive integer (got '$max_jobs')"; return 1 ;; + esac + rm -rf "$PAR_BASE"; mkdir -p "$PAR_BASE" + echo " launching ${#specs[@]} xsim job(s), parallelism=$max_jobs" # launch all jobs in parallel - local s snap k c wd + local s snap k c wd active=0 launched=0 total_specs=${#specs[@]} for s in "${specs[@]}"; do IFS=: read -r snap k c <<< "$s" + launched=$((launched + 1)) + if [ -t 1 ]; then + printf "\r running [%d/%d] K=%s CASE=%s" "$launched" "$total_specs" "$k" "$c" + else + echo " running [$launched/$total_specs] K=$k CASE=$c" + fi wd="$PAR_BASE/${mtag}_k${k}_c${c}" mkdir -p "$wd" cp -r "$repo/xsim.dir" "$wd/xsim.dir" - # The TB loads vectors via repo-relative $readmemh paths - # (sync_rtl/top/TB/vectors/...). xsim resolves these against the run - # cwd, so symlink the repo's sync_rtl tree into each private workdir. - ln -sf "$repo/sync_rtl" "$wd/sync_rtl" + # The TB loads vectors via repo-relative $readmemh paths. xsim resolves + # these against the run cwd, so mount the generated vector directory + # under each private workdir. + if [ -n "$KAT_RUN_VECTOR_DIR" ]; then + mkdir -p "$wd/sync_rtl/top/TB" + ln -sf "$KAT_RUN_VECTOR_DIR" "$wd/sync_rtl/top/TB/vectors" + else + ln -sf "$repo/sync_rtl" "$wd/sync_rtl" + fi ( cd "$wd" - echo " xsim $snap -R -testplusarg CASE=$c" - xsim "$snap" -R -testplusarg "CASE=$c" --nolog > "$wd/run.out" 2>&1 + { + echo "xsim $snap -R -testplusarg CASE=$c" + xsim "$snap" -R -testplusarg "CASE=$c" --nolog + } > "$wd/run.out" 2>&1 ) & + active=$((active + 1)) + if [ "$active" -ge "$max_jobs" ]; then + wait -n || true + active=$((active - 1)) + fi done - wait + wait || true + [ -t 1 ] && echo "" - # ordered summary + per-job log copy to /tmp/run_tb__k*_c*.log - local fail=0 pf nf log timing_logs=() + # ordered result aggregation + per-job log copy to /tmp/run_tb__k*_c*.log + local fail=0 pf nf log ok + local total=0 pass_count=0 fail_count=0 noresult_count=0 fnf_count=0 + local timing_logs=() failures=() for s in "${specs[@]}"; do IFS=: read -r snap k c <<< "$s" wd="$PAR_BASE/${mtag}_k${k}_c${c}" @@ -233,14 +363,38 @@ run_xsim_jobs() { timing_logs+=("$log") pf=$(grep -oE "$pgrep" "$log" | tail -1) nf=$(grep -c 'cannot be opened' "$log") - echo " K=$k CASE=$c -> ${pf:-NORESULT} (file-not-found=$nf, log: $log)" + total=$((total + 1)) + [ -n "$pf" ] || noresult_count=$((noresult_count + 1)) + [ "$nf" -eq 0 ] || fnf_count=$((fnf_count + 1)) + # pmatch == "PASS*" means "any PASS (Dn) stage tag"; else exact match. if [ "$pmatch" = "PASS*" ]; then - { [[ "$pf" == PASS* ]] && [ "$nf" -eq 0 ]; } || fail=1 + [[ "$pf" == PASS* ]] && [ "$nf" -eq 0 ]; ok=$? else - { [ "$pf" = "$pmatch" ] && [ "$nf" -eq 0 ]; } || fail=1 + [ "$pf" = "$pmatch" ] && [ "$nf" -eq 0 ]; ok=$? + fi + + if [ "$ok" -eq 0 ]; then + pass_count=$((pass_count + 1)) + else + fail=1 + fail_count=$((fail_count + 1)) + if [ "${#failures[@]}" -lt 20 ]; then + failures+=("K=$k CASE=$c -> ${pf:-NORESULT} (file-not-found=$nf, log: $log)") + fi fi done + + echo "" + echo "Result summary: total=$total success=$pass_count failure=$fail_count noresult=$noresult_count file-not-found=$fnf_count" + if [ "$fail_count" -gt 0 ]; then + echo "Failed cases (first ${#failures[@]} of $fail_count):" + local item + for item in "${failures[@]}"; do + echo " $item" + done + fi + print_timing_summary "${timing_logs[@]}" rm -rf "$PAR_BASE" return $fail @@ -248,11 +402,12 @@ run_xsim_jobs() { # Fast single-K / single-case path for the 'top' (ML-KEM KeyGen) module. # Compiles the same RTL as the tcl, but elaborates ONLY the requested K and -# runs the CASE(s) in parallel. Avoids the 3-snapshot + 11-run serial sweep. +# runs the generated/enumerated CASE(s) through the bounded parallel launcher. run_top_selected() { local tcl_file="$1" ksel="$2" csel="$3" set +e # we do our own error handling / result parsing here + generate_kat_vectors top "$ksel" "$csel" || return 1 rm -rf xsim.dir .Xil # Compile every xvlog line from the tcl, verbatim. @@ -267,10 +422,13 @@ run_top_selected() { echo " xelab tb_mlkem_kg_katK_xsim -generic_top KP=$k -s mlkem_kg_k$k --timescale 1ns/1ps" xelab tb_mlkem_kg_katK_xsim -generic_top KP=$k -s mlkem_kg_k$k --timescale 1ns/1ps \ || { echo "ELAB FAILED for K=$k"; return 1; } - # Cases per K: K=2 has 0..4, K=3/4 have 0..2. local cases - if [ "$k" = "2" ]; then cases="0 1 2 3 4"; else cases="0 1 2"; fi - if [ -n "$csel" ]; then cases="$csel"; fi + if [ -n "$csel" ]; then + cases="$csel" + else + cases="$(kat_cases_for top "$k")" + fi + [ -n "$cases" ] || { echo "ERROR: no KeyGen KAT cases found for K=$k"; return 1; } local c for c in $cases; do specs+=("mlkem_kg_k$k:$k:$c"); done done @@ -285,6 +443,7 @@ run_enc_selected() { local tcl_file="$1" ksel="$2" csel="$3" set +e + generate_kat_vectors enc "$ksel" "$csel" || return 1 rm -rf xsim.dir .Xil # Compile every xvlog line from the tcl EXCEPT the KeyGen TB (the encaps TB @@ -306,8 +465,13 @@ run_enc_selected() { echo " xelab tb_mlkem_enc_katK_xsim -generic_top KP=$k -s mlkem_enc_k$k --timescale 1ns/1ps" xelab tb_mlkem_enc_katK_xsim -generic_top KP=$k -s mlkem_enc_k$k --timescale 1ns/1ps \ || { echo "ELAB FAILED for K=$k"; return 1; } - local cases="0 1 2" - if [ -n "$csel" ]; then cases="$csel"; fi + local cases + if [ -n "$csel" ]; then + cases="$csel" + else + cases="$(kat_cases_for enc "$k")" + fi + [ -n "$cases" ] || { echo "ERROR: no Encaps KAT cases found for K=$k"; return 1; } local c for c in $cases; do specs+=("mlkem_enc_k$k:$k:$c"); done done @@ -321,6 +485,7 @@ run_dec_selected() { local tcl_file="$1" ksel="$2" csel="$3" set +e + generate_kat_vectors dec "$ksel" "$csel" || return 1 rm -rf xsim.dir .Xil while read -r cmd; do @@ -338,8 +503,13 @@ run_dec_selected() { echo " xelab tb_mlkem_dec_katK_xsim -generic_top KP=$k -s mlkem_dec_k$k --timescale 1ns/1ps" xelab tb_mlkem_dec_katK_xsim -generic_top KP=$k -s mlkem_dec_k$k --timescale 1ns/1ps \ || { echo "ELAB FAILED for K=$k"; return 1; } - local cases="0 1 2" - if [ -n "$csel" ]; then cases="$csel"; fi + local cases + if [ -n "$csel" ]; then + cases="$csel" + else + cases="$(kat_cases_for dec "$k")" + fi + [ -n "$cases" ] || { echo "ERROR: no Decaps KAT cases found for K=$k"; return 1; } local c for c in $cases; do specs+=("mlkem_dec_k$k:$k:$c"); done done diff --git a/sync_rtl/sample_ntt/TB/gen_vectors.py b/sync_rtl/sample_ntt/TB/gen_vectors.py index bea0df4..c30575a 100644 --- a/sync_rtl/sample_ntt/TB/gen_vectors.py +++ b/sync_rtl/sample_ntt/TB/gen_vectors.py @@ -1,34 +1,22 @@ #!/usr/bin/env python3 -"""gen_vectors.py - Test vector generator for sample_ntt_sync module. +"""Generate FIPS 203 SampleNTT test vectors for sample_ntt_sync. -Generates random rho+k+i+j test vectors, computes expected coefficients using -Keccak-p[1600, 24] matching the RTL's per-permutation squeeze pattern. +The reference oracle is hashlib.shake_128 (FIPS 202). It samples +SHAKE128(rho || j || i) by reading three bytes at a time and accepting +d1 = b0 + 256 * (b1 mod 16) and d2 = floor(b1 / 16) + 16 * b2 when d < Q. -The RTL sample_ntt_sync absorbs rho || j || i, then repeatedly permutes -the keccak state, extracting d1,d2 from bits [23:0] of each permuted state -with rejection sampling (d < Q=3329). - -Algorithm (matching RTL exactly): - 1. Build absorb state: pad10*1 padding for SHAKE-128 (rate=1344) on msg(272b) - 2. state = keccak_p(absorb_state) - 3. Extract d1 = (state[11:8] << 8) | state[7:0] - d2 = (state[23:16] << 4) | state[15:12] - 4. If d1 < Q: output d1 (12-bit unsigned) - 5. If d2 < Q: output d2 - 6. state = keccak_p(state) - 7. Repeat 3-6 until 256 coefficients collected - -Bit ordering (FIPS 202 / RTL match): - The RTL feeds rho_i[0] as the first message bit into SHA3. - $readmemh stores hex MSB-first → rho_i[255:0] in MSB-first order. - Python: input bytes = reversed(bytes.fromhex(rho_hex)) + bytes([j, i]) +The RTL feeds rho_i[0] as the first message byte. $readmemh loads +rho_i[255:0] MSB-first, so Python passes +reversed(bytes.fromhex(rho_hex)) + bytes([j, i]) to SHAKE-128. Usage: python3 gen_vectors.py # Generate vectors python3 gen_vectors.py --verify # Verify results against expected - python3 gen_vectors.py --selftest # Run Keccak-p self-test + python3 gen_vectors.py --refresh-expected # Recompute checked-in oracle + python3 gen_vectors.py --selftest # Run Keccak-p self-test """ +import hashlib import os import random import sys @@ -36,6 +24,15 @@ import sys Q = 3329 N_COEFFS = 256 +# This vector accepts its 256th coefficient as d2 from group 168, the final +# group of a SHAKE-128 rate block. It guards the no-extra-permutation boundary. +RATE_BOUNDARY_VECTOR = { + "rho_hex": "7484937160DBF5D93F7D69AEA2DF7C7C77B3A6B02D6B4D579CF975E6F8562097", + "k": 2, + "i": 1, + "j": 1, +} + # ====================================================================== # Keccak-p[1600, 24] implementation (stdlib only, matches RTL exactly) # ====================================================================== @@ -269,10 +266,7 @@ def extract_d1_d2(state): def sample_ntt_compute(rho_hex, k, i, j): - """Compute expected coefficients matching RTL sample_ntt_sync. - - The RTL absorbs rho || j || i, then repeatedly permutes, - extracting d1,d2 from each permuted state with rejection sampling. + """Compute the FIPS 203 SampleNTT output for one matrix polynomial. Args: rho_hex: 64-char hex string. @@ -283,22 +277,29 @@ def sample_ntt_compute(rho_hex, k, i, j): Returns: list of 256 integers in [0, Q-1]. """ - state = build_absorb_state(rho_hex, j, i) - state = keccak_p(state) - + del k + msg = bytes.fromhex(rho_hex)[::-1] + bytes([j & 0xFF, i & 0xFF]) coeffs = [] + out_len = 168 + processed = 0 + while len(coeffs) < N_COEFFS: - d1, d2 = extract_d1_d2(state) - if d1 < Q: - coeffs.append(d1) - if len(coeffs) == N_COEFFS: - break - if d2 < Q: - coeffs.append(d2) - if len(coeffs) == N_COEFFS: - break - # Re-permute for next squeeze - state = keccak_p(state) + stream = hashlib.shake_128(msg).digest(out_len) + for off in range(processed, len(stream) - 2, 3): + b0, b1, b2 = stream[off:off + 3] + d1 = b0 + 256 * (b1 & 0x0F) + d2 = (b1 >> 4) + 16 * b2 + + if d1 < Q: + coeffs.append(d1) + if len(coeffs) == N_COEFFS: + break + if d2 < Q: + coeffs.append(d2) + if len(coeffs) == N_COEFFS: + break + processed = out_len + out_len += 168 return coeffs @@ -367,9 +368,7 @@ def write_expected_hex(vectors, filepath): """Write expected coefficients: one 12-bit hex value per line.""" os.makedirs(os.path.dirname(filepath), exist_ok=True) with open(filepath, "w") as f: - for idx, v in enumerate(vectors): - f.write(f"# VECTOR_{idx} k={v['k']} i={v['i']} j={v['j']} " - f"rho={v['rho_hex']}\n") + for v in vectors: for c in v["coeffs"]: f.write(coeff_to_hex(c) + "\n") @@ -424,7 +423,7 @@ def main(): if "--selftest" in sys.argv: keccak_p_selftest() - print("Running quick smoke test on sample_ntt computation...") + print("Running FIPS SampleNTT reference self-test...") rho = "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" coeffs = sample_ntt_compute(rho, k=4, i=0, j=0) print(f" rho={rho[:16]}...: {len(coeffs)} coefficients") @@ -467,14 +466,33 @@ def main(): else: print("VERIFICATION FAILED") sys.exit(1) + elif "--refresh-expected" in sys.argv: + if not os.path.exists(input_file): + print(f"ERROR: Input file not found: {input_file}") + sys.exit(1) + + vectors = [] + with open(input_file, "r") as f: + for line in f: + line = line.strip() + if not line: + continue + if len(line) != 66: + raise ValueError(f"invalid packed input vector: {line}") + header = int(line[:2], 16) + vectors.append({ + "rho_hex": line[2:], + "k": header & 0x7, + "i": (header >> 3) & 0x3, + "j": (header >> 5) & 0x3, + }) + for v in vectors: + v["coeffs"] = sample_ntt_compute(v["rho_hex"], v["k"], v["i"], v["j"]) + write_expected_hex(vectors, expected_file) + print(f"Wrote {len(vectors)} FIPS SampleNTT expected vectors to {expected_file}") else: - # Generate mode — only input vectors (no expected outputs). - # The RTL uses per-permutation Keccak-p extraction that may not - # match standard SHAKE-128 bit-stream output. The TB performs a - # smoke test: 256 coefficients, each in [0, Q-1]. vector_count = 4 print(f"Generating {vector_count} random input vectors...") - print(f"(Expected outputs are NOT computed — TB uses smoke-test only.)") vectors = [] for idx in range(vector_count): @@ -490,8 +508,15 @@ def main(): }) print(f" Vector {idx}: k={k}, i={i}, j={j}, rho={rho_hex[:8]}...") + vectors.append(RATE_BOUNDARY_VECTOR.copy()) + print(" Boundary vector: k=2, i=1, j=1 (256th coefficient is group 168 d2)") + write_input_hex(vectors, input_file) + for v in vectors: + v["coeffs"] = sample_ntt_compute(v["rho_hex"], v["k"], v["i"], v["j"]) + write_expected_hex(vectors, expected_file) print(f"Wrote {len(vectors)} vectors to {input_file}") + print(f"Wrote FIPS SampleNTT expected values to {expected_file}") if __name__ == "__main__": diff --git a/sync_rtl/sample_ntt/TB/tb_sample_ntt_xsim.v b/sync_rtl/sample_ntt/TB/tb_sample_ntt_xsim.v index 28a50d4..b6378ca 100644 --- a/sync_rtl/sample_ntt/TB/tb_sample_ntt_xsim.v +++ b/sync_rtl/sample_ntt/TB/tb_sample_ntt_xsim.v @@ -1,10 +1,7 @@ -// tb_sample_ntt_xsim.v - Vivado xsim smoke-test testbench for sample_ntt_sync +// tb_sample_ntt_xsim.v - Vivado xsim FIPS SampleNTT testbench // -// Drives the DUT with test vectors from a hex file, then verifies that -// the DUT produces exactly 256 coefficients, each in range [0, Q-1]. -// This is a smoke test — it does NOT compare against Python expected values -// because the RTL uses a per-permutation Keccak-p approach that differs -// from standard SHAKE-128 bit-stream semantics. +// Drives the DUT with test vectors from a hex file and checks every coefficient +// against the FIPS 203 reference generated by gen_vectors.py. // // Vector format (packed hex, 66 chars for $readmemh): // {j_idx[1:0], i_idx[1:0], k_i[2:0], rho_i[255:0]} (264 bits → 66 hex chars) @@ -16,7 +13,8 @@ // // Prerequisites: // - Generate vectors: python3 TB/gen_vectors.py -// - Output file: vectors/sample_ntt_input.hex +// - Or refresh expected vectors: python3 TB/gen_vectors.py --refresh-expected +// - Output files: vectors/sample_ntt_input.hex, vectors/sample_ntt_expected.hex `timescale 1ns / 1ps @@ -25,11 +23,13 @@ module tb_sample_ntt_xsim; // ================================================================ // Parameters // ================================================================ - parameter VECTOR_FILE = "sync_rtl/sample_ntt/TB/vectors/sample_ntt_input.hex"; - parameter MAX_VECTORS = 32; // max lines in input file - parameter Q = 3329; // ML-KEM modulus - parameter N_COEFFS = 256; // coefficients per polynomial - parameter TIMEOUT = 500000; // per-vector timeout (cycles) + parameter VECTOR_FILE = "sync_rtl/sample_ntt/TB/vectors/sample_ntt_input.hex"; + parameter EXPECTED_FILE = "sync_rtl/sample_ntt/TB/vectors/sample_ntt_expected.hex"; + parameter MAX_VECTORS = 32; // allocation limit for input vectors + parameter VECTOR_COUNT = 5; // vectors present in VECTOR_FILE + parameter Q = 3329; // ML-KEM modulus + parameter N_COEFFS = 256; // coefficients per polynomial + parameter TIMEOUT = 500000; // per-vector timeout (cycles) // ================================================================ // DUT signals @@ -75,6 +75,7 @@ module tb_sample_ntt_xsim; // Vector memory (loaded by $readmemh) // ================================================================ reg [263:0] vector_mem [0:MAX_VECTORS-1]; + reg [11:0] expected_mem [0:MAX_VECTORS*N_COEFFS-1]; integer vec_count; integer idx; integer cycle_count; @@ -88,27 +89,14 @@ module tb_sample_ntt_xsim; // Main test sequence // ================================================================ initial begin - vec_count = 0; - // Load vectors from hex file $readmemh(VECTOR_FILE, vector_mem); + $readmemh(EXPECTED_FILE, expected_mem); - // Count non-zero/X entries to determine actual vector count - begin - integer found_end; - found_end = 0; - for (idx = 0; idx < MAX_VECTORS; idx = idx + 1) begin - if (!found_end && (vector_mem[idx] === {264{1'bx}} || vector_mem[idx] === {264{1'bz}})) - found_end = 1; - else if (!found_end) - vec_count = vec_count + 1; - end - end - - if (vec_count == 0) begin - $display("ERROR: No vectors loaded from %s", VECTOR_FILE); - $display(" Check that the file exists and is in the correct format."); - $display(" Each line: <66 hex chars> = {j, i, k, rho}"); + vec_count = VECTOR_COUNT; + if (vec_count < 1 || vec_count > MAX_VECTORS) begin + $display("ERROR: VECTOR_COUNT=%0d must be in [1,%0d]", + vec_count, MAX_VECTORS); $finish; end @@ -141,6 +129,8 @@ module tb_sample_ntt_xsim; reg [1:0] vec_i; reg [1:0] vec_j; reg range_ok; + reg coeff_ok; + reg last_ok; // Extract fields from packed vector_mem // vector_mem[263:0] = {1'b0, j_idx, i_idx, k_i, rho_i} @@ -170,18 +160,31 @@ module tb_sample_ntt_xsim; coeff_idx = 0; cycle_count = 0; range_ok = 1'b1; // assume OK until proven otherwise + coeff_ok = 1'b1; + last_ok = 1'b1; while (coeff_idx < N_COEFFS && cycle_count < TIMEOUT) begin @(posedge clk); cycle_count = cycle_count + 1; if (valid_o) begin + if (coeff_o !== expected_mem[idx*N_COEFFS + coeff_idx]) begin + $display("ERROR: Vector %0d coeff[%0d] mismatch: got=%03h expected=%03h", + idx, coeff_idx, coeff_o, + expected_mem[idx*N_COEFFS + coeff_idx]); + coeff_ok = 1'b0; + end // Check range: coefficient must be in [0, Q-1] if (coeff_o >= Q) begin $display("ERROR: Vector %0d coeff[%0d]=%0d out of range [0,%0d]", idx, coeff_idx, coeff_o, Q-1); range_ok = 1'b0; end + if (last_o !== (coeff_idx == N_COEFFS-1)) begin + $display("ERROR: Vector %0d coeff[%0d] last_o=%b expected=%b", + idx, coeff_idx, last_o, coeff_idx == N_COEFFS-1); + last_ok = 1'b0; + end coeff_idx = coeff_idx + 1; end end @@ -199,8 +202,16 @@ module tb_sample_ntt_xsim; $display("ERROR: Vector %0d produced out-of-range coefficients", idx); fail_count = fail_count + 1; + end else if (!coeff_ok) begin + $display("ERROR: Vector %0d did not match FIPS SampleNTT", + idx); + fail_count = fail_count + 1; + end else if (!last_ok) begin + $display("ERROR: Vector %0d asserted last_o on the wrong coefficient", + idx); + fail_count = fail_count + 1; end else begin - $display("INFO: Vector %0d PASSED (%0d coefficients in %0d cycles, all in range)", + $display("INFO: Vector %0d PASSED (%0d FIPS-matching coefficients in %0d cycles)", idx, coeff_idx, cycle_count); pass_count = pass_count + 1; end diff --git a/sync_rtl/sample_ntt/TB/vectors/sample_ntt_expected.hex b/sync_rtl/sample_ntt/TB/vectors/sample_ntt_expected.hex index 8df0881..4e2f7e4 100644 --- a/sync_rtl/sample_ntt/TB/vectors/sample_ntt_expected.hex +++ b/sync_rtl/sample_ntt/TB/vectors/sample_ntt_expected.hex @@ -1,1028 +1,1280 @@ -# VECTOR_0 k=3 i=1 j=0 rho=F6E5D64607BA30905E9F3976195E2B9A0C82BE0DB27480902BA8CA44BAAF0F50 -81D -C75 -1DE -355 -7A4 -037 -2DD -07F -8AD -69A -180 -CBF -A57 -251 -7DC -7C1 -BC4 -4A7 -838 -B7A -865 -B77 -7BD -22D -1E1 -B6E -110 -96F -C06 -152 -7F7 -1CD -545 -77D -BBD -9F9 -4CC -C90 -44D -239 -3FC -81C -9F6 -8EA -3E6 -A49 -B5E -913 -CA1 -314 -555 -000 -250 -63A -1F3 -79B -795 -1F1 -BA0 -AF4 -967 -0E6 -AF2 -526 -6A3 -35F -595 -47E -660 -2C4 -CFD -603 -1F7 -21E -BFE -0B7 -4E4 -35E -1CA -CD9 -0BF -C7D -37B -28D -BAD -241 -7C0 -429 -172 -A07 -C95 -C16 -888 -A78 -C81 -A03 -172 -74D -B6B -C1A -2AC -912 -281 -C44 -776 -AE7 -453 -1EC -58E -1D1 -01D -5B0 -611 -93A -6C6 -35C -90A -634 -020 -21C -322 -763 -2CA -9E5 -084 -37C -CFD -1C2 -812 -0F7 -30D -19F -67D -7EC -53B -B16 -B1F -79E -281 -933 -4E2 -C1F -AAF -33A -36A -8C6 -020 -C81 -2E5 -95F -B62 -837 -243 -8BB -3CF -A4E -0B1 -0A2 -A81 -854 -988 -166 -606 -4E4 -417 -C72 -360 -809 -6FB -552 -912 -729 -B80 -5EC -02F -9EB -AF7 -241 -33F -C98 -6FC -719 -5FA -3C0 -0D7 -8FC -1BC -7A5 -AB5 -40D -132 -081 -A8F -8C6 -0B1 -11C -82E -827 -917 -8C2 -673 -26B -0F1 -433 -633 -587 -5C9 -536 -6E9 -405 -AAA -157 -1BC -504 -CA9 -190 -B26 -9E3 -126 -5C8 -015 -180 -C42 -549 -232 -C12 -182 -B64 -C91 -C03 -A16 -2D9 -BFC -89D -772 -CF9 -801 -CD0 -7E4 -C5C -6BD -9DD -75D -6B4 -975 -3B0 -662 -A5D -57E -368 -33C -1CC -632 -87E -3D5 -67B -# VECTOR_1 k=4 i=2 j=0 rho=EF02248243A8FDAC343C3B298DEA5CEAA2F520D79153B4D3F7009ED90D0E63FA -143 -508 -5BA -508 -B33 -648 -2A2 -AC2 -174 -769 -960 -41A -457 -3B9 -18E -343 -B52 -990 -A58 -037 -B67 -989 -C74 -7D8 -70C -510 -43B -355 -8C2 -816 -9E4 -073 -AA8 -A26 -9C8 -740 -287 -018 -92C -9B8 -BF6 -A4A -6D9 -1C0 -14D -590 -3A3 -8BF -3AA -90D -2DB -58F -A2C -62C -5A8 -747 -BAC -772 -6CD -4E8 -1FE -566 -374 -243 -279 -054 -571 -2E6 -0F2 -C57 -C31 -282 -C7A -2A7 -7DC -A82 -7C1 -710 -A9D -398 -B80 -1E5 -78D -B45 -AE4 -404 -1DA -10D -7FD -520 -54F -1C4 -67F -5E3 -961 -614 -68F -16E -272 -391 -95F -A19 -120 -BF5 -361 -5C6 -042 -4FE -AA8 -90D -C52 -7B5 -C64 -BD7 -BA9 -898 -00C -8E2 -185 -AA1 -A21 -13D -C37 -00E -741 -969 -8CC -577 -261 -A22 -C24 -41A -BAF -BEA -62E -9C7 -15D -297 -762 -2BC -C40 -17D -0E3 -124 -8B2 -57A -CB0 -2DC -356 -799 -0E3 -235 -8E3 -15F -185 -613 -225 -213 -B27 -A26 -702 -CCB -86C -730 -981 -4AD -7F8 -609 -ACA -81E -833 -131 -844 -AEE -82D -012 -48B -B4B -295 -CE1 -6F4 -B0E -812 -62B -500 -CC0 -22E -85C -44F -1E1 -9BC -878 -883 -047 -26F -223 -9BA -5A6 -5A8 -5EF -2DA -C6A -119 -3BB -42B -7D1 -C5C -A07 -C02 -73B -93F -C5E -CD8 -6C8 -256 -99F -730 -945 -3FE -85E -C8C -3CA -7F3 -C9A -2A9 -B1A -757 -609 -00F -1A6 -1CC -6BF -885 -8AF -B1F -8E5 -3E2 -B97 -36D -54B -C18 -6F6 -BAE -17D -99B -6C2 -3BC -A5C -5E8 -563 -1FC -C55 -294 -741 -0AC -B58 -# VECTOR_2 k=4 i=0 j=1 rho=A606EFDC962E55F0BC95332332D82BCC5ACB04497FA99EF06A1D71BF11AF8297 -155 -4E7 -823 -445 -C42 -B2C -244 -4AD -CF8 -BFF -8D2 -9D9 -4DB -8CE -50A -9B5 -502 -20C -72D -5C4 -09D -BD5 -294 -386 -BE4 -507 -132 -0C3 -23D -853 -609 -369 -CD7 -C0C -A95 -C2E -155 -770 -C61 -A04 -896 -399 -A7A -B74 -B23 -B12 -01D -4B2 -45E -A16 -670 -9C2 -7D5 -664 -75B -6D5 -ADC -C9A -03E -B3C -505 -1A1 -CE5 -BBD -CA0 -388 -2C2 -707 -6AA -326 -200 -584 -850 -76C -6A3 -734 -B74 -C80 -2A6 -3DA -965 -42A -238 -2CB -B1A -082 -7EC -0AD -2A6 -5FB -778 -C5F -6CB -03A -927 -BCF -C55 -634 -0AC -C34 -17F -996 -6C1 -008 -B9A -BE2 -BAE -936 -7D7 -4C6 -AF6 -885 -7E2 -0E6 -1D1 -863 -C82 -C52 -A06 -1EE -642 -6E1 -93E -38A -9A9 -7BF -769 -055 -324 -663 -7B7 -AEC -B20 -B20 -112 -4D2 -924 -6B3 -1A0 -86C -418 -2A8 -AB6 -95F -854 -3F7 -0AB -05C -6DE -AD2 -4EC -6E8 -5D4 -147 -238 -1F2 -91E -370 -AF9 -311 -810 -B33 -A80 -238 -295 -799 -380 -2DF -7E0 -ABC -BAB -033 -2C3 -AC1 -5B8 -409 -7AF -58D -56F -9E6 -006 -B35 -C62 -02E -8A9 -0B9 -794 -9EF -07D -04D -8DB -B31 -736 -4F1 -0E0 -68E -170 -58E -4B6 -A8D -604 -8AC -4D1 -B0E -78E -C94 -2B2 -344 -56F -358 -4E6 -020 -828 -591 -AE9 -2B1 -251 -5B1 -6D5 -17C -C5A -AF8 -9B8 -7E0 -0E7 -3B0 -4F2 -B38 -A93 -668 -851 -408 -45E -009 -053 -1D8 -234 -4D9 -8BC -385 -293 -0DE -12C -401 -2D4 -8F3 -02A -A6C -22F -613 -B53 -67C -7A0 -4AC -CCD -3AD -# VECTOR_3 k=2 i=0 j=2 rho=6F23F87730D6FE0FE18F27180ECA3DE60D0CA77846F40F8D5FB024030E0CEC0F -56D -A4F -586 -CA6 -960 -BBF -42D -583 -7C9 -19B -2A0 -14F -656 -792 -526 -A76 -4E3 -417 -3F9 -4B6 -707 -762 -459 -8EB -206 -476 -CF6 -AAB -C7E -7C9 -358 -38F -383 -73C -CFC -274 -2B9 -9C7 -420 -55E -87C -78B -A0D -7E0 -12C -05D -00B -502 -A8C -130 -CD2 -C7D -9AB -4E9 -5D5 -BF1 -825 -038 -9CC -10F +544 +B0C +CC3 86D -4BD -627 -A05 -995 -8CB -0AD -C4B -06B -463 -22C -ABC -797 -543 -396 -044 -42F -252 -A31 -1B0 -6FA -6A6 -7B3 -366 -6FD -7A0 -96F -002 -602 -A3B -C36 -040 -91E -741 -A33 -90C -C06 -3BE -940 -10E -C88 -0A0 -3D0 -347 -93C -62E -3DD -8FC -7F7 -29A -7BF -5C9 -61C -47A -63C -6B2 -118 -2AB -B97 -AD4 -269 -5AB -1BD -C5B -296 -BD0 -4C9 -A51 -A62 -91E -29B -190 -170 -7C5 -9D8 -676 -727 -4C1 -051 -455 -6D1 -64B -A00 -43A -606 -BCC -5F1 -4E9 -6E2 -995 -8B7 -811 -71F -646 -75D -B93 -174 -9E1 -B11 -4A7 -984 -633 -109 -8F6 -976 -CA5 -BC3 -136 -8A4 -83C -50F -066 -1E5 -834 -8A5 -CBE -9AF -939 -BD6 -5C2 -7D9 -04E -36B -116 -1DF -1D3 -417 -146 -405 -4D7 -4F7 -A4D -685 -18A -2E6 -03C -A38 -BEE -20E -A39 -10A -111 -867 -872 -B31 -84B -BAE -89A -2B2 -5BC -2E6 -32F -833 -232 -3F9 -315 -4AE -922 -934 -69A -4A5 -ADD -37F -0A7 -64B -857 -1BB -664 -5F7 -ADB -2CE -17C -60F -48F -68C -A83 -2BF -443 -A81 -20D -484 +8C5 +963 +346 +A04 +5CF +895 +454 +4FD +A5E +219 +73C +63F +095 +409 +030 863 -5F3 -853 -49D -C5B -B7A -9F2 -476 -571 -A57 +B2B +865 +C6A +792 +468 +846 +421 +92F +6D1 +13A +0CB +155 +47B +41A +C0E +12C +7A6 +B85 +31E +747 +9DD +3D8 +BCF +127 +5EB +3A2 +041 +1C1 +A92 +8CC +0B4 +664 +44D +896 +4F5 +AF1 +730 +0A9 +B79 +2A7 +4AF +5CC +160 +5BF +CD2 +5D4 +412 +025 +899 +733 +629 +AD7 +959 +66C +85A +3E1 +555 +89E +16B +A8C +05A +1A6 +A6B +49B +A37 +945 +18A +CA5 +515 +632 +895 +92E +3CB +1C3 +A2E +798 +1B9 +B7E +7E9 +9E7 +C41 +2B1 +065 +689 +997 +B0C +717 +6D2 +C87 +006 +574 +B91 +37D +BF5 +7FF +288 +C22 +800 +088 +257 +BA8 +12E +2B0 +9F7 +200 +697 +AC0 +8B9 +68B +CA2 +88A +20A +079 +111 +3D2 +88A +10E +28D +9B4 +2EE +34C +8E0 +147 +71E +C55 +83B +8A8 +01D +B50 +217 +58C +562 +8CD +A88 +797 +C9F +A55 +B42 +661 +97A +50C +A4E +9D3 +987 +123 +02C +941 +450 +548 +0D4 +61D +91B +C02 +534 +557 +65D +2D7 +5DD +6A0 +336 +54E +4B2 +61D +430 +32F +CBF +C0F +44E +30D +67E +3D9 +B20 +1B4 +972 +BB5 +377 +174 +26F +AE3 +B6A +507 +51E +ADD +38E +3BB +1C3 +7ED +AA2 +CD5 +227 +C63 +61F +4BC +2A2 +A94 +20F +3A4 +ADC +3DB +4EB +CEB +27B +B52 +6D6 +07D +8CA +2C9 +C91 +352 +C44 +C57 +483 +B54 +9E0 +1A4 +987 +8A0 +B9E +352 +9B5 +96D +C46 +65C +987 +37C +C61 +302 +281 +002 +6C1 +8B8 +203 +54B +4B6 +690 +8AC +0BB +1E6 +97F +885 +9B4 +806 +7BA +B3C +CBE +96C +562 +9ED +39E +45B +742 +3FF +8FD +466 +48A +164 +233 +C5F +6F6 +A43 +072 +929 +BA7 +2E3 +B11 +48B +7EA +8D9 +BA4 +3A4 +026 +059 +2D5 +0F8 +BDE +AB1 +9C5 +1DB +1E5 +11A +7F9 +61C +291 +51F +659 +76F +98D +ACC +961 +670 +A5D +2DC +CE8 +A92 +03C +7F1 +A4C +C7B +451 +CC8 +C34 +804 +048 +2DD +AC1 +1B4 +647 +124 +01B +649 +975 +413 +C83 +B4D +C7F +26E +11A +630 +2B7 +097 +7A3 +CA4 +773 +0FA +48A +050 +4FB +97E +AF6 +32C +C1F +B33 +343 +825 +2D0 +202 +521 +872 +CE4 +6BA +539 +86C +1CB +B38 +3F9 +148 +528 +4FD +391 +030 +C93 +39F +86B +5AF +08C +5C2 +3E0 +6C1 +380 +74F +6F5 +284 +228 +4BB +C80 +339 +8A4 +107 +9D8 +047 +335 +666 +AEC +0FA +380 +BE1 +C52 +C0E +49F +BFB +78B +7AA +64A +B6F +B2D +C3F +956 +709 +070 +941 +026 +2BE +CFF +A43 +AC0 +A76 +0D5 +554 +4A4 +6C7 +8D4 +386 +AA1 +A3F +751 +CB3 +5EB +AC8 +880 +7C6 +BBF +000 +25A +6C2 +638 +5AB +8CD +C81 +AAF +8DC +B80 +65A +A12 +408 +761 +19E +AF0 +28B +006 +67C +BB1 +26F +33D +949 +937 +9E6 +A07 +290 +787 +218 +7D5 +B17 +05A +54A +0CB +8D8 +643 +449 +9DA +78C +752 +000 +258 +7AB +442 +C37 +B5F +366 +4A9 +895 +CEC +715 +903 +3FB +AC4 +291 +3BF +172 +70B +5E9 +8AB +412 +7EC +A30 +1AD +B4E +339 +430 +136 +9CF +437 +56D +755 +6F7 +7BC +4C4 +C8E +8C3 +C03 +462 +12F +32B +B48 +04E +3E2 +12A +A33 +1E5 +342 +CCA +48D +6AA +A52 +2E2 +875 +2B5 +9AA +8CC +AB7 +04D +606 +929 +CFB +887 +4B8 +1C0 +585 +A3C +0BD +0D5 +7FC +19F +7A6 +562 +321 +2BF +391 +044 +38F +BF1 +04C +19D +8C0 +B40 +65B +4DF +AA4 +67A +C82 +2CC +C44 +30A +9B0 +7A6 +6C3 +262 +524 +CC3 +97B +640 +152 +9B7 +3EE +085 +908 +CAF +8E2 +7F2 +BA8 +6E4 +124 +99F +B18 +507 +314 +618 +528 +779 +4CA +5A3 +730 +B98 +6D5 +A46 +406 +637 +1BE +648 +9C2 +A2F +5A6 +370 +096 +A30 +998 +1F8 +50F +644 +490 +446 +4A7 +94F +5B8 +363 +8F3 +2CF +069 +308 +27B +8C4 +2CB +120 +9B6 +C85 +7B5 +4E1 +8F9 +9A5 +652 +38F +C02 +B46 +B0F +762 +8B5 +58F +205 +CE4 +81A +C03 +98A +8E1 +137 +0E3 +699 +3AC +4A4 +C22 +1D2 +9B9 +4C0 +B2D +506 +B30 +94B +63D +4CF +038 +BE4 +BEE +1CC +C39 +145 +2A6 +470 +847 +0BE +120 +005 +9B4 +4FF +84E +2EF +C5E +242 +320 +477 +B46 +534 +6D5 +92C +11B +1F7 +15A +96B +8BF +0E2 +2F2 +45C +8E5 +7E7 +1AC +C33 +321 +BD5 +02D +6A0 +B8F +266 +776 +595 +114 +371 +2F0 +959 +875 +C0D +704 +AA6 +850 +B89 +8B1 +735 +05E +130 +7DB +58F +24A +806 +652 +C94 +7B2 +C43 +963 +803 +1B9 +229 +688 +65B +6D4 +53A +A68 +67A +594 +13A +45A +6DF +8AB +54F +1F5 +A4C +754 +777 +A74 +635 +001 +97B +43B +485 +564 +69F +0D3 +296 +B56 +06D +016 +0A1 +024 +CA7 +9C7 +531 +AA4 +964 +A36 +3B0 +3E2 +951 +0FD +90E +547 +0D9 +074 +A6D +4E7 +A1E +509 +BF0 +99D 23C -460 -85C -0EB +02B +5E4 +9AE +73E +33B +AB3 +B2B +73B +A51 +43F +8CC +253 +779 +384 +CE2 +80F +382 +10A +B9F +BBC +184 +6B7 +B8E +085 +B11 +813 +673 +A27 +1C1 +761 +3AD +8A0 +19B +88E +CDA +334 +2A1 +62A +3E6 +73B +AEF +AC0 +3AC +A5C +C22 +1B1 +C37 +124 +A4B +37A +57D +434 +2F9 +C73 +938 +62D +7E3 +C5A +48F +780 +6BD +653 +32D +4CF +441 +3F9 +40C +C33 +3AE +8A6 +B71 +490 +214 +098 +604 +B0E +AF5 +747 +C24 +289 +052 +228 694 +A94 +196 +0A3 +766 +6AD +40F +181 +B63 +C7E +402 +C99 +06F +48E +660 +006 +B85 +BDB +5C9 +073 +3A3 +249 +5CC +CF8 +333 +BB5 +7E3 +185 +8DA +9BA +B96 +237 +9FE +705 +026 +B11 +B5C +C30 +B57 +370 +640 +654 +6D4 +725 +041 +7DA +42C +1C3 +1F9 +758 +762 +C42 +613 +182 +504 +0D1 +808 +9A4 +A25 +8B2 +049 +4F6 +66E +092 +3A8 +A89 +B71 +394 +9F0 +A65 +CC9 +577 +198 +B78 +002 +B55 +547 +055 +3F2 +0D6 +94C +514 +9C5 +A75 +945 +C9B +149 +33C +65D +935 +7E9 +B00 +AC3 +8B7 +BC1 +628 +7FF +9FF +74B +AE6 +617 +9D2 +234 +A65 +B2B +38F +162 +181 +89D +98E +785 +21D +6D5 +B86 +53C +89A +6DF +507 +405 +AE6 +863 +6CF +007 +1C3 +596 +242 +8A0 +192 +6AB +479 +3CF +BFD +06A +C6F +818 +9DD +51E +B0B +C5C +769 +4F4 +34F +5A1 +3D0 +6AD +A36 +827 +435 +708 +0B7 +547 +8A5 +8EA +1E5 +6E8 +A9E +BF6 +A35 +BDB +649 +23C +797 +88D +A2B +A30 +478 +494 +CB3 +B30 +1AD +338 +0E0 +CF8 +3B4 +478 +4A9 +C9C +144 +C96 +CF2 +8CB +733 +9DA +35F +C44 +307 +521 +180 +26C +B43 +393 +1C8 +492 +B82 +46B +7DA +7FC +B65 +ABF +303 +5FF +05F +577 +857 +CFD +AEE +119 +BDF +1F5 +8BE +37E +3FF +B4F +996 +7AB +9D9 +C0B +A3A +B23 +43A +6C8 +C04 +B35 +B69 +188 +78A +A66 +B09 +CFA +18D +2B6 +A4D +090 +15E +20F +177 +C5A +321 +8A0 +2AB +868 +012 +0FE +63A +6E3 +BD9 +612 +7AA +5D0 +2AC +123 +2B9 +CCA +916 +6B2 +5FD +AB2 +A18 +5A6 +CF2 +86D +48B +638 +6C7 +64A +85D +962 +5B1 +671 +296 +A18 +263 +229 +945 +46C +2B2 +B26 +579 +8FB +375 +684 +A25 +18B +C07 +CAF +72A +648 +172 +C8A +2A9 +200 +989 +8F5 +793 +87A +823 +0C6 +1F5 +A89 +C34 +399 +1CA +9AC +663 +864 +350 +A76 +A12 +C1A +6FA +7E7 +7B3 +0B4 +752 +B6B +16B +00F +87A +49C +096 +80C +B47 +41B +2A1 +9C2 +591 +1F6 +57D +409 +462 +17E +70F +B4A +665 +569 +848 +9A9 +CCD +49F +BA4 +830 +C03 +535 +0E5 +6BC +63C +A66 +C22 +B29 +8E8 +7FF +1CE +12F +548 +2A6 +C2F +219 +6D7 +4E1 +845 +9DF +6D7 +7BE +4ED +9F8 +013 +2E9 +ADB +46F +703 +A59 +8B4 +479 +048 +515 +4BE +AB9 +308 +187 +266 +A2D +6F1 +3E4 +115 +597 +B00 +0CF +7C3 +880 +4BF +1CB +D00 +0EE +76B +6E3 +6F0 +B3B +AF0 +7E6 +8E3 +4B1 +8E9 +2BF +5A7 +313 +249 +B85 +AB4 +596 +270 +8DB +935 +B7D +B36 +C49 +253 +742 +15D +7F0 diff --git a/sync_rtl/sample_ntt/TB/vectors/sample_ntt_input.hex b/sync_rtl/sample_ntt/TB/vectors/sample_ntt_input.hex index 92ebdda..f98256e 100644 --- a/sync_rtl/sample_ntt/TB/vectors/sample_ntt_input.hex +++ b/sync_rtl/sample_ntt/TB/vectors/sample_ntt_input.hex @@ -2,3 +2,4 @@ 12F9652FD859317D04232072A19A8A4E2ABE9A8D5402819FC53C33C337C6797E4B 52CFFFE52DCB27B795B608BD58C7D52D79367553276B2B54C039E0650A0D86AFDA 735E2459D975610B15D89165C144715F9D218BC08EE93CE6AD0B52F8FE751CAA56 +2A7484937160DBF5D93F7D69AEA2DF7C7C77B3A6B02D6B4D579CF975E6F8562097