Historical Fingerprinter v2
Overview
Historical Fingerprinter v2 shifts evaluation toward cross-browser identity linking and measures how reliably miners can keep one stable identity across browser changes, privacy modes, and spoofing conditions.
Compared to v1, this version expands the browser/test matrix, introduces fixed hashing utilities that must be used in linking logic, and adds stricter formatting validation before submission.
For general challenge information, environment details, and plagiarism policies, refer to the Historical Fingerprinter README.
What Changed From v1
- Scoring focus updated: Greater emphasis on cross-browser linking quality
- Test matrix expanded: More browser coverage and scenario depth
- Hashing standardized: Miners must use provided hashing utilities in
linking.py - Formatting gate added: Ruff format checks are required before submission
- Miner support improved: Agentic skills and
AGENT.mdare included for easier onboarding
Test Cases and Browser Weights
The active v2 scoring config is defined in:
src/hfp_challenge/challenge/api/core/configs/_challenge.py
Test Case Weights
| Test Case | Weight |
|---|---|
anti_fingerprint_browser |
10.0 |
timezone_change |
8.0 |
language_change |
8.0 |
incognito_with_vpn |
7.0 |
vpn_proxy_enabled |
5.0 |
incognito_mode |
3.0 |
normal |
1.0 |
Browser Weights
| Browser | Weight |
|---|---|
brave |
4.0 |
firefox |
3.0 |
safari |
3.0 |
duckduckgo |
2.0 |
edge |
2.0 |
chrome |
1.0 |
Penalties and Thresholds
- Collision Penalty:
0.3 - Fragmentation Penalty:
0.2 - Max Collision Threshold:
0.1 - Max Fragmentation Threshold:
0.1
Final Formula
Required Hashing Functions (Mandatory)
Miners must use the challenge-provided hashing functions from:
src/hfp_challenge/challenge/fingerprinter/src/submissions/hashing.py
Required functions:
hash_payload(payload: dict[str, Any]) -> strhash_keys(payload: dict[str, Any], keys: list[str], digest_len: int = 24) -> str
These must be integrated into miner linking logic in linking.py (or equivalent linker implementation path used by your commit template).
Submission Format
Submissions keep the same three-file Python structure (see challenge documentation):
# initializer.py
def initialize_db(db_path: str | None = None) -> sqlite3.Connection:
...
# metrics_collector.py
def preprocess_metrics(raw_metrics: dict[str, Any]) -> dict[str, Any]:
...
# linker.py
def generate_and_link(payload: dict[str, Any], db_conn: sqlite3.Connection) -> dict[str, Any]:
...
Requirements
- Each file is limited to 1000 lines
- Function names must match exactly:
initialize_db,preprocess_metrics,generate_and_link - Additional package installation is not allowed
- Request processing must stay within challenge limits
- Hashing utilities from
hashing.pymust be used for fingerprint/link generation
Formatting Validation (Ruff)
Before submitting, miners must run Ruff format checks as described in:
examples/miner_commit/README.md
Example commands:
ruff format --config ../../volumes/configs/.ruff.toml --check ./src/commit/initializer.py
ruff format --config ../../volumes/configs/.ruff.toml --check ./src/commit/linker.py
ruff format --config ../../volumes/configs/.ruff.toml --check ./src/commit/metrics_collector.py
Miner Enablement
To reduce setup friction and improve iteration speed, v2 includes:
- Agentic skills for guided implementation workflows
AGENT.mdguidance for miner-side development conventions
Use these resources together with the challenge template and miner commit example.
Submission Guide
To build and submit your solution, follow: