Skip to content

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.md are 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

Final Score = (Base Score) × (Test Case Weight) × (Browser Weight) - Penalties

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]) -> str
  • hash_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.py must 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.md guidance 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: