Se la sicurezza non è un problema, quello che stai descrivendo è a mio parere non una funzione di hash. Una funzione hash è una funzione unidirezionale, il che significa che calcolare l'hash è facile, ma ripristinarlo è "difficile" o, idealmente, impossibile.
Le vostre esigenze, invece descrivono un injective function dato alcuna x1, x2 nel dominio X vale quanto segue:
For all x1, x2 element of X, x1 != x2 => f(x1) != f(x2)
f (x) = x è una tale funzione, f (x) = x² non lo è. In parole semplici: vuoi avere risultati diversi se i tuoi input sono diversi, gli stessi risultati solo se gli input sono gli stessi. È vero che anche questo è vero per gli hash sicuri, ma forniscono anche le caratteristiche unidirezionali come la proprietà di non essere in grado (facilmente) di trovare x se si è data solo f (x), tra gli altri. Per quanto ho capito, non hai bisogno di queste proprietà di sicurezza.
Banalmente, una mappatura quali iniettiva da String a galleggiare sarebbe dato semplicemente interpretando i "byte stringa" come "Float byte" da ora in poi, vale a dire si interpretano i byte in modo diverso (si pensi C:
unsigned char *bytes = "...";
double d = (double)bytes;
). Ma c'è un rovescio della medaglia: il vero problema è che Float ha una precisione massima, quindi ti imbatterai in una situazione di overflow se le tue stringhe sono troppo lunghe (i Floats sono internamente rappresentati come valori double
, ovvero 8 byte su un 32 bit macchina). Quindi non c'è abbastanza spazio per quasi tutti i casi d'uso. Persino MD5, prima di tutto, non risolve il problema: l'output MD5 è già lungo 16 byte.
Quindi questo potrebbe essere un problema reale, a seconda dei vostri esatti requisiti. Sebbene MD5 (o qualsiasi altro hash) funzionerà a sufficienza con l'input per renderlo il più casuale possibile, si taglia comunque l'intervallo di valori possibili da 16 byte a 8 byte effettivi. (Nota: il troncamento casuale dell'uscita a 16 byte a 8 byte è generalmente considerato "sicuro" in termini di conservazione della casualità. La crittografia a curve ellittiche fa qualcosa di simile, ma per quanto ne so nessuno può davvero dimostrarlo, ma nessuno potrebbe provarlo al contrario finora). Quindi una collisione è molto più probabile con la tua gamma Float limitata. Per il paradosso del compleanno, trovare una collisione richiede sqrt (numero di valori in un intervallo finito). Per MD5 questo è 2^64, ma per il tuo schema è solo 2^32. È ancora molto, molto improbabile che produca una collisione. Probabilmente è qualcosa nell'ordine di vincere alla lotteria, mentre allo stesso tempo viene colpito da un fulmine. Se si potesse vivere con questo minima possibilità, andare per esso:
def string_to_float(str)
Digest::MD5.new.digest(str).unpack('D')
end
Se unicità è di priorità assoluta che consiglierei di passare da carri a numeri interi. Ruby ha il supporto integrato per i grandi numeri interi che non sono limitati dai vincoli interni di un valore long
(questo è il motivo per cui un Fixnum si riduce a). Quindi qualsiasi output hash arbitrario potrebbe essere rappresentato come un numero intero di grandi dimensioni.
Vuoi che il risultato sia "sicuro", cioè qualcuno con il galleggiante non ha modo di indovinare quale fosse la stringa originaria? O è irrilevante? – emboss
La sicurezza non è un problema. Finché qualsiasi input univoco produce lo stesso float normalizzato come output. Ma anche se lo fosse, sembra che un sale segreto potrebbe facilmente essere aggiunto, uno ho le basi di come questo possa funzionare. –