it-swarm.asia

Benzersizlik ve hız için hangi karma algoritma en iyisidir?

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

SHA-256 ve benzeri şeyler olduğunu biliyorum, ama bu algoritmalar güvenli , bu genellikle daha az olan algoritmalardan daha yavaş oldukları anlamına gelir benzersiz. Hızlı olmak için tasarlanmış bir karma algoritma istiyorum, ancak çarpışmaları önlemek için oldukça benzersiz kalıyorum.

1444
Earlz

Hız ve çarpışma sayısını ölçen farklı algoritmaları test ettim.

Üç farklı anahtar seti kullandım:

Her bir ceset için, çarpışmaların sayısı ve karma işlem için harcanan ortalama süre kaydedildi.

Test ettim:

Sonuçlar

Her sonuç ortalama karma süresini 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 :

  • LoseLose algoritması (karma = karma + karakter) gerçekten korkunç. Her şey aynı 1.375 kovaya çarpıyor
  • SuperFastHash hızlı, işler oldukça dağınık görünüyor; Tanrım = sayı çarpışmalar. Taşıyan adamın yanlış bir şey aldığını umuyorum ; oldukça kötü
  • CRC32 oldukça iyi. Daha yavaş ve 1k arama tablosu

Çarpışmalar gerçekten oluyor mu?

Evet. Karma çarpışmaların aslında olup olmadığını görmek için test programımı yazmaya başladım ve sadece teorik bir yapı değiller. Gerçekten olurlar:

FNV-1 çarpışmaları

  • creamwovequists ile çarpışır

FNV-1a çarpışmaları

  • costarringliquid ile çarpışır
  • declinatemacallums ile çarpışır
  • altaragezinke ile çarpışır
  • altarageszinkes ile çarpışır

Üfürüm2 çarpışması

  • cataractperiti ile çarpışır
  • roquetteskivie ile çarpışır
  • shawlstormbound ile çarpışır
  • dowlasestramontane ile çarpışır
  • cricketingstwanger ile çarpışır
  • longanswhigs ile çarpışır

DJB2 çarpışmaları

  • hetairasmentioner ile çarpışır
  • heliotropesneurospora ile çarpışır
  • depravementserafins ile çarpışır
  • stylistsubgenera ile çarpışır
  • joyfulsynaphea ile çarpışır
  • redescribedurites ile çarpışır
  • dramvivency ile çarpışır

DJB2a çarpışmaları

  • haggadotloathsomenesses ile çarpışır
  • adorablenessesrentability ile çarpışır
  • playwrightsnush ile çarpışır
  • playwrightingsnushing ile çarpışır
  • treponematoseswaterbeds ile çarpışır

CRC32 çarpışmaları

  • coddinggnu ile çarpışır
  • exhibitersschlager ile çarpışır

SuperFastHash çarpışmaları

  • dahabiahdrapability ile çarpışır
  • encharmenclave ile çarpışır
  • grahamsgramary ile çarpışır
  • ... 79 çarpışmayı kes ...
  • nightvigil ile çarpışır
  • nightsvigils ile çarpışır
  • finksvinic ile çarpışır

Randomnessification

Diğer öznel önlem, karmaların ne kadar rasgele dağıtıldığıdır. Elde edilen HashTable'ların eşlenmesi, verilerin ne kadar eşit olarak dağıtıldığını gösterir. Tabloyu doğrusal olarak eşlerken tüm sağlama işlevleri iyi bir dağılım gösterir:

Enter image description here

Veya Hilbert Haritası ( XKCD her zaman alakalı ):

Enter image description here

Sayı dizelerini ayırırken ("1", "2", ..., "216553") (örneğin, Posta kodları ), burada karma algoritmaların çoğunda kalıplar ortaya çıkmaya başlar:

[~ # ~] SDBM [~ # ~] :

Enter image description here

DJB2a :

Enter image description here

FNV'nin-1 :

Enter image description here

FNV-1a hariç, hepsi bana hala rastgele görünüyor:

Enter image description here

Aslında, Murmur2 Numbers ile FNV-1a'den daha iyi bir rasgeleliğe sahip gibi görünüyor:

Enter image description here

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


Tablodaki fazladan *, rastgeleliğin ne kadar kötü olduğunu gösterir. FNV-1a en iyisi ve DJB2x en kötüsü:

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

Başlangıçta ben çarpışmalar hakkında endişe bile olup olmadığına karar vermek için bu programı yazdım: Yaparım.

Ve sonra, karma işlevlerinin yeterince rastgele olduğundan emin olmaya dönüştü.

FNV-1a algoritması

FNV1 karması 32, 64, 128, 256, 512 ve 1024 bit karmaları döndüren varyantlarda gelir.

FNV-1a algoritması :

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

FNV_offset_basis ve FNV_prime sabitleri istediğiniz dönüş karma boyutuna bağlıdır:

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.

Tüm sonuçlarım 32-bit varyantı ile.

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

Hayır. FNV-1a her yerde daha iyidir. İngilizce Word corpus 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ğil, sadece% 20 daha kötüdür.

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

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

Ve sonra karmaların ne kadar eşit dağıldığı var:

  • olağanüstü dağıtım: Murmur2, FNV-1a, SuperFastHas
  • mükemmel dağılım: FNV-1
  • iyi dağıtım: SDBM, DJB2, DJB2a
  • korkunç dağıtım: Kaybetmek

Güncellemesi

Üfürüm? Tabii, neden olmasın


Güncellemesi

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

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

CRC dağıtımı ile ilgili tüm hatalı şeyleri kesin - benim hatam


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

  • Daha hızlı
  • Daha iyi rasgeleleştirme tüm girdi sınıflarının

Ve gerçekten, gerçekten Umarım bulduğum SuperFastHash algoritmasında yanlış bir şey vardır ; olduğu kadar popüler olmak çok kötü.

Güncelleme: Google'daki MurmurHash3 ana sayfasından :

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

Sanırım sadece ben değilim.

Güncelleme: Murmur 'ın neden diğerlerinden daha hızlı olduğunu anladım. MurmurHash2 bir seferde dört bayt üzerinde çalışır. Çoğu algoritma bayt bayt:

for each octet in Key
   AddTheOctetToTheHash

Bu, anahtarlar uzadıkça Murmur'un parlama şansını elde ettiği anlamına gelir.


Güncellemesi

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

Raymond Chen tarafından zamanında gönderilen bir gönderi "rastgele" GUID'lerin rastgele olmaları için kullanılmadığı gerçeğini yinelemektedir. Onlar veya bunların bir alt kümesi, bir karma anahtar olarak uygun değildir:

Sürüm 4 GUID algoritmasının bile öngörülemez olduğu garanti edilmez, çünkü algoritma rasgele sayı üretecinin kalitesini belirtmez. GUID için Wikipedia makalesi, gelecekteki ve önceki GUID'lerin, rasgele sayı üreteci durumu bilgisine dayanılarak tahmin edilebileceğini öneren birincil araştırmayı içerir, çünkü jeneratör şifreli olarak değildir kuvvetli.

Rasgelelik, çarpışmadan kaçınma ile aynı şey değildir; bu yüzden "rastgele" bir kılavuzun alt kümesini alarak kendi "karma" algoritmanızı icat etmeye çalışmak 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, "rastgele GUID" tırnak işaretleri koydum, çünkü GUID'lerin "rastgele" varyantı. Daha doğru bir açıklama Type 4 UUID olacaktır. Ancak kimse tip 4'ün veya tip 1, 3 ve 5'in ne olduğunu bilmiyor. Bu yüzden onlara "rastgele" GUID'ler demek daha kolaydır.

Tüm İngilizce kelimeler

2530
Ian Boyd

Değişmeyen bir sözlükten bir karma harita oluşturmak istiyorsanız, karma işlevini oluştururken mükemmel karma https://en.wikipedia.org/wiki/Perfect_hash_function - ve hash tablosu, belirli bir veri kümesi için çarpışma olmayacağını garanti edebilirsiniz.

61
Damien

Here , karma işlevlerinin bir listesidir, ancak kısa sürüm:

Sadece iyi bir karma işlevine sahip olmak istiyorsanız ve bekleyemezseniz, djb2 bildiğim en iyi dize karma işlevlerinden biridir. Birçok farklı anahtar ve masa boyutu setinde mükemmel dağılı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;
}
34
Dean Harding

CityHash by Google, aradığınız algoritmadır. Kriptografi için iyi değildir, ancak benzersiz karmalar oluşturmak için iyidir.

Daha fazla bilgi için blog adresini ve kodu burada bulabilirsiniz adresini okuyun.

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

Yaklaşık 32 bit desteği:

Tüm CityHash işlevleri 64 bit işlemciler için ayarlanmıştır. Bununla birlikte, 32-bit kodda (SSE4.2 kullanan yeni olanlar hariç) çalışacaklardır. Yine de çok hızlı olmayacaklar. Murmur ya da başka bir şeyi 32 bit kodda kullanmak isteyebilirsiniz.

29
Vipin Parakkat

Dosyaları karma yaparken farklı karma algoritmaların kısa hızlı karşılaştırmasını çizdim.

Tek tek grafikler okuma yönteminde çok az farklılık gösterir ve tüm dosyalar bir tmpfs içinde saklandığından burada yok sayılabilir. Eğer merak ediyorsanız, bu nedenle kriter IO-bağlı değildi.

Algoritmalar şunları içerir: SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}.

Sonuç:

  • Murmur3, Cityhash ve Spooky gibi kriptografik olmayan karma işlevler birbirine oldukça yakındır. Cityhash'ın CPU'mda olmayan SSE 4.2s CRC talimatı) CPU'larda daha hızlı olabileceğini unutmamalıyım.
  • MD5, şifreleme sağlama işlevlerini kullanırken iyi bir dengede gibi görünmektedir, ancak SHA256, MD5 ve SHA1'in çarpışma güvenlik açıkları için daha güvenli olabilir.
  • Tüm algoritmaların karmaşıklığı doğrusaldır - blok halinde çalıştıkları için gerçekten şaşırtıcı değildir. (Okuma yönteminin bir fark yaratıp yaratmadığını görmek istedim, böylece en sağdaki değerleri karşılaştırabilirsiniz).
  • SHA256, SHA512'den daha yavaştı.
  • Karma işlevlerinin rastgeleliklerini araştırmadım. Ancak burada , eksik olan karma işlevlerinin Ian Boyds cevabı içinde iyi bir karşılaştırmasıdır. Bu, CityHash'in köşe vakalarında bazı problemleri olduğuna işaret ediyor.

Arsalar için kullanılan kaynak:

21
Sahib

SHA algoritmaları (SHA-256 dahil) tasarlanmış olarak hızlı şeklindedir.

Aslında, hızları bazen bir sorun olabilir. Özellikle, paroladan türetilen bir jetonu depolamak için yaygın bir teknik, standart bir hızlı karma algoritmasını 10.000 kez çalıştırmaktır (... parolasının karma karmasının karmasını depolamak).

#!/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)
18
yfeldblum

SHA-256 ve benzeri şeyler olduğunu biliyorum, ama bu algoritmalar tasarlanmış olmak güvenli, bu genellikle daha az olan algoritmalardan daha yavaş olduğu anlamına gelir benzersiz.

Kriptografik karma işlevlerinin daha benzersiz olduğu varsayımı yanlıştır ve aslında pratikte genellikle geriye doğru olduğu gösterilebilir. Gerçekte:

  1. Kriptografik karma fonksiyonları ideal olarak rastgele ayırt edilemez olmalıdır;
  2. Ancak kriptografik olmayan karma işlevlerle, olası girdilerle olumlu etkileşimde bulunmaları istenir.

Bu, kriptografik olmayan bir karma işlevinin, "iyi" veri kümesi için tasarlandığı veri kümeleri için kriptografik olandan daha iyi daha az çarpışma olabileceği anlamına gelir.

Bunu aslında Ian Boyd'un cevabı ve biraz matematikteki verilerle gösterebiliriz: Doğum Günü problemi . [1, d] Kümesinden rasgele n tamsayı seçerseniz beklenen çarpışan çiftlerin formülü şudur: (Wikipedia'dan alınmıştır):

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

n = 216,553 ve d = 2 ^ 32 tıklandığında 5,5 beklenen çarpışma alırız. Ian'ın testleri çoğunlukla bu mahallenin etrafında sonuçlar gösterir, ancak dramatik bir istisna dışında: işlevlerin çoğu ardışık sayı testlerinde sıfır çarpışma aldı. Rastgele 216.553 32 bit sayı seçme ve sıfır çarpışma olasılığı% 0,43 civarındadır. Ve bu sadece bir işlev için - burada sıfır çarpışmayla beş farklı hash işlevi ailesi var!

Burada gördüğümüz şey, Ian'ın test ettiği karma değerlerin olumlu ardışık sayılar veri kümesiyle etkileşime girmesidir; yani, minimal farklı girdiler ideal bir şifreleme karma işlevinden daha geniş. (Yan not: Bu, Ian'ın FNV-1a ve MurmurHash2'nin veri setinde kendisine "rastgele göründüğüne" ilişkin grafik değerlendirmesinin kendi verilerinden çürütülebileceği anlamına gelir. = both hash fonksiyonları, çarpıcı bir şekilde rastgele değil!)

Bu sürpriz değildir, çünkü bu, hash işlevlerinin birçok kullanımı için arzu edilen bir davranıştır. Örneğin, karma tablo tuşları genellikle çok benzerdir; Ian'ın cevabından bahsediyor MSN'in bir zamanlar Posta kodu karma tablolarında sahip olduğu bir sorun . Bu, olası girdilerdeki çarpışmadan kaçınmanın rastgele benzer davranışlar üzerinden kazanıldığı bir kullanımdır.

Burada bir başka öğretici karşılaştırma, CRC ve kriptografik hash fonksiyonları arasındaki tasarım hedeflerindeki kontrasttır:

  • CRC, az sayıda bit çevirme olasılığı olan gürültülü iletişim kanallarından kaynaklanan hatalar yakalamak için tasarlanmıştır;
  • Kripto karmaları, sınırlı hesaplama kaynakları ancak keyfi olarak çok zekice tahsis edilen kötü niyetli saldırganlar tarafından yapılan değişiklikler yakalamak için tasarlanmıştır.

Yani CRC için, minimal farklı girişlerde rastgele daha az çarpışma olması iyi. Kripto karmalarıyla, bu hayır-hayır!

15
sacundim

SipHash kullanın. birçok arzu edilen özelliğe sahiptir:

  • Hızlı. Optimize edilmiş bir uygulama bayt başına yaklaşık 1 döngü sürer.

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

    • Karma tablo problarınızın çarpışmalar nedeniyle lineer hale gelmesi konusunda endişelenmenize gerek yok. SipHash ile girdilere bakılmaksızın ortalama olarak ortalama durum performansı elde edeceğinizi bilirsiniz .

    • Karma tabanlı hizmet reddi saldırılarına karşı bağışıklık.

    • SipHash'i (özellikle 128 bit çıkışlı sürüm) MAC (Mesaj Kimlik Doğrulama Kodu) olarak kullanabilirsiniz. Bir ileti ve bir SipHash etiketi alırsanız ve etiket, SipHash'i gizli anahtarınızla çalıştırmayla aynı ise, o zaman hash'ı oluşturanın da gizli anahtarınıza sahip olduğunu ve ne iletinin ne de karma beri değiştirildi.

10
Demi

Bu, hash ettiğiniz verilere bağlıdır. Bazı karma metin gibi belirli verilerle daha iyi çalışır. Bazı karma algoritmalar spesifik olarak belirli veriler için iyi olacak şekilde tasarlanmıştır.

Paul Hsieh bir zamanlar hızlı karma yaptı. Kaynak kodu ve açıklamaları listeler. Ama çoktan dövülmüştü. :)

9
user712092

Java this basit çarpma ve ekleme algoritmasını kullanır:

Bir String nesnesinin sağlama kodu şu şekilde hesaplanır:

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

int aritmetik kullanarak, burada s[i], dizenin i karakteridir, n dizenin uzunluğudur ve ^, üstellemeyi belirtir. (Boş dizenin sağlama değeri sıfırdır.)

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

6
biziclop

Her şeyden önce, neden kendi karma işleminizi uygulamanız gerekiyor? Çoğu görev için, mevcut bir uygulama olduğu varsayılarak (sadece kendi eğitiminiz için bunu yapmadığınız sürece) standart bir kütüphaneden veri yapıları ile iyi sonuçlar almalısınız.

Gerçek karma algoritmalara gelince, benim kişisel favorim FNV. 1

C'deki 32 bit sürümünün ö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;
}
4
user17754