2026-09-03 17:46:33 +02:00
|
|
|
#!/bin/sh
|
|
|
|
|
# fplearn.sh -- the template-learning measurement, as a protocol rather than a
|
|
|
|
|
# pile of remembered commands.
|
|
|
|
|
#
|
fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.
wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.
enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
|
|
|
# fplearn.sh wipe remove every stored template (backup first)
|
|
|
|
|
# fplearn.sh enrol [finger] enrol at the config's sample count
|
2026-09-03 17:46:33 +02:00
|
|
|
# fplearn.sh base [n] [w] trial with learning OFF (the baseline)
|
|
|
|
|
# fplearn.sh trend [n] [w] three trials with learning ON
|
|
|
|
|
# fplearn.sh sizes just print the template container sizes
|
|
|
|
|
#
|
fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.
wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.
enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
|
|
|
# WIPE FIRST when re-enrolling a finger that is already in the group. Measured
|
|
|
|
|
# 2026-09-04: the duplicated-finger check refuses a finger the group already
|
|
|
|
|
# holds -- 0 accepted of 7 presses, rc=0 on every one, while a never-enrolled
|
|
|
|
|
# finger progressed normally. Re-enrolment ADDS a template and there is no
|
|
|
|
|
# trustlet-side remove, so the old one has to go first. `enrol` refuses a
|
|
|
|
|
# finger name that is already in the map and points here.
|
|
|
|
|
#
|
2026-09-03 17:46:33 +02:00
|
|
|
# WHY IT IS SHAPED LIKE THIS. Learning is cumulative: every matched press folds
|
|
|
|
|
# frames into the stored template, so a second run is not a repeat of the first
|
|
|
|
|
# and an A/B against a moving template is not an A/B at all. The only honest
|
|
|
|
|
# comparison is on ONE template lineage, in order:
|
|
|
|
|
#
|
|
|
|
|
# 1. enrol a fresh template, 20 samples, no position prompts --
|
|
|
|
|
# which is also the outstanding replication of the 7/10
|
|
|
|
|
# result, the one measurement this lane was parked on
|
|
|
|
|
# 2. base learning off: the clean number for THIS template, and
|
|
|
|
|
# the only figure comparable to every rate in the journal
|
|
|
|
|
# 3. trend learning on, three times: the rate should climb, and
|
|
|
|
|
# the container size is an independent witness that it
|
|
|
|
|
# is the template moving and not the weather
|
|
|
|
|
#
|
|
|
|
|
# Do NOT read run 1 of the trend as "learning made it better". Run 1 starts on
|
|
|
|
|
# the same template the baseline ended on; it is the first run that can improve
|
|
|
|
|
# it, not one that has already been improved.
|
|
|
|
|
set -u
|
|
|
|
|
|
|
|
|
|
GROUP=/mnt/persist/data/RIY7A+mQm3EA4FsCUmkJo0b9dFUYP2YZ4P5hmMiZgeA_Alt
|
fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.
wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.
enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
|
|
|
MAP=/var/lib/fingerprintd/fingers-10000.map
|
2026-09-03 17:46:33 +02:00
|
|
|
UNIT=fingerprintd-test
|
|
|
|
|
BIN=/tmp/fingerprintd
|
|
|
|
|
COMMON="--daemon --verbose --edge-wake --sfs-root=/var/lib/fingerprintd/sfs --sfs-writable --rpmb-write"
|
|
|
|
|
|
2026-09-04 23:43:47 +02:00
|
|
|
# How many frames learning actually folded, out of the daemon's own transcript.
|
|
|
|
|
# Without this a trend run cannot tell "learning fired and did not help" from
|
|
|
|
|
# "learning never fired" -- which is exactly the confusion that made the first
|
|
|
|
|
# trend run measure a static template three times.
|
|
|
|
|
folds() {
|
|
|
|
|
L=$(ls -t /var/log/fingerprintd/*.log 2>/dev/null | head -1)
|
|
|
|
|
[ -n "$L" ] || { echo " (no transcript)"; return; }
|
|
|
|
|
m=$(grep -c -- "-> MATCH fid=" "$L" 2>/dev/null || echo 0)
|
|
|
|
|
f=$(grep -c "folded in (metric" "$L" 2>/dev/null || echo 0)
|
|
|
|
|
s=$(grep -c "learn: template saved" "$L" 2>/dev/null || echo 0)
|
|
|
|
|
echo " folds: $f frame(s) over $m matched press(es), $s save(s)"
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-03 17:46:33 +02:00
|
|
|
sizes() {
|
|
|
|
|
# A template is stored twice, the container and its backup, so the sizes
|
|
|
|
|
# come in pairs. The BODY is the container minus its 4096-byte header.
|
|
|
|
|
sudo ls -la "$GROUP" 2>/dev/null | awk '$5 > 200000 { printf " %9d body %9d %s\n", $5, $5-4096, $9 }' | sort -u
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
restart() { # $1 = extra args
|
|
|
|
|
sudo systemctl stop "$UNIT" 2>/dev/null
|
|
|
|
|
sleep 2
|
|
|
|
|
sudo systemd-run --unit="$UNIT" --collect $BIN $COMMON $1 >/dev/null 2>&1
|
|
|
|
|
printf 'daemon starting'
|
|
|
|
|
i=0
|
|
|
|
|
while [ $i -lt 40 ]; do
|
|
|
|
|
if busctl --system list 2>/dev/null | grep -q net.reactivated.Fprint; then
|
|
|
|
|
# Owning the name is not the same as being ready: the session comes
|
|
|
|
|
# up on the worker thread afterwards.
|
|
|
|
|
sleep 6; printf ' ready\n'; return 0
|
|
|
|
|
fi
|
|
|
|
|
printf '.'; sleep 1; i=$((i+1))
|
|
|
|
|
done
|
|
|
|
|
printf ' TIMED OUT\n'; return 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case "${1:-}" in
|
|
|
|
|
sizes)
|
|
|
|
|
echo "template containers now:"; sizes ;;
|
|
|
|
|
|
fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.
wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.
enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
|
|
|
wipe)
|
|
|
|
|
# The procedure of 2026-09-03 and 2026-09-04, and its reasoning: ONLY the
|
|
|
|
|
# template containers go (>200000 bytes; each template is stored twice).
|
|
|
|
|
# The 1588-byte group index is KEPT -- deleting it risks the RPMB
|
|
|
|
|
# anti-rollback counters going stale against object ids QTEE would then
|
|
|
|
|
# recreate, which already cost an index restore once -- and a missing
|
|
|
|
|
# template container is the known-good "not exist, skip" case. The daemon
|
|
|
|
|
# is stopped first so the trustlet reloads from the store, and a backup is
|
|
|
|
|
# taken first because a template is not reproducible without a finger.
|
|
|
|
|
echo "=== wipe: every stored template ==="
|
|
|
|
|
echo "before:"; sizes
|
|
|
|
|
D=$HOME/fp6-backups/$(date +%Y-%m-%d-%H%M)-pre-wipe
|
|
|
|
|
mkdir -p "$D"
|
|
|
|
|
sudo tar -cf "$D/persist-data.tar" -C /mnt/persist data
|
|
|
|
|
sudo cp "$MAP" "$D/" 2>/dev/null || true
|
|
|
|
|
sudo chown -R "$(id -u):$(id -g)" "$D"
|
|
|
|
|
echo "backup: $D ($(tar -tf "$D/persist-data.tar" | wc -l) entries, $(sha256sum "$D/persist-data.tar" | cut -c1-16))"
|
|
|
|
|
sudo systemctl stop "$UNIT" 2>/dev/null; sleep 2
|
|
|
|
|
n=0
|
|
|
|
|
for f in $(sudo ls "$GROUP"); do
|
|
|
|
|
sz=$(sudo stat -c %s "$GROUP/$f")
|
|
|
|
|
if [ "$sz" -gt 200000 ]; then sudo rm -f "$GROUP/$f"; n=$((n+1)); fi
|
|
|
|
|
done
|
|
|
|
|
sudo sync
|
|
|
|
|
sudo sh -c ": > $MAP"
|
|
|
|
|
echo "removed $n container(s); index and small containers kept; map cleared"
|
|
|
|
|
restart "--learn=1" || exit 1
|
|
|
|
|
fprintd-list user 2>&1 | tail -1
|
|
|
|
|
echo "after:"; sizes
|
|
|
|
|
echo; echo "next: fplearn.sh enrol <finger>" ;;
|
|
|
|
|
|
2026-09-03 17:46:33 +02:00
|
|
|
enrol)
|
|
|
|
|
F=${2:-right-middle-finger}
|
fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.
wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.
enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
|
|
|
if sudo grep -q "^$F " "$MAP" 2>/dev/null; then
|
|
|
|
|
echo "$F is already enrolled (in $MAP)."
|
|
|
|
|
echo "The trustlet REFUSES to re-enrol a finger it already holds; run"
|
|
|
|
|
echo " fplearn.sh wipe"
|
|
|
|
|
echo "first. (Measured 2026-09-04: 0 accepted of 7 presses, rc=0 each.)"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
2026-09-03 17:46:33 +02:00
|
|
|
echo "=== enrol $F ==="
|
|
|
|
|
echo "sizes before:"; sizes
|
|
|
|
|
restart "--learn=1" || exit 1
|
|
|
|
|
/tmp/fpenrol.sh "$F"
|
|
|
|
|
echo; echo "sizes after the enrolment:"; sizes
|
|
|
|
|
echo; echo "next: fplearn.sh base" ;;
|
|
|
|
|
|
|
|
|
|
base)
|
2026-09-04 23:43:47 +02:00
|
|
|
N=${2:-15}; W=${3:-0}
|
2026-09-03 17:46:33 +02:00
|
|
|
echo "=== BASELINE: learning OFF ==="
|
|
|
|
|
restart "--learn=0" || exit 1
|
|
|
|
|
echo "sizes before:"; sizes
|
|
|
|
|
/tmp/fptrial.sh "$N" "$W"
|
|
|
|
|
echo; echo "sizes after (MUST be unchanged -- learning was off):"; sizes
|
|
|
|
|
echo; echo "next: fplearn.sh trend" ;;
|
|
|
|
|
|
|
|
|
|
trend)
|
2026-09-04 23:43:47 +02:00
|
|
|
# No wrong-finger taps by default: zero false accepts is settled over forty
|
|
|
|
|
# of them, and the presses are better spent on the false-negative rate.
|
|
|
|
|
N=${2:-15}; W=${3:-0}
|
2026-09-03 17:46:33 +02:00
|
|
|
echo "=== TREND: learning ON, three runs on one template ==="
|
|
|
|
|
restart "--learn=1" || exit 1
|
|
|
|
|
echo "sizes at the start:"; sizes
|
|
|
|
|
r=1
|
|
|
|
|
while [ $r -le 3 ]; do
|
|
|
|
|
echo; echo "----- learning run $r of 3 -----"
|
|
|
|
|
/tmp/fptrial.sh "$N" "$W"
|
2026-09-04 23:43:47 +02:00
|
|
|
echo "after run $r:"; sizes; folds
|
2026-09-03 17:46:33 +02:00
|
|
|
r=$((r+1))
|
|
|
|
|
done
|
|
|
|
|
echo
|
|
|
|
|
echo "Read it as a trend, not three numbers. A rate that climbs while the"
|
|
|
|
|
echo "container grows is learning; a rate that moves while the container"
|
|
|
|
|
echo "does not is noise, and the daemon's own 'learn:' lines say which." ;;
|
|
|
|
|
|
|
|
|
|
*)
|
fplearn.sh: a wipe step, and enrol refuses a finger the group already holds
Measured 2026-09-04: the trustlet's duplicated-finger check refuses to re-enrol
a finger it already has a template for -- 0 accepted of 7 presses, rc=0 on each,
while a never-enrolled finger progressed normally. Re-enrolment adds a template
and there is no trustlet-side remove, so a measured finger's old template has to
go before it can be enrolled again.
wipe does that the way it has been done by hand twice: backup first, daemon
stopped so the trustlet reloads from the store, only the template containers
removed, the group index kept because deleting it risks the RPMB anti-rollback
counters going stale, the name map cleared, then a restart and the sizes.
enrol checks the name map and refuses a finger that is already there, pointing
at wipe, so the refusal cannot be mistaken for bad pressing again.
2026-09-04 23:06:45 +02:00
|
|
|
sed -n '2,38p' "$0"; exit 1 ;;
|
2026-09-03 17:46:33 +02:00
|
|
|
esac
|