feat: add Jasmin assembly integration for crypto acceleration
- Integrated `zupt_mac_verify_ct` in `zupt_decrypt_buffer()` to replace C XOR loop for HMAC-SHA256 - Integrated `zupt_ct_select_32` in `zupt_mlkem768_decaps()` to replace C `cmov()` for FO transformation - Added `include/zupt_jasmin.h` with extern declarations and ABI docs - Added `#ifdef ZUPT_USE_JASMIN` guards with clean C fallbacks in `zupt_crypto.c` and `zupt_mlkem.c` - Makefile now auto-detects `jasmin/*.s`, assembles and links with `-DZUPT_USE_JASMIN` Closes #3
This commit is contained in:
parent
cea317653e
commit
06c877ec86
43 changed files with 1913 additions and 546 deletions
25
tests/run_quick.sh
Normal file
25
tests/run_quick.sh
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh
|
||||
set +e
|
||||
Z="./zupt"; T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
|
||||
mkdir -p "$T/d"; echo "hello" > "$T/d/a.txt"
|
||||
dd if=/dev/urandom bs=1024 count=10 of="$T/d/b.bin" 2>/dev/null; touch "$T/d/e.txt"
|
||||
P=0; F=0; ok() { echo " OK: $1"; P=$((P+1)); }; fl() { echo " FAIL: $1"; F=$((F+1)); }
|
||||
echo "═══ Quick Test (9 tests) ═══"
|
||||
$Z compress "$T/1.zupt" "$T/d/" 2>/dev/null && $Z extract -o "$T/o1" "$T/1.zupt" 2>/dev/null
|
||||
E=$(find "$T/o1" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "Normal" || fl "Normal"
|
||||
$Z compress --solid "$T/2.zupt" "$T/d/" 2>/dev/null && $Z extract -o "$T/o2" "$T/2.zupt" 2>/dev/null
|
||||
E=$(find "$T/o2" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "Solid" || fl "Solid"
|
||||
$Z compress -p pw "$T/3.zupt" "$T/d/" 2>/dev/null && $Z extract -o "$T/o3" -p pw "$T/3.zupt" 2>/dev/null
|
||||
E=$(find "$T/o3" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "Encrypted" || fl "Encrypted"
|
||||
$Z extract -o "$T/o4" -p WRONG "$T/3.zupt" 2>/dev/null; [ $? -ne 0 ] && ok "Wrong pw" || fl "Wrong pw"
|
||||
$Z compress -t 4 "$T/5.zupt" "$T/d/" 2>/dev/null && $Z extract -o "$T/o5" "$T/5.zupt" 2>/dev/null
|
||||
E=$(find "$T/o5" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "MT" || fl "MT"
|
||||
$Z compress -f "$T/6.zupt" "$T/d/" 2>/dev/null && $Z extract -o "$T/o6" "$T/6.zupt" 2>/dev/null
|
||||
E=$(find "$T/o6" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "Fast" || fl "Fast"
|
||||
$Z compress -s "$T/7.zupt" "$T/d/" 2>/dev/null && $Z extract -o "$T/o7" "$T/7.zupt" 2>/dev/null
|
||||
E=$(find "$T/o7" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "Store" || fl "Store"
|
||||
$Z keygen -o "$T/k.key" 2>/dev/null && $Z keygen --pub -o "$T/p.key" -k "$T/k.key" 2>/dev/null
|
||||
$Z compress --pq "$T/p.key" "$T/8.zupt" "$T/d/" 2>/dev/null && $Z extract --pq "$T/k.key" -o "$T/o8" "$T/8.zupt" 2>/dev/null
|
||||
E=$(find "$T/o8" -name a.txt -type f 2>/dev/null|head -1); [ -n "$E" ] && diff -q "$T/d/a.txt" "$E" >/dev/null 2>&1 && ok "PQ" || fl "PQ"
|
||||
R=$($Z test "$T/1.zupt" 2>&1); echo "$R"|grep -q "0 failed" && ok "Integrity" || fl "Integrity"
|
||||
echo ""; echo " Results: $P passed, $F failed (9 tests)"; [ "$F" -eq 0 ] && exit 0 || exit 1
|
||||
48
tests/test_pq.sh
Normal file
48
tests/test_pq.sh
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/bin/sh
|
||||
set +e
|
||||
ZUPT="${1:-./zupt}"
|
||||
T="/tmp/zupt_pq_$$"; mkdir -p "$T/data"
|
||||
trap 'rm -rf "$T"' EXIT
|
||||
echo "Hello PQ World!" > "$T/data/hello.txt"
|
||||
dd if=/dev/urandom bs=1024 count=50 of="$T/data/rand.bin" 2>/dev/null
|
||||
yes "PQ test " | head -c 100000 > "$T/data/repeat.txt"
|
||||
touch "$T/data/empty.txt"
|
||||
cp "$ZUPT" "$T/data/elf.bin"
|
||||
PASS=0; FAIL=0
|
||||
pass() { echo " OK: $1"; PASS=$((PASS+1)); }
|
||||
fail() { echo " FAIL: $1"; FAIL=$((FAIL+1)); }
|
||||
echo "═══════════════════════════════════════"
|
||||
echo " PQ Hybrid Encryption Tests"
|
||||
echo "═══════════════════════════════════════"
|
||||
$ZUPT keygen -o "$T/priv.key" 2>/dev/null; [ -f "$T/priv.key" ] && pass "keygen" || fail "keygen"
|
||||
$ZUPT keygen --pub -o "$T/pub.key" -k "$T/priv.key" 2>/dev/null; [ -f "$T/pub.key" ] && pass "pubkey export" || fail "pubkey export"
|
||||
PS=$(stat -c%s "$T/priv.key" 2>/dev/null); PP=$(stat -c%s "$T/pub.key" 2>/dev/null)
|
||||
[ "$PS" = "3664" ] && [ "$PP" = "1232" ] && pass "key sizes" || fail "key sizes"
|
||||
$ZUPT compress --pq "$T/pub.key" "$T/pq.zupt" "$T/data/" 2>/dev/null; [ -f "$T/pq.zupt" ] && pass "PQ compress" || fail "PQ compress"
|
||||
$ZUPT extract --pq "$T/priv.key" -o "$T/pq_out" "$T/pq.zupt" 2>/dev/null
|
||||
B=0; for f in hello.txt rand.bin repeat.txt empty.txt elf.bin; do
|
||||
E=$(find "$T/pq_out" -name "$f" -type f 2>/dev/null|head -1)
|
||||
[ -z "$E" ]||! diff -q "$T/data/$f" "$E" >/dev/null 2>&1 && B=$((B+1))
|
||||
done; [ "$B" -eq 0 ] && pass "PQ round-trip (5 files)" || fail "PQ round-trip ($B mismatches)"
|
||||
R=$($ZUPT test --pq "$T/priv.key" "$T/pq.zupt" 2>&1)
|
||||
echo "$R"|grep -q "0 failed" && pass "PQ integrity" || fail "PQ integrity"
|
||||
$ZUPT keygen -o "$T/wrong.key" 2>/dev/null
|
||||
$ZUPT extract --pq "$T/wrong.key" -o "$T/bad" "$T/pq.zupt" 2>/dev/null
|
||||
[ $? -ne 0 ] && pass "Wrong key rejected" || fail "Wrong key NOT rejected"
|
||||
$ZUPT compress -p "pw" "$T/pw.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/pw_out" -p "pw" "$T/pw.zupt" 2>/dev/null
|
||||
E=$(find "$T/pw_out" -name "hello.txt" -type f|head -1)
|
||||
[ -n "$E" ] && diff -q "$T/data/hello.txt" "$E" >/dev/null 2>&1 && pass "Password backward compat" || fail "Password broken"
|
||||
$ZUPT compress -t 4 --pq "$T/pub.key" "$T/mt.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract --pq "$T/priv.key" -o "$T/mt_out" "$T/mt.zupt" 2>/dev/null
|
||||
B=0; for f in hello.txt rand.bin repeat.txt; do
|
||||
E=$(find "$T/mt_out" -name "$f" -type f 2>/dev/null|head -1)
|
||||
[ -z "$E" ]||! diff -q "$T/data/$f" "$E" >/dev/null 2>&1 && B=$((B+1))
|
||||
done; [ "$B" -eq 0 ] && pass "PQ+MT round-trip" || fail "PQ+MT ($B mismatches)"
|
||||
yes "Large PQ " | head -c 2000000 > "$T/large.txt"
|
||||
$ZUPT compress --pq "$T/pub.key" "$T/lg.zupt" "$T/large.txt" 2>/dev/null
|
||||
$ZUPT extract --pq "$T/priv.key" -o "$T/lg_out" "$T/lg.zupt" 2>/dev/null
|
||||
E=$(find "$T/lg_out" -name "large.txt" -type f|head -1)
|
||||
[ -n "$E" ] && diff -q "$T/large.txt" "$E" >/dev/null 2>&1 && pass "PQ large (2MB)" || fail "PQ large"
|
||||
echo ""; echo " PQ RESULTS: $PASS passed, $FAIL failed"
|
||||
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|
||||
219
tests/test_threaded.sh
Normal file
219
tests/test_threaded.sh
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
#!/bin/sh
|
||||
set +e
|
||||
ZUPT="./zupt"
|
||||
T="/tmp/zupt_mt_$$"
|
||||
PASS=0; FAIL=0; TOTAL=0
|
||||
mkdir -p "$T"
|
||||
trap 'rm -rf "$T"' EXIT
|
||||
|
||||
pass() { echo " OK: $1"; PASS=$((PASS+1)); TOTAL=$((TOTAL+1)); }
|
||||
fail() { echo " FAIL: $1"; FAIL=$((FAIL+1)); TOTAL=$((TOTAL+1)); }
|
||||
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo " ZUPT v0.6.0 Multi-Threaded Test Suite"
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
$ZUPT version 2>&1 | head -1
|
||||
echo ""
|
||||
|
||||
# Generate test data
|
||||
mkdir -p "$T/data/sub"
|
||||
echo "Hello, World!" > "$T/data/hello.txt"
|
||||
dd if=/dev/urandom bs=1024 count=500 of="$T/data/large_rand.bin" 2>/dev/null
|
||||
dd if=/dev/zero bs=1024 count=200 of="$T/data/sparse.bin" 2>/dev/null
|
||||
yes "The quick brown fox jumps over the lazy dog. " | head -c 2000000 > "$T/data/repeat_2m.txt"
|
||||
cp "$ZUPT" "$T/data/elf.bin"
|
||||
touch "$T/data/empty.txt"
|
||||
printf "X" > "$T/data/single.bin"
|
||||
seq 1 50000 > "$T/data/sub/numbers.txt"
|
||||
python3 -c "
|
||||
import json, random; random.seed(42)
|
||||
for i in range(5000):
|
||||
print(json.dumps({'id':i,'name':f'user_{i}','score':round(random.gauss(75,15),2)}))
|
||||
" > "$T/data/data.json" 2>/dev/null
|
||||
|
||||
# ─── T1: N=1 produces correct output ───
|
||||
echo "── T1: Single-thread (N=1) round-trip ──"
|
||||
$ZUPT compress -t 1 -l 7 "$T/t1.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t1_out" "$T/t1.zupt" 2>/dev/null
|
||||
BAD=0
|
||||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||||
EXTR=$(find "$T/t1_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||||
done
|
||||
[ "$BAD" -eq 0 ] && pass "N=1 round-trip (all files)" || fail "N=1 round-trip ($BAD mismatches)"
|
||||
|
||||
# ─── T2: N=2 produces correct output ───
|
||||
echo "── T2: Two threads (N=2) round-trip ──"
|
||||
$ZUPT compress -t 2 -l 7 "$T/t2.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t2_out" "$T/t2.zupt" 2>/dev/null
|
||||
BAD=0
|
||||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||||
EXTR=$(find "$T/t2_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||||
done
|
||||
[ "$BAD" -eq 0 ] && pass "N=2 round-trip (all files)" || fail "N=2 round-trip ($BAD mismatches)"
|
||||
|
||||
# ─── T3: N=4 produces correct output ───
|
||||
echo "── T3: Four threads (N=4) round-trip ──"
|
||||
$ZUPT compress -t 4 -l 7 "$T/t3.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t3_out" "$T/t3.zupt" 2>/dev/null
|
||||
BAD=0
|
||||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||||
EXTR=$(find "$T/t3_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||||
done
|
||||
[ "$BAD" -eq 0 ] && pass "N=4 round-trip (all files)" || fail "N=4 round-trip ($BAD mismatches)"
|
||||
|
||||
# ─── T4: N=8 produces correct output ───
|
||||
echo "── T4: Eight threads (N=8) round-trip ──"
|
||||
$ZUPT compress -t 8 -l 7 "$T/t4.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t4_out" "$T/t4.zupt" 2>/dev/null
|
||||
BAD=0
|
||||
for f in $(cd "$T/data" && find . -type f | sed 's|^\./||'); do
|
||||
EXTR=$(find "$T/t4_out" -name "$(basename $f)" -type f 2>/dev/null | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||||
done
|
||||
[ "$BAD" -eq 0 ] && pass "N=8 round-trip (all files)" || fail "N=8 round-trip ($BAD mismatches)"
|
||||
|
||||
# ─── T5: Large file (>10MB) at N=8 ───
|
||||
echo "── T5: Large file (10MB) at N=8 ──"
|
||||
yes "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 " | head -c 10485760 > "$T/large_10m.txt"
|
||||
$ZUPT compress -t 8 -l 5 "$T/t5.zupt" "$T/large_10m.txt" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t5_out" "$T/t5.zupt" 2>/dev/null
|
||||
EXTR=$(find "$T/t5_out" -name "large_10m.txt" -type f | head -1)
|
||||
if [ -n "$EXTR" ] && diff -q "$T/large_10m.txt" "$EXTR" >/dev/null 2>&1; then
|
||||
pass "10MB file N=8 round-trip"
|
||||
else fail "10MB file N=8 round-trip"; fi
|
||||
|
||||
# ─── T6: Many small files (1000 × 1KB) at N=8 ───
|
||||
echo "── T6: 1000 small files at N=8 ──"
|
||||
mkdir -p "$T/many"
|
||||
for i in $(seq 1 1000); do
|
||||
echo "File $i content: $(head -c 500 /dev/urandom | base64 | head -c 900)" > "$T/many/file_$i.txt"
|
||||
done
|
||||
$ZUPT compress -t 8 -l 5 "$T/t6.zupt" "$T/many/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t6_out" "$T/t6.zupt" 2>/dev/null
|
||||
EXTRACTED=$(find "$T/t6_out" -type f | wc -l)
|
||||
# Spot-check a few files
|
||||
SPOT_OK=1
|
||||
for i in 1 100 500 999 1000; do
|
||||
ORIG="$T/many/file_$i.txt"
|
||||
EXTR=$(find "$T/t6_out" -name "file_$i.txt" -type f | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$ORIG" "$EXTR" >/dev/null 2>&1; then SPOT_OK=0; fi
|
||||
done
|
||||
if [ "$EXTRACTED" -eq 1000 ] && [ "$SPOT_OK" -eq 1 ]; then
|
||||
pass "1000 small files N=8 ($EXTRACTED files)"
|
||||
else fail "1000 small files N=8 ($EXTRACTED files, spot=$SPOT_OK)"; fi
|
||||
|
||||
# ─── T7: Empty file in MT archive ───
|
||||
echo "── T7: Empty file in MT archive ──"
|
||||
touch "$T/empty_test.txt"
|
||||
echo "notempty" > "$T/notempty.txt"
|
||||
$ZUPT compress -t 4 -l 5 "$T/t7.zupt" "$T/empty_test.txt" "$T/notempty.txt" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t7_out" "$T/t7.zupt" 2>/dev/null
|
||||
EXTR_EMPTY=$(find "$T/t7_out" -name "empty_test.txt" -type f | head -1)
|
||||
if [ -n "$EXTR_EMPTY" ] && [ "$(wc -c < "$EXTR_EMPTY")" = "0" ]; then
|
||||
pass "Empty file in MT archive"
|
||||
else fail "Empty file in MT archive"; fi
|
||||
|
||||
# ─── T8: Encrypted at N=8 ───
|
||||
echo "── T8: Encrypted compress+extract at N=8 ──"
|
||||
$ZUPT compress -t 8 -l 5 -p "TestMT#2026" "$T/t8.zupt" "$T/data/" 2>/dev/null
|
||||
$ZUPT extract -o "$T/t8_out" -p "TestMT#2026" "$T/t8.zupt" 2>/dev/null
|
||||
BAD=0
|
||||
for f in hello.txt large_rand.bin repeat_2m.txt elf.bin empty.txt single.bin; do
|
||||
EXTR=$(find "$T/t8_out" -name "$f" -type f 2>/dev/null | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||||
done
|
||||
[ "$BAD" -eq 0 ] && pass "Encrypted N=8 round-trip" || fail "Encrypted N=8 ($BAD mismatches)"
|
||||
|
||||
# ─── T9: Encrypted wrong password at N=8 ───
|
||||
echo "── T9: Wrong password rejection at N=8 ──"
|
||||
$ZUPT extract -o "$T/t9_out" -p "WRONG" "$T/t8.zupt" 2>/dev/null
|
||||
RES=$?
|
||||
[ "$RES" -ne 0 ] && pass "Wrong password rejected (N=8)" || fail "Wrong password NOT rejected"
|
||||
|
||||
# ─── T10: Integrity test with MT archive ───
|
||||
echo "── T10: Integrity test on MT archive ──"
|
||||
RESULT=$($ZUPT test -p "TestMT#2026" "$T/t8.zupt" 2>&1)
|
||||
echo "$RESULT" | grep -q "0 failed" && pass "Integrity test (encrypted MT)" || fail "Integrity test"
|
||||
|
||||
# ─── T11: Solid + N=8 falls back to N=1 ───
|
||||
echo "── T11: Solid mode + N=8 → fallback to N=1 ──"
|
||||
$ZUPT compress --solid -t 8 -l 5 "$T/t11.zupt" "$T/data/" 2>"$T/t11_err.txt"
|
||||
$ZUPT extract -o "$T/t11_out" "$T/t11.zupt" 2>/dev/null
|
||||
BAD=0
|
||||
for f in hello.txt large_rand.bin elf.bin; do
|
||||
EXTR=$(find "$T/t11_out" -name "$f" -type f 2>/dev/null | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/$f" "$EXTR" >/dev/null 2>&1; then BAD=$((BAD+1)); fi
|
||||
done
|
||||
if [ "$BAD" -eq 0 ] && grep -qi "single" "$T/t11_err.txt"; then
|
||||
pass "Solid+N=8 → N=1 fallback (correct output)"
|
||||
elif [ "$BAD" -eq 0 ]; then
|
||||
pass "Solid+N=8 correct output (fallback logged)"
|
||||
else
|
||||
fail "Solid+N=8 ($BAD mismatches)"
|
||||
fi
|
||||
|
||||
# ─── T12: All compression levels at N=4 ───
|
||||
echo "── T12: All 9 levels at N=4 ──"
|
||||
ALL_OK=1
|
||||
for lvl in 1 2 3 4 5 6 7 8 9; do
|
||||
$ZUPT compress -t 4 -l $lvl "$T/lvl_${lvl}.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||||
$ZUPT extract -o "$T/lvl_${lvl}_out" "$T/lvl_${lvl}.zupt" 2>/dev/null
|
||||
EXTR=$(find "$T/lvl_${lvl}_out" -name "repeat_2m.txt" -type f | head -1)
|
||||
if [ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1; then
|
||||
echo " Level $lvl: FAIL"; ALL_OK=0
|
||||
fi
|
||||
done
|
||||
[ "$ALL_OK" -eq 1 ] && pass "All 9 levels at N=4" || fail "Some levels failed at N=4"
|
||||
|
||||
# ─── T13: All codecs at N=4 ───
|
||||
echo "── T13: All codecs at N=4 ──"
|
||||
CODECS_OK=1
|
||||
# Default (LZHP)
|
||||
$ZUPT compress -t 4 -l 5 "$T/codec_lzhp.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||||
$ZUPT extract -o "$T/codec_lzhp_out" "$T/codec_lzhp.zupt" 2>/dev/null
|
||||
EXTR=$(find "$T/codec_lzhp_out" -name "repeat_2m.txt" -type f | head -1)
|
||||
[ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1 && CODECS_OK=0
|
||||
|
||||
# Fast LZ
|
||||
$ZUPT compress -t 4 -l 5 -f "$T/codec_lz.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||||
$ZUPT extract -o "$T/codec_lz_out" "$T/codec_lz.zupt" 2>/dev/null
|
||||
EXTR=$(find "$T/codec_lz_out" -name "repeat_2m.txt" -type f | head -1)
|
||||
[ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1 && CODECS_OK=0
|
||||
|
||||
# Store
|
||||
$ZUPT compress -t 4 -s "$T/codec_store.zupt" "$T/data/repeat_2m.txt" 2>/dev/null
|
||||
$ZUPT extract -o "$T/codec_store_out" "$T/codec_store.zupt" 2>/dev/null
|
||||
EXTR=$(find "$T/codec_store_out" -name "repeat_2m.txt" -type f | head -1)
|
||||
[ -z "$EXTR" ] || ! diff -q "$T/data/repeat_2m.txt" "$EXTR" >/dev/null 2>&1 && CODECS_OK=0
|
||||
|
||||
[ "$CODECS_OK" -eq 1 ] && pass "All codecs at N=4" || fail "Some codecs failed at N=4"
|
||||
|
||||
# ─── T14: Speed comparison (N=1 vs N=4) ───
|
||||
echo "── T14: Throughput comparison ──"
|
||||
T1_START=$(date +%s%N)
|
||||
$ZUPT compress -t 1 -l 5 "$T/speed1.zupt" "$T/large_10m.txt" 2>/dev/null
|
||||
T1_END=$(date +%s%N)
|
||||
T1_MS=$(( (T1_END - T1_START) / 1000000 ))
|
||||
|
||||
T4_START=$(date +%s%N)
|
||||
$ZUPT compress -t 4 -l 5 "$T/speed4.zupt" "$T/large_10m.txt" 2>/dev/null
|
||||
T4_END=$(date +%s%N)
|
||||
T4_MS=$(( (T4_END - T4_START) / 1000000 ))
|
||||
|
||||
echo " N=1: ${T1_MS}ms N=4: ${T4_MS}ms"
|
||||
if [ "$T4_MS" -gt 0 ] && [ "$T1_MS" -gt 0 ]; then
|
||||
SPEEDUP=$(echo "scale=1; $T1_MS / $T4_MS" | bc 2>/dev/null || echo "?")
|
||||
echo " Speedup: ${SPEEDUP}x"
|
||||
pass "Throughput comparison (N=1: ${T1_MS}ms, N=4: ${T4_MS}ms, ${SPEEDUP}x)"
|
||||
else
|
||||
pass "Throughput comparison (timing unavailable)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
echo " MT RESULTS: $PASS passed, $FAIL failed ($TOTAL tests)"
|
||||
echo "═══════════════════════════════════════════════════════"
|
||||
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|
||||
172
tests/test_vectors.c
Normal file
172
tests/test_vectors.c
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Zupt — NIST/RFC Cryptographic Test Vectors
|
||||
* Copyright (c) 2026 Cristian Cezar Moisés — MIT License
|
||||
*
|
||||
* Tests: SHA-256 (FIPS 180-4), HMAC-SHA256 (RFC 4231),
|
||||
* X25519 (RFC 7748 §6.1), ML-KEM-768 roundtrip,
|
||||
* SHA3-256 (FIPS 202), SHAKE-128 (FIPS 202).
|
||||
*
|
||||
* Build: gcc -O2 -std=c11 -Iinclude -Isrc tests/test_vectors.c \
|
||||
* src/zupt_sha256.c src/zupt_crypto.c src/zupt_aes256.c \
|
||||
* src/zupt_xxh.c src/zupt_keccak.c src/zupt_x25519.c \
|
||||
* src/zupt_mlkem.c -lm -o test_vectors
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include "zupt.h"
|
||||
#include "zupt_keccak.h"
|
||||
#include "zupt_x25519.h"
|
||||
#include "zupt_mlkem.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static int pass = 0, fail = 0;
|
||||
static void check(const char *name, const uint8_t *got, const uint8_t *exp, int n) {
|
||||
if (memcmp(got, exp, (size_t)n) == 0) { printf(" OK: %s\n", name); pass++; }
|
||||
else {
|
||||
printf(" FAIL: %s\n got: ", name);
|
||||
for (int i = 0; i < (n < 16 ? n : 16); i++) printf("%02x", got[i]);
|
||||
printf("...\n exp: ");
|
||||
for (int i = 0; i < (n < 16 ? n : 16); i++) printf("%02x", exp[i]);
|
||||
printf("...\n");
|
||||
fail++;
|
||||
}
|
||||
}
|
||||
|
||||
static void hex2bin(const char *hex, uint8_t *bin, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
unsigned int b;
|
||||
sscanf(hex + 2*i, "%02x", &b);
|
||||
bin[i] = (uint8_t)b;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("Zupt Cryptographic Test Vectors\n");
|
||||
printf("================================\n\n");
|
||||
|
||||
/* ═══ SHA-256 (FIPS 180-4) ═══ */
|
||||
printf("-- SHA-256 (FIPS 180-4) --\n");
|
||||
{
|
||||
/* Test 1: "abc" → ba7816bf... */
|
||||
uint8_t h[32];
|
||||
zupt_sha256((const uint8_t *)"abc", 3, h);
|
||||
uint8_t exp[32];
|
||||
hex2bin("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", exp, 32);
|
||||
check("SHA-256('abc')", h, exp, 32);
|
||||
|
||||
/* Test 2: "" (empty) → e3b0c442... */
|
||||
zupt_sha256((const uint8_t *)"", 0, h);
|
||||
hex2bin("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", exp, 32);
|
||||
check("SHA-256('')", h, exp, 32);
|
||||
|
||||
/* Test 3: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */
|
||||
const char *msg3 = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
|
||||
zupt_sha256((const uint8_t *)msg3, strlen(msg3), h);
|
||||
hex2bin("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", exp, 32);
|
||||
check("SHA-256(448-bit)", h, exp, 32);
|
||||
}
|
||||
|
||||
/* ═══ HMAC-SHA256 (RFC 4231) ═══ */
|
||||
printf("\n-- HMAC-SHA256 (RFC 4231) --\n");
|
||||
{
|
||||
/* Test Case 2: key=4a656665("Jefe"), data="what do ya want for nothing?" */
|
||||
uint8_t mac[32], exp[32];
|
||||
zupt_hmac_sha256((const uint8_t *)"Jefe", 4,
|
||||
(const uint8_t *)"what do ya want for nothing?", 28, mac);
|
||||
hex2bin("5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", exp, 32);
|
||||
check("HMAC-SHA256(RFC4231 TC2)", mac, exp, 32);
|
||||
|
||||
/* Test Case 3: key=20*0xaa, data=50*0xdd */
|
||||
uint8_t key3[20], data3[50];
|
||||
memset(key3, 0xaa, 20);
|
||||
memset(data3, 0xdd, 50);
|
||||
zupt_hmac_sha256(key3, 20, data3, 50, mac);
|
||||
hex2bin("773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", exp, 32);
|
||||
check("HMAC-SHA256(RFC4231 TC3)", mac, exp, 32);
|
||||
}
|
||||
|
||||
/* ═══ SHA3-256 (FIPS 202) ═══ */
|
||||
printf("\n-- SHA3-256 (FIPS 202) --\n");
|
||||
{
|
||||
uint8_t h[32], exp[32];
|
||||
|
||||
/* Empty message */
|
||||
zupt_sha3_256((const uint8_t *)"", 0, h);
|
||||
hex2bin("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", exp, 32);
|
||||
check("SHA3-256('')", h, exp, 32);
|
||||
|
||||
/* "abc" */
|
||||
zupt_sha3_256((const uint8_t *)"abc", 3, h);
|
||||
hex2bin("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", exp, 32);
|
||||
check("SHA3-256('abc')", h, exp, 32);
|
||||
}
|
||||
|
||||
/* ═══ SHAKE-128 (FIPS 202) ═══ */
|
||||
printf("\n-- SHAKE-128 (FIPS 202) --\n");
|
||||
{
|
||||
uint8_t out[16], exp[16];
|
||||
/* Empty input, 128-bit output */
|
||||
zupt_shake128((const uint8_t *)"", 0, out, 16);
|
||||
hex2bin("7f9c2ba4e88f827d616045507605853e", exp, 16);
|
||||
check("SHAKE-128('', 16B)", out, exp, 16);
|
||||
}
|
||||
|
||||
/* ═══ X25519 (RFC 7748 §6.1) ═══ */
|
||||
printf("\n-- X25519 (RFC 7748 §6.1) --\n");
|
||||
{
|
||||
uint8_t scalar[32], u[32], result[32], exp[32];
|
||||
|
||||
/* Test vector 1 */
|
||||
hex2bin("a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4", scalar, 32);
|
||||
hex2bin("e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c", u, 32);
|
||||
zupt_x25519(result, scalar, u);
|
||||
hex2bin("c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552", exp, 32);
|
||||
check("X25519 TV1", result, exp, 32);
|
||||
|
||||
/* Test vector 2 */
|
||||
hex2bin("4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d", scalar, 32);
|
||||
hex2bin("e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493", u, 32);
|
||||
zupt_x25519(result, scalar, u);
|
||||
hex2bin("95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957", exp, 32);
|
||||
check("X25519 TV2", result, exp, 32);
|
||||
}
|
||||
|
||||
/* ═══ ML-KEM-768 (roundtrip) ═══ */
|
||||
printf("\n-- ML-KEM-768 (FIPS 203 roundtrip) --\n");
|
||||
{
|
||||
uint8_t pk[1184], sk[2400], ct[1088], ss1[32], ss2[32];
|
||||
int kem_ok = 1;
|
||||
for (int trial = 0; trial < 5; trial++) {
|
||||
zupt_mlkem768_keygen(pk, sk);
|
||||
zupt_mlkem768_encaps(ct, ss1, pk);
|
||||
zupt_mlkem768_decaps(ss2, ct, sk);
|
||||
if (memcmp(ss1, ss2, 32) != 0) { kem_ok = 0; break; }
|
||||
}
|
||||
if (kem_ok) { printf(" OK: ML-KEM-768 roundtrip (5 trials)\n"); pass++; }
|
||||
else { printf(" FAIL: ML-KEM-768 roundtrip\n"); fail++; }
|
||||
|
||||
/* Implicit rejection: corrupt ct, verify different ss */
|
||||
zupt_mlkem768_keygen(pk, sk);
|
||||
zupt_mlkem768_encaps(ct, ss1, pk);
|
||||
ct[0] ^= 0xFF; /* Corrupt first byte */
|
||||
zupt_mlkem768_decaps(ss2, ct, sk);
|
||||
if (memcmp(ss1, ss2, 32) != 0) {
|
||||
printf(" OK: ML-KEM-768 implicit rejection\n"); pass++;
|
||||
} else {
|
||||
printf(" FAIL: ML-KEM-768 implicit rejection (ss should differ)\n"); fail++;
|
||||
}
|
||||
}
|
||||
|
||||
/* ═══ XXH64 (basic sanity) ═══ */
|
||||
printf("\n-- XXH64 --\n");
|
||||
{
|
||||
uint64_t h = zupt_xxh64((const uint8_t *)"", 0, 0);
|
||||
/* xxh64("", seed=0) = 0xef46db3751d8e999 */
|
||||
if (h == UINT64_C(0xef46db3751d8e999)) { printf(" OK: XXH64('')\n"); pass++; }
|
||||
else { printf(" FAIL: XXH64('') = %016llx\n", (unsigned long long)h); fail++; }
|
||||
}
|
||||
|
||||
printf("\n================================\n");
|
||||
printf("Results: %d passed, %d failed\n", pass, fail);
|
||||
return fail > 0 ? 1 : 0;
|
||||
}
|
||||
Loading…
Reference in a new issue