Benzersiz karmaşa ve hız için hangi karma algoritma en iyisidir?


1388

Benzersiz karmaşa ve hız için hangi karma algoritma en iyisidir? Örnek (iyi) kullanımlar, karma sözlükleri içerir.

SHA-256 gibi şeyler olduğunu biliyorum , ancak bu algoritmalar güvenli olacak şekilde tasarlandı , bu da genellikle daha az benzersiz olan algoritmalardan daha yavaş olduklarını gösteriyor . Hızlı olacak şekilde tasarlanmış bir karma algoritma istiyorum, ancak çarpışmaları önlemek için oldukça benzersiz kalıyorum.


9
Hangi amaç için, güvenlik veya başka?
Orbling

19
@Orbling, karma bir sözlüğün uygulanması için. Bu yüzden çarpışmalar minimumda tutulmalı, ancak güvenlik amacı yoktur.
Earlz

4
En azından hash tablonuzda bazı çarpışmalar beklemeniz gerekeceğini unutmayın , aksi takdirde tablonun göreceli olarak az sayıdaki anahtarla bile başa çıkabilmesi için muazzam olması gerekir ...
Dean Harding

19
Harika yazı! Ayrıca Yann Collet'in Murmur'dan iki kat daha hızlı olan xxHash'ı (yaratıcısı veya LZ4) kontrol edebilir misiniz? Anasayfa: code.google.com/p/xxhash için bilgiler fastcompression.blogspot.fr/2012/04/...

24
@zvrba Algoritmaya bağlı. bcrypt yavaş olacak şekilde tasarlanmıştır.
Izkata

Yanıtlar:


2461

Bazı algoritmaları test ettim, hızını ve çarpışma sayısını ölçtüm.

Üç farklı anahtar seti kullandım:

Her bir korpus için çarpışma sayısı ve ortalama harcanan zaman kaydedildi.

Test ettim:

Sonuçlar

Her sonuç ortalama karma zamanı ve çarpışma sayısını içerir.

Hash           Lowercase      Random UUID  Numbers
=============  =============  ===========  ==============
Murmur            145 ns      259 ns          92 ns
                    6 collis    5 collis       0 collis
FNV-1a            152 ns      504 ns          86 ns
                    4 collis    4 collis       0 collis
FNV-1             184 ns      730 ns          92 ns
                    1 collis    5 collis       0 collis▪
DBJ2a             158 ns      443 ns          91 ns
                    5 collis    6 collis       0 collis▪▪▪
DJB2              156 ns      437 ns          93 ns
                    7 collis    6 collis       0 collis▪▪▪
SDBM              148 ns      484 ns          90 ns
                    4 collis    6 collis       0 collis**
SuperFastHash     164 ns      344 ns         118 ns
                   85 collis    4 collis   18742 collis
CRC32             250 ns      946 ns         130 ns
                    2 collis    0 collis       0 collis
LoseLose          338 ns        -             -
               215178 collis

Notlar :

Çarpışmalar gerçekten oluyor mu?

Evet. Test programımı karma çarpışmaların gerçekten olup olmadığını görmek için yazmaya başladım - ve sadece teorik bir yapı değil. Gerçekten de oluyorlar:

FNV-1 çarpışmaları

  • creamwove ile çarpışır quists

FNV-1a çarpışmaları

  • costarring ile çarpışır liquid
  • declinate ile çarpışır macallums
  • altarage ile çarpışır zinke
  • altarages ile çarpışır zinkes

Murmur2 çarpışmaları

  • cataract ile çarpışır periti
  • roquette ile çarpışır skivie
  • shawl ile çarpışır stormbound
  • dowlases ile çarpışır tramontane
  • cricketings ile çarpışır twanger
  • longans ile çarpışır whigs

DJB2 çarpışmaları

  • hetairas ile çarpışır mentioner
  • heliotropes ile çarpışır neurospora
  • depravement ile çarpışır serafins
  • stylist ile çarpışır subgenera
  • joyful ile çarpışır synaphea
  • redescribed ile çarpışır urites
  • dram ile çarpışır vivency

DJB2a çarpışmaları

  • haggadot ile çarpışır loathsomenesses
  • adorablenesses ile çarpışır rentability
  • playwright ile çarpışır snush
  • playwrighting ile çarpışır snushing
  • treponematoses ile çarpışır waterbeds

CRC32 çarpışmaları

  • codding ile çarpışır gnu
  • exhibiters ile çarpışır schlager

SuperFastHash çarpışmaları

  • dahabiah ile çarpışır drapability
  • encharm ile çarpışır enclave
  • grahams ile çarpışır gramary
  • ... 79 çarpışmayı engelle ...
  • night ile çarpışır vigil
  • nights ile çarpışır vigils
  • finks ile çarpışır vinic

Randomnessification

Diğer sübjektif ölçü ise karmaların ne kadar rastgele dağıtıldığıdır. Sonuçta elde edilen HashTable'ların eşlenmesi verilerin ne kadar eşit dağıldığını gösterir. Tüm karma işlevleri, tabloyu doğrusal olarak eşlerken iyi dağılım gösterir:

Resim tanımını buraya girin

Veya bir Hilbert Haritası olarak ( XKCD her zaman ilgilidir ):

Resim tanımını buraya girin

Sayı dizelerinin ( "1",, "2"..., "216553") (örneğin, posta kodları ) eklenmesi haricinde , kalıpların karma algoritmaların çoğunda ortaya çıkmaya başladığı durumlar hariç :

SDBM :

Resim tanımını buraya girin

DJB2a :

Resim tanımını buraya girin

FNV-1 :

Resim tanımını buraya girin

Hala bana rastgele görünen FNV-1a hariç :

Resim tanımını buraya girin

Aslında, Murmur2 ile daha da iyi rastlantısallığını var gibi gözüküyor Numbersdaha FNV-1a:

Resim tanımını buraya girin

FNV-1a"Sayı" haritasına baktığımda, ince dikey desenler gördüğümü düşünüyorum . Murmur ile hiçbir desen göremiyorum. Ne düşünüyorsun?


*Tablodaki ekstra , rastgeleliğin ne kadar kötü olduğunu göstermektedir. En FNV-1aiyisi ve DJB2xen kötüsü olmak:

      Murmur2: .
       FNV-1a: .
        FNV-1: ▪
         DJB2: ▪▪
        DJB2a: ▪▪
         SDBM: ▪▪▪
SuperFastHash: .
          CRC: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
     Loselose: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
                                        ▪
                                 ▪▪▪▪▪▪▪▪▪▪▪▪▪
                        ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
          ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪

Aslında bu programı çarpışmalardan endişe duyup duymamam gerektiğine karar vermek için yazdım : Yaparım.

Ve sonra karma fonksiyonlarının yeterince rastgele olduğundan emin olmaya başladı.

FNV-1a algoritması

FNV1 karma, 32, 64, 128, 256, 512 ve 1024 bit karma değerlerini döndüren değişkenlerle gelir.

FNV'nin-1a Algoritma olduğu:

hash = FNV_offset_basis
for each octetOfData to be hashed
    hash = hash xor octetOfData
    hash = hash * FNV_prime
return hash

Burada istediğiniz sabit FNV_offset_basisve FNV_primedönüş hash büyüklüğüne bağlı:

Hash Size  
===========
32-bit
    prime: 2^24 + 2^8 + 0x93 = 16777619
    offset: 2166136261
64-bit
    prime: 2^40 + 2^8 + 0xb3 = 1099511628211
    offset: 14695981039346656037
128-bit
    prime: 2^88 + 2^8 + 0x3b = 309485009821345068724781371
    offset: 144066263297769815596495629667062367629
256-bit
    prime: 2^168 + 2^8 + 0x63 = 374144419156711147060143317175368453031918731002211
    offset: 100029257958052580907070968620625704837092796014241193945225284501741471925557
512-bit
    prime: 2^344 + 2^8 + 0x57 = 35835915874844867368919076489095108449946327955754392558399825615420669938882575126094039892345713852759
    offset: 9659303129496669498009435400716310466090418745672637896108374329434462657994582932197716438449813051892206539805784495328239340083876191928701583869517785
1024-bit
    prime: 2^680 + 2^8 + 0x8d = 5016456510113118655434598811035278955030765345404790744303017523831112055108147451509157692220295382716162651878526895249385292291816524375083746691371804094271873160484737966720260389217684476157468082573
    offset: 1419779506494762106872207064140321832088062279544193396087847491461758272325229673230371772250864096521202355549365628174669108571814760471015076148029755969804077320157692458563003215304957150157403644460363550505412711285966361610267868082893823963790439336411086884584107735010676915

Ayrıntılar için ana FNV sayfasına bakın.

Bütün sonuçlarım 32 bit değişkendir.

FNV-1, FNV-1a'dan daha mı iyi?

Hayır. FNV-1a her yerde daha iyi durumda. İngilizce corpus kelimesini kullanırken FNV-1a ile daha fazla çarpışma oldu:

Hash    Word Collisions
======  ===============
FNV-1   1
FNV-1a  4

Şimdi küçük ve büyük harfleri karşılaştırın:

Hash    lowercase word Collisions  UPPERCASE word collisions
======  =========================  =========================
FNV-1   1                          9
FNV-1a  4                          11

Bu durumda FNV-1a, "% 400" FN-1'den daha kötü değildir, sadece% 20 daha kötüdür.

Bence en önemli paket, çarpışmalar söz konusu olduğunda iki algoritma sınıfı olması:

  • nadir çarpışmalar : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
  • ortak çarpışmalar : SuperFastHash, Loselose

Ve sonra, karmaların ne kadar eşit dağılmış olduğu:

  • üstün dağıtım: Murmur2, FNV-1a, SuperFastHas
  • mükemmel dağıtım: FNV-1
  • iyi dağıtım: SDBM, DJB2, DJB2a
  • korkunç dağıtım: Loselose

Güncelleme

Mırıldanıyorum? Tabii neden olmasın


Güncelleme

@whatshisname bir CRC32'nin nasıl performans gösterdiğini merak etti, tabloya numaralar ekledi.

CRC32 oldukça iyi . Birkaç çarpışma, ancak daha yavaş ve 1k'lik bir arama tablosunun ek yükü.

CRC dağılımı ile ilgili tüm hatalı şeyleri koparın - benim kötü


Bugüne kadar fiili hash-tablo karma algoritması olarak FNV-1a'yı kullanacaktım . Ama şimdi Murmur2'ye geçiyorum:

  • Daha hızlı
  • Tüm girdi sınıflarının daha iyi tesadüfi olması

Ve gerçekten, gerçekten de SuperFastHashbulduğum algoritmada yanlış bir şeyler olduğunu umuyorum ; olduğu kadar popüler olmak çok kötü.

Güncelleme: Gönderen Google'da MurmurHash3 ana :

(1) - SuperFastHash, başka bir yerde belgelenen çok zayıf çarpışma özelliklerine sahiptir.

Sanırım sadece ben değilim.

Güncelleme: Neden Murmurdiğerlerinden daha hızlı olduğunu anladım . MurmurHash2 aynı anda dört baytta çalışır. Çoğu algoritma byte bayt :

for each octet in Key
   AddTheOctetToTheHash

Bu, anahtarlar uzadıkça Murmur'un parlama şansı olduğu anlamına gelir.


Güncelleme

GUID'ler rastgele değil, benzersiz olacak şekilde tasarlanmıştır

Raymond Chen'in zamanında gönderdiği bir yazı, "rastgele" GUID'lerin rastgele olmaları için kullanılmadığı gerçeğini yineliyor . Onlar veya alt kümeleri, karma anahtar olarak uygun değildir:

Sürüm 4 GUID algoritmasının bile tahmin edilemez olduğu garanti edilmez, çünkü algoritma rasgele sayı üretecinin kalitesini belirlemez. GUID için Wikipedia makalesi , jeneratörün kriptografik olarak güçlü olmadığı için gelecekteki ve önceki GUID'lerin rasgele sayı üreteci durumunun bilgisine dayanarak tahmin edilebileceğini öne süren birincil araştırmaları içermektedir .

Rastgele çarpışmadan kaçınma ile aynı değildir; bu nedenle, "rastgele" bir kılavuzun alt kümesini alarak kendi "karma" algoritmanızı icat etmeye çalışmak bir hata olur:

int HashKeyFromGuid(Guid type4uuid)
{
   //A "4" is put somewhere in the GUID.
   //I can't remember exactly where, but it doesn't matter for
   //the illustrative purposes of this pseudocode
   int guidVersion = ((type4uuid.D3 & 0x0f00) >> 8);
   Assert(guidVersion == 4);

   return (int)GetFirstFourBytesOfGuid(type4uuid);
}

Not : Yine, "rasgele GUID" i tırnak içine koyarım, çünkü GUID'lerin "rasgele" bir çeşididir. Daha doğru bir açıklama olacaktır Type 4 UUID. Fakat kimse tip 4 veya tip 1, 3 ve 5'in ne olduğunu bilmiyor. Bu yüzden onları "rastgele" GUID'ler olarak adlandırmak daha kolay.

Tüm İngilizce Kelimeler mirrors


41
SHA'nın nasıl karşılaştırılacağını görmek gerçekten ilginç olurdu, çünkü burada bir karma algoritma için iyi bir aday değil, ancak herhangi bir kriptografik karma'nın hız algoritmaları için yapılanlarla nasıl karşılaştırılacağını görmek gerçekten ilginç olurdu.
Michael

8
Yann Collet'in 'xxHash' adında yeni bir karma, geçenlerde tur yapıyordu. Her zaman yeni bir karmaşadan şüpheleniyorum. Karşılaştırmada görmek ilginç olurdu (eğer ekleneceklerini duydukları rastgele karmaları öneren insanlardan
sıkılmıyorsanız

7
Aslında. XxHash proje sayfasının ilan ettiği performans numaraları etkileyici görünüyor, gerçek olamayacak kadar fazla. En azından açık kaynaklı bir proje: code.google.com/p/xxhash
ATTracker

9
Merhaba Ian, SuperFastHash Delphi uygulamam doğrudur. Uygulama yaparken, uygulamamın sonuçlarını ve referans uygulamamı karşılaştırmak için C ve Delphi'de bir test seti oluşturdum. Fark yok. Öyleyse gördüğünüz karmaşanın asıl kötülüğüdür ... (Bu yüzden MurmurHash uygulamasını da yayınladım: landman-code.blogspot.nl/2009/02/… )
Davy Landman

19
Poster bunun sadece müthiş bir cevap olmadığını biliyor mu - bu konuyla ilgili dünyanın fiili referans kaynağı mı? Ne zaman hashlarla uğraşmam gerekiyorsa, sorunumu o kadar hızlı ve otoriter bir şekilde çözer ki başka hiçbir şeye ihtiyacım olmaz.
MaiaVictor

59

Değişmeyen bir sözlükten bir karma haritası oluşturmak istiyorsanız, mükemmel karma değerinin dikkate alınmasını isteyebilirsiniz - https://en.wikipedia.org/wiki/Perfect_hash_function - karma işlevinin ve karma tablosunun oluşturulması sırasında, Belirli bir veri kümesi için çarpışma olmayacak.


2
İşte (en az) Perfect Hashing burtleburtle.net/bob/hash/perfect.html , performans verilerini de içeren, en güncel işlemciyi kullanmasa da…
Ellie Kesselman,

4
Oldukça açık, ancak herhangi bir çarpışmayı garanti altına almamak için, algoritmanın kullanabileceği değerler üzerinde bir kısıtlama yoksa, anahtarların değerlerle aynı boyutta olması gerektiğine dikkat çekmek gerekir.
devios1

1
@ devios1 İfadeniz anlamsız. İlk olarak, bir karma tablosundaki değerler mükemmel veya değil, anahtarlardan bağımsızdır. İkincisi, mükemmel bir karma tablo, tüm indekslerin benzersiz olması için hazırlanmış olan fonksiyonun sonucu tarafından indekslenen sadece bir değerler dizisidir.
Jim Balter

1
@MarcusJ Mükemmel karma, genellikle 100'den az anahtarla kullanılır, ancak cmph.sourceforge.net'e bakın ... hala menzilinizin çok altında.
Jim Balter

1
@DavidCary Bağlantınızdaki hiçbir şey talebinizi desteklemiyor. Muhtemelen O (1) 'i "çarpışma yok" ile karıştırdınız, ancak hepsi aynı şey değil. Tabii ki, mükemmel karmaşa çarpışma garantisi vermez, ancak tüm anahtarların önceden bilinmesini ve göreceli olarak daha az sayıda bulunmasını gerektirir. (Ancak yukarıdaki cmph ile bağlantıya bakın.)
Jim Balter

34

İşte karma fonksiyonların bir listesi, ancak kısa versiyonu:

Eğer sadece iyi bir karma fonksiyonuna sahip olmak ve bekleyemezseniz, djb2bildiğim en iyi string hash fonksiyonlarından biri. Birçok farklı tuş takımı ve masa ebatında mükemmel bir dağıtım ve hıza sahiptir.

unsigned long
hash(unsigned char *str)
{
    unsigned long hash = 5381;
    int c;

    while (c = *str++)
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */

    return hash;
}

6
Aslında djb2 sıfıra duyarlıdır; çoğu bu basit karma fonksiyonlar gibi, böylelikle bu karma dizileri kolayca kırabilirsiniz. O en smhasher kalite testlerinde kırar, kötü bir önyargı çok fazla çarpışmalar ve kötü bir dağılım vardır: Bkz github.com/rurban/smhasher/blob/master/doc/bernstein O'nun cdb veritabanı kullanır, ancak bunu kullanmak ister halka açık.
Rurban

2
DJB, performans ve dağıtım açısından oldukça kötü. Bugün kullanmazdım.
Conrad Meyer

@ConradMeyer, bahse girerim ki, DJB benim bu sorudaki gibi üç kat daha hızlandırabilir ve sonra muhtemelen en kullanışlı algoritmaları yenerdi. Dağıtım konusunda katılıyorum. İki harfli dizeler için bile çarpışma yapan bir karmaşa gerçekten iyi olamaz.
maaartinus

28

Google'dan CityHash, aradığınız algoritmadır. Kriptografi için iyi değildir, ancak benzersiz hash üretme için iyidir.

Daha fazla ayrıntı için blogu okuyun ve kod burada mevcuttur .

CityHash, C ++ ile yazılmıştır. Ayrıca düz bir C bağlantı noktası var .

32 bit destek hakkında:

Tüm CityHash işlevleri 64 bit işlemciler için ayarlanmıştır. Bununla birlikte, 32 bit kodunda (SSE4.2 kullanan yenileri hariç) çalışacaklarını söyledi. Yine de çok hızlı olmayacaklar. Murmur veya başka bir şeyi 32-bit kodda kullanmak isteyebilirsiniz.


11
CityHash, "City Sushi" ye benziyor mu?
Eric

2
SipHash'a da bir göz atın, MurmurHash / CityHash / etc ile değiştirilir. : 131002.net/siphash
Török Edwin

3
Ayrıca bkz. CitHash'ın halefi olan FarmHash. code.google.com/p/farmhash
stevendaniels

7
xxHash, CityHash'tan 5 kat daha hızlı olduğunu iddia ediyor.
Clay Bridges

plain C portbağlantı koptu
makerj

20

Dosyaları karıştırırken farklı karma algoritmaların kısa bir hız karşılaştırmasını çizdim.

Ayrı ayrı parseller okuma yönteminde sadece biraz farklıdır ve burada tüm dosyalar bir tmpfs içerisinde saklandığı için göz ardı edilebilir. Bu nedenle, merak ediyorsanız kriter IO'ya bağlı değildi.

Algoritmalar şunlardır: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}.

Sonuç:

  • Murmur3, Cityhash ve Spooky gibi kriptografik olmayan karma fonksiyonlar birbirine oldukça yakın. Birisi Cityhash'ın, CRCişlemcimin sahip olmadığı SSE 4.2 talimatıyla CPU'larda daha hızlı olabileceğini unutmamalı . SpookyHash benim durumumda CityHash'tan önce hep küçük bir parça oldu.
  • MD5, şifreleme karma işlevlerini kullanırken iyi bir tradeoff gibi görünüyor, ancak SHA256 , MD5 ve SHA1'in çarpışma açıklarına karşı daha güvenli olabilir .
  • Tüm algoritmaların karmaşıklığı doğrusaldır - blok olarak çalıştıkları için şaşırtıcı değildir. (Okuma yönteminin bir fark yaratıp yaratmadığını görmek istedim, böylece sadece en doğru değerleri karşılaştırabilirsiniz).
  • SHA256, SHA512'den daha yavaştı.
  • Hash fonksiyonlarının rastgeleliğini araştırmamıştım. Ama burada eksik özet fonksiyonları iyi karşılaştırma Ian Boyds cevap . Bu CityHash'in köşe davalarında bazı problemleri olduğuna işaret ediyor.

Arsalar için kullanılan kaynak:


1
Doğrusal ölçek grafiği, çizdiği miktarı belirten y ekseni etiketini keser. Sanırım logaritmik skala ile aynı "saniye cinsinden zaman" olurdu. Tamir etmeye değer.
Craig McQueen,

18

SHA algoritmaları (SHA-256 dahil) hızlı olacak şekilde tasarlanmıştır .

Aslında, hızları bazen bir sorun olabilir. Özellikle, parola türetilmiş bir belirteci depolamak için yaygın bir teknik, standart bir hızlı karma algoritmasını 10.000 kez çalıştırmaktır (şifrenin karma değerinin karma değerini saklar).

#!/usr/bin/env ruby
require 'securerandom'
require 'digest'
require 'benchmark'

def run_random_digest(digest, count)
  v = SecureRandom.random_bytes(digest.block_length)
  count.times { v = digest.digest(v) }
  v
end

Benchmark.bmbm do |x|
  x.report { run_random_digest(Digest::SHA256.new, 1_000_000) }
end

Çıktı:

Rehearsal ------------------------------------
   1.480000   0.000000   1.480000 (  1.391229)
--------------------------- total: 1.480000sec

       user     system      total        real
   1.400000   0.000000   1.400000 (  1.382016)

57
Kriptografik bir karma algoritması için oldukça hızlı . Fakat OP sadece değerleri bir karma tabloda depolamak istiyor ve kriptografik bir karma fonksiyonunun bunun için gerçekten uygun olduğunu sanmıyorum.
Dean Harding

6
Soru, (teğetsel olarak, şimdi ortaya çıkıyor), şifreleme hash fonksiyonlarının konusu ile ortaya çıktı. Cevap verdiğim şey bu.
yfeldblum

15
İnsanları “Özellikle, şifre türetilmiş bir jetonun depolanması için yaygın bir teknik, standart bir hızlı karma algoritması 10.000 kez çalıştırmak” dır. Bu senaryolar için tasarlanmış algoritmalar vardır, örn bcrypt. Doğru araçları kullanın.
TC1

3
Şifreleme karmaları, yüksek verime sahip olacak şekilde tasarlanmıştır, ancak bu genellikle yüksek kurulum, ayırma .rodatave / veya durum maliyetleri anlamına gelir . Bir karma tablo için bir algoritma istediğinizde, genellikle çok kısa anahtarlara ve çoğuna sahip olursunuz, ancak bir şifreleme özelliğinin ek garantilerine gerek yoktur. Tweaked Jenkins'in teker tekerini kendim kullanıyorum.
mirabilos

1
@ChrisMorgan: Kriptografik olarak güvenli bir karma kullanmak yerine, HashTable DoS, karma rastgele birleştirme kullanarak çok daha verimli bir şekilde çözülebilir, böylece programların her çalıştırması, hatta her karma tablo üzerinde, böylece veriler her seferinde aynı kovada gruplandırılmaz .
Yalan Ryan

14

SHA-256 gibi şeyler olduğunu biliyorum, ancak bu algoritmalar güvenli olacak şekilde tasarlandı , bu da genellikle daha az benzersiz olan algoritmalardan daha yavaş oldukları anlamına geliyor .

Kriptografik karma fonksiyonların daha eşsiz olduğu varsayımı yanlıştır ve aslında uygulamada sıklıkla geriye doğru olduğu gösterilebilir. Aslında:

  1. Kriptografik karma fonksiyonları ideal olarak rasgele ayırt edilemez olmalıdır ;
  2. Ancak kriptografik olmayan karma işlevlerde, olası girdilerle olumlu etkileşime girmeleri istenir .

Hangi olmayan bir kriptografik hash fonksiyonu iyi olabileceğini gösterir az çarpışmalara set-veriler için tasarlanmış olduğunu belirler "iyi" veri için şifreleme olandan.

Bunu aslında Ian Boyd'un cevabındaki ve biraz da matematiğindeki verilerle gösterebiliriz: Doğum günü problemi . Kümeden nrasgele tamsayı seçerseniz, beklenen çarpışan çift sayısının formülü [1, d]şöyledir (Wikipedia'dan alınmıştır):

n - d + d * ((d - 1) / d)^n

Takma n= 216,553 ve d= 2 ^ 32 yaklaşık almak 5.5 beklenen çarpışma . Ian'ın testleri çoğunlukla bu mahallenin etrafındaki sonuçları gösteriyor, ancak çarpıcı bir istisna dışında: fonksiyonların çoğu ardışık sayı testlerinde sıfır çarpışma aldı. 216,553 32 bit sayıyı rastgele seçme ve sıfır çarpışma alma olasılığı yaklaşık% 0,43'dür. Ve bu sadece bir işlev için - burada sıfır çarpışma olan beş ayrı karma işlev ailemiz var!

Burada gördüğümüz karmaşanın, Ian'ın test ettiği karışmaların ardışık sayılar veri kümesiyle olumlu bir şekilde etkileşime girdiğidir - yani, ideal bir şifreleme hash işlevinden daha geniş ölçüde farklı girdiler dağıtıyorlar. (Not: bu, Ian'ın FNV-1a ve MurmurHash2'nin kendisine veri sayılarında "rastgele göründüğü" grafiksel değerlendirmesinin, kendi verilerinden reddedilebileceği anlamına gelir. Her iki karma işlevi için bu boyuttaki veri kümesinde sıfır çarpışmalar , çarpıcı bir şekilde rastgele!

Bu sürpriz değil, çünkü bu karma fonksiyonların birçok kullanımı için istenen bir davranış. Örneğin, karma tablo anahtarları genellikle çok benzerdir; Ian'ın cevabı, MSN'in bir zamanlar ZIP kodu karma tabloları ile ilgili bir problemden bahsetti . Bu, muhtemel girdilerde çarpışmadan kaçınmanın rastgele benzeri davranışlar üzerine kazandığı bir kullanımdır .

Buradaki diğer bir öğretici karşılaştırma, CRC ve kriptografik karma işlevleri arasındaki tasarım hedeflerindeki karşıtlıktır:

  • CRC, az sayıda bit kayması olması muhtemel olan gürültülü iletişim kanallarından kaynaklanan hataları yakalamak için tasarlanmıştır ;
  • Kripto hasheleri, sınırlı işlemsel kaynaklar tahsis edilmiş fakat keyfi olarak çok akıllıca ayrılmış kötü niyetli saldırganlar tarafından yapılan değişiklikleri yakalamak için tasarlanmıştır .

Dolayısıyla, CRC için, minimal olarak farklı girdilerde rastgeledan daha az çarpışma olması tekrar iyidir . Kripto hash ile bu bir hayır-hayır!


10

SipHash kullanın . It has birçok istenir özelliklere:

  • Hızlı. Optimize edilmiş bir uygulama bayt başına yaklaşık 1 devir alır.

  • Güvenli. SipHash güçlü bir PRF'dir (yalancı rasgele fonksiyon). Bu, rastgele bir işlevden ayırt edilemez olduğu anlamına gelir (128 bit gizli anahtarı bilmiyorsanız). Dolayısıyla:

    • Hash tablası problarınızın çarpışmalar nedeniyle doğrusal zaman kazanması konusunda endişelenmenize gerek yok SipHash ile girdilere bakılmaksızın ortalama olarak ortalama vaka performansı alacağınızı biliyorsunuz .

    • Hizmet temelli hizmet reddi saldırılarına karşı bağışıklık.

    • MAC (Mesaj Doğrulama Kodu) olarak SipHash'ı (özellikle 128 bit çıkışlı versiyonu) kullanabilirsiniz. Bir mesaj ve bir SipHash etiketi alırsanız ve etiket, SipHash'ı gizli anahtarınızla çalıştırmanınkiyle aynıysa, o zaman hashı yaratan kişinin aynı zamanda gizli anahtarınıza sahip olduğunu ve ne mesajın ne de hash o zamandan beri değişmiş.


1
SipHash güvenliğe ihtiyaç duymadıkça fazla öldürülmüyor mu? Sadece yüceltilmiş bir karma tohum olan 128-bit bir anahtar gerektirir. MurmurHash3'ün 128-bit çıkışı vardır ve SipHash'ın sadece 64-bit çıkışı vardır. Açıkçası, daha büyük özetin daha düşük bir çarpışma şansı var.
bryc

@bryc Farkı, SipHash'ın kötü niyetli girdilerde bile iyi davranılmaya devam edeceğidir. SipHash tabanlı bir karma tablo, potansiyel olarak düşmanca kaynaklardan gelen veriler için kullanılabilir ve karma işlevinin ayrıntılarına çok hassas olan doğrusal sondaj gibi bir algoritma kullanabilir.
Demi

9

Bu, sahip olduğunuz verilere bağlıdır. Bazı karma metin gibi belirli verilerle daha iyi çalışır. Bazı karma algoritmalar, spesifik veriler için iyi olacak şekilde özel olarak tasarlanmıştır.

Paul Hsieh bir zamanlar hızlı hash yaptı . Kaynak kodunu ve açıklamalarını listeler. Ama çoktan dövüldü. :)


6

Java bu basit çarp ve ekle algoritmasını kullanır:

Bir String nesnesinin karma kodu şöyle hesaplanır

 s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

int aritmetik, kullanan s[i]bir i dize ıncı karakteri, ndizenin uzunluğu ve ^üs gösterir. (Boş dizenin karma değeri sıfırdır.)

Orada muhtemelen çok daha iyi olanlar var ama bu oldukça yaygın ve hız ve benzersizlik arasında iyi bir denge gibi görünüyor.


12
Burada kullanılanla aynı olanı kullanmazdım, çünkü bununla çarpışma yapmak hala nispeten kolay. Bu var kesinlikle korkunç değil, ama çok daha iyi olanlar orada var. Java ile uyumlu olmak için önemli bir neden yoksa , seçilmemelidir.
Joachim Sauer

4
Hala bir nedenden dolayı bu karma yöntemi seçerseniz, en azından 92821 gibi daha iyi bir prime çarpanı kullanabilirsiniz. Bu çarpışmaları çok azaltır. stackoverflow.com/a/2816747/21499
Hans-Peter Störr

1
Bunun yerine FNV1a'yı da kullanabilirsiniz. Aynı zamanda basit bir çarpma tabanlı karma, ancak hash'ı daha iyi dağıtan daha büyük bir çarpan kullanır.
bryc

4

Her şeyden önce, neden kendi karma işlemenizi yapmanız gerekiyor? Çoğu görev için, standart bir kütüphaneden veri yapılarıyla iyi sonuçlar almalısınız, bir uygulama olduğunu varsayarak (bunu sadece kendi eğitiminiz için yapmıyorsanız).

Gerçek karma algoritmalar gittiğinde kişisel favorim FNV. 1

İşte C'deki 32-bit versiyonun örnek bir uygulaması:

unsigned long int FNV_hash(void* dataToHash, unsigned long int length)
{
  unsigned char* p = (unsigned char *) dataToHash;
  unsigned long int h = 2166136261UL;
  unsigned long int i;

  for(i = 0; i < length; i++)
    h = (h * 16777619) ^ p[i] ;

  return h;
}

2
FNV-1a varyantı rasgelelikle biraz daha iyidir. Sırasını değiştirme *ve ^: h = (h * 16777619) ^ p[i]==>h = (h ^ p[i]) * 16777619
Ian Boyd
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.