# Signature verification baseline A small research starter project for online handwritten-signature verification. It includes common-format CSV/JSON loading, preprocessing, feature extraction, DTW matching, threshold metrics, and a local FastAPI capture demo. ## Setup From the project root: ```powershell py -m venv .venv .\.venv\Scripts\Activate.ps1 python -m pip install -e ".[dev]" $env:SIGVERIFY_FERNET_KEY = python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" uvicorn app.main:app --reload ``` Open . The generated Fernet key is for local testing; keep the same key between runs to read previously enrolled templates. Store a production key in a secret manager, never in source control. Without a key, the API rejects enrollment and verification rather than storing plaintext. Run tests with `pytest`. The package can also be installed with `pip install -e .`. ## Data format The common signature format has one sample per point with `user_id`, `t`, `x`, `y`, optional `p` (pressure), optional `area` (contact area), and optional `pen_down`. CSV loaders expect these names by default; pass column overrides for a dataset with different headers. A JSON signature uses the same names with array-valued `t`, `x`, and `y`. For MOBISIG, check the downloaded release's layout is supported directly by `load_mobisig`: `timestamp`, `x`, `y`, `pressure`, and `fingerarea` are mapped automatically. Names such as `SIGN_GEN_USER1_USER1_1.csv` and `SIGN_FOR_USER1_USER2_1.csv` determine the claimed user and genuine/forgery label; metadata files such as `users.csv` are ignored. Put downloaded or self-collected material under `data/raw/`. Raw data is ignored by Git. ## Baseline workflow 1. Load signatures into `Signature`. 2. Sort timestamps, collapse repeated times, lightly smooth, resample, and translate/scale positions. Preprocessing records the original bounding-box diagonal because size may itself be discriminative. Pen-up samples are excluded from the baseline trajectory. 3. Extract x/y and motion features; pressure and contact area can be enabled as explicit ablations. 4. Enroll several genuine examples, compare using band-constrained DTW, and divide by the median within-enrollment distance. 5. Tune global and per-user thresholds on a development split; evaluate only on held-out attempts. Thresholds in the demo are illustrative, not research results. `experiments/` contains starter scripts for inspecting data, running a simple split, and comparing feature sets. Report user-disjoint development/test results separately from the API demo. Do not train or tune on the test set. For the included MOBISIG layout, run: ```powershell python experiments/02_baseline_dtw.py --data-dir data/raw/mobisig ` --output results/mobisig_baseline.json ``` ## Capture and consent The browser sends pointer positions, elapsed milliseconds, and optional pressure. It does not persist anything in the browser. Review [`docs/data_collection_protocol.md`](docs/data_collection_protocol.md) and [`docs/consent_form.md`](docs/consent_form.md) before collecting data; adapt them to institutional requirements and obtain approval where required. The SQLite demo stores encrypted template JSON and a small lockout counter in process memory. Lockout state resets when the server restarts, so this is not a production account-security system. Use HTTPS, authentication, durable rate-limiting, access controls, key management, and a retention/deletion policy before exposing a service beyond localhost.