[Standalone / Library] Actual Fingerprints – real-looking prints from a seed

This project had nothing to do with FiveM but I thought it could be useful for developers who create creative and realistic scripts (like MDT, EMS).

Those all generated from actual-fingerprints. All grown from seeds. You do pass a string, you get a print back. The image, the type (loop / whorl / arch), and the minutiae list (ridge endings and bifurcations with angles). You don’t need any db operations underneath since same seed gives you the exact same print every time on any machine, so you don’t store images at all, you store the seed. that was the part that made me think of FiveM tbh, everyone’s database is already fat enough.

NOTE: It’s a library not a resource. there’s no fxmanifest, you npm install actual-fingerprints into your own resource and bundle it.

A little demonstration on how I’d wire it up, not saying this is the only way:

When a character gets created, server side:

import { generate } from 'actual-fingerprints'
import { seedFor } from 'actual-fingerprints/node'

const secret = GetConvar('fp_secret', '')

for (const finger of ['R1', 'R2', 'R3', 'R4', 'R5']) {
  const seed = seedFor(secret, citizenId, finger)
  const p = generate(seed, { hand: 'right' })
  db.insert('fingerprints', { citizenid: citizenId, finger, seed, pattern: p.pattern, minutiae: JSON.stringify(p.minutiae) })
}

seedFor is just HMAC with a secret from your server config. don’t use the CitizenID raw as the seed, otherwise anyone can generate anyone’s prints on the client.

Let’s give an example; You want to show the suspect’s fingerprint in your MDT NUI, all you have to do is: send the seed over and draw it, nothing goes over the wire but a string:

import { generate, ink, toRGBA } from 'actual-fingerprints'

const p = ink(generate(seed))
ctx.putImageData(new ImageData(toRGBA(p), p.width, p.height), 0, 0)

ink() is what makes it look like it was actually pressed on paper, pores and uneven ink and sometimes a crease. leave it out for the clean version.

Matching a print from a scene against the db, the stored minutiae are enough, no regenerating:

import { compare } from 'actual-fingerprints'

const found = generate(evidenceSeed)
for (const row of db.select('fingerprints', { pattern: found.pattern })) {
  if (compare(found, { minutiae: JSON.parse(row.minutiae), width: 320, height: 400 }).score > 0.3) return row.citizenid
}

Same finger scores 1, different fingers score like 0.02, so 0.3 is not a delicate number.

Only real gotcha is that generating takes ~100ms and the server runs everything on one thread. do it on character creation or in nui, not in a loop on the server, and you’ll be fine.

npm: https://www.npmjs.com/package/actual-fingerprints
source: GitHub - 1etu/actual-fingerprints: Deterministic synthetic fingerprints from a seed. Zero dependencies, Node. · GitHub
there’s a page with a live demo where you can type seeds and see what comes out, plus how it actually works if you care: actual-fingerprints: deterministic synthetic fingerprints from a seed

If you develop on Lua only? Wrap it in a tiny js server script with a couple exports, it’s like three lines. You can ask me if you get stuck.

Code is accessible Yes
Subscription-based No
Lines (approximately) 1200
Requirements Nothing
Support No
9 Likes

Really cool concept and awesome. Its even seed based. Now there is something i can use for this. Great man! keep it up. Maşallah :clap: :hand_with_index_finger_and_thumb_crossed:

1 Like

tuff work man, keep doing it :ok_hand:

2 Likes

Good job! I’ve done something similar but don’t think they look as good as this, I might actually switch it!

1 Like

Thanks dude

1 Like

Thank you, possibly one of the most realistic implementation of fingerprints using an actual research papers written about it. I don’t really know If there’s a possible slightly better / realistic version to be honest

Glad you liked it

Good job, tebrikler kardeşim

Eyvalla kardeşim