Hàm Hash tốt là gì?


130

Hàm Hash tốt là gì? Tôi đã thấy rất nhiều hàm băm và ứng dụng trong các khóa học cấu trúc dữ liệu của mình ở trường đại học, nhưng tôi hầu như nhận thấy rằng thật khó để tạo ra hàm băm tốt. Như một quy tắc để tránh va chạm, giáo sư của tôi đã nói rằng:

function Hash(key)
  return key mod PrimeNumber
end

(mod là toán tử% trong C và các ngôn ngữ tương tự)

với số nguyên tố là kích thước của bảng băm. Tôi hiểu rằng đó là một chức năng khá tốt để tránh va chạm và nhanh chóng, nhưng làm thế nào tôi có thể làm cho tốt hơn? Có các hàm băm tốt hơn cho các khóa chuỗi so với các phím số không?


34
Bạn đã cân nhắc sử dụng một hoặc nhiều hàm băm cho mục đích chung sau: partow.net/programming/hashfifts/index.html

Trong fnv_func, loại p [i] là char, điều gì sẽ xảy ra với h sau lần lặp đầu tiên? Nó đã được thực hiện trong mục đích?

5
@martinatime cho biết: Có rất nhiều thông tin xung quanh các hàm băm trong wikipedia en.wikipedia.org/wiki/Hash_feft và phần dưới của bài viết này partow.net/programming/hashfifts/index.html có thuật toán được triển khai bằng nhiều ngôn ngữ khác nhau.
2501

Câu trả lời:


33

Để thực hiện tra cứu bảng băm "bình thường" trên cơ bản bất kỳ loại dữ liệu nào - dữ liệu này của Paul Hsieh là cách tốt nhất tôi từng sử dụng.

http://www.azillionmonkeys.com/qed/hash.html

Nếu bạn quan tâm về bảo mật bằng mật mã hoặc bất kỳ thứ gì cao cấp hơn, thì YMMV. Nếu bạn chỉ muốn một hàm băm mục đích chung kick ass cho tra cứu bảng băm, thì đây là những gì bạn đang tìm kiếm.


Cảm ơn các liên kết thông tin! Tôi biết một vài phân tích của Bob Jenkins và những người khác chỉ ra các hàm băm khá phổ biến được chấp nhận nhưng tôi chưa bắt gặp cái này.
Konrad Rudolph

Tôi đã đọc từ trang web của Jenkins rằng SFH là một trong những điều tốt nhất sau đó, nhưng tôi nghĩ Murmur có thể làm tốt hơn, hãy xem câu trả lời tuyệt vời này: lập trình
viên.stackexchange.com/questions/49550/iêu

2
YMMV có nghĩa là gì?
cobarzan

3
@cobarzan Số dặm của bạn có thể thay đổi
Lập trình viên

2
Hàm băm của Hsieh là khủng khiếp, với một mức độ va chạm lớn hơn chúng ta muốn. Cụ thể, các chuỗi chỉ khác nhau trong 4 byte cuối có thể va chạm dễ dàng. Nếu bạn có một chuỗi 30 ký tự, khác nhau trong 4 byte cuối cùng, sau 28 byte đã được xử lý, các giá trị băm chỉ khác nhau ở 2 byte cuối. Điều đó có nghĩa là bạn được ĐẢM BẢO một xung đột cho một trong các giá trị hai byte còn lại. (Vâng, nó rất nhanh. Vậy thì sao.)
Andrew Lazarus

51

Không có thứ gọi là hàm băm tốt của Viking, đối với các hàm băm phổ quát (vâng, vâng, tôi biết có một thứ như là băm vạn năng phổ biến, nhưng đó không phải là ý tôi). Tùy thuộc vào ngữ cảnh, các tiêu chí khác nhau sẽ xác định chất lượng của hàm băm. Hai người đã đề cập đến SHA. Đây là một hàm băm mật mã và nó hoàn toàn không tốt cho các bảng băm mà bạn có thể muốn nói.

Bảng băm có các yêu cầu rất khác nhau. Tuy nhiên, việc tìm kiếm một hàm băm tốt trên toàn cầu rất khó vì các loại dữ liệu khác nhau phơi bày thông tin khác nhau có thể được băm. Theo nguyên tắc thông thường, tốt nhất là xem xét tất cả các thông tin mà một loại giữ như nhau. Điều này không phải lúc nào cũng dễ dàng hoặc thậm chí có thể. Vì lý do thống kê (và do đó va chạm), điều quan trọng là tạo ra sự lan truyền tốt trên không gian vấn đề, tức là tất cả các đối tượng có thể. Điều này có nghĩa là khi băm các số trong khoảng từ 100 đến 1050, sẽ không tốt khi để chữ số có ý nghĩa nhất đóng vai trò lớn trong hàm băm vì với ~ 90% các đối tượng, chữ số này sẽ là 0. Điều quan trọng hơn nhiều là để cho ba chữ số cuối cùng chữ số xác định hàm băm.

Tương tự, khi băm chuỗi, điều quan trọng là phải xem xét tất cả các ký tự - ngoại trừ khi biết trước rằng ba ký tự đầu tiên của tất cả các chuỗi sẽ giống nhau; xem xét những điều này sau đó là một sự lãng phí.

Đây thực sự là một trong những trường hợp mà tôi khuyên nên đọc những gì Knuth nói trong Nghệ thuật lập trình máy tính , tập. 3. Một tác phẩm hay khác là Nghệ thuật băm của Julienne Walker's .


1
Konrad, bạn chắc chắn đúng từ góc độ lý thuyết, nhưng bạn đã bao giờ thử sử dụng hàm băm Paul Hsieh mà tôi đã đề cập trong nhận xét của mình chưa? Nó thực sự khá tốt đối với nhiều loại dữ liệu khác nhau!
Chris Harris

9

Có hai mục đích chính của hàm băm:

  • để phân tán các điểm dữ liệu thống nhất thành n bit.
  • để xác định an toàn dữ liệu đầu vào.

Không thể đề xuất một hàm băm mà không biết bạn đang sử dụng nó để làm gì.

Nếu bạn chỉ tạo một bảng băm trong một chương trình, thì bạn không cần phải lo lắng về việc thuật toán có thể đảo ngược hoặc có thể hack được như thế nào ... SHA-1 hoặc AES hoàn toàn không cần thiết cho việc này, bạn nên sử dụng tốt hơn một biến thể của FNV . FNV đạt được sự phân tán tốt hơn (và do đó ít va chạm hơn) so với một mod nguyên tố đơn giản như bạn đã đề cập và nó thích nghi hơn với các kích cỡ đầu vào khác nhau.

Nếu bạn đang sử dụng băm để ẩn và xác thực thông tin công khai (chẳng hạn như băm mật khẩu hoặc tài liệu), thì bạn nên sử dụng một trong những thuật toán băm chính được xem xét kỹ lưỡng bởi sự xem xét công khai. Hash Function Lounge là một nơi tốt để bắt đầu.


liên kết được cập nhật tới The Hash Function Lounge: larc.usp.br/~pbarreto/hflounge.html
Tim Partridge

FNV chịu được va chạm sinh nhật tốt như thế nào so với, ví dụ, cùng số bit ra khỏi SHA1?
Kevin Hsu

@Kevin Miễn là các đặc tính sẵn có của hàm băm là tốt (những thay đổi nhỏ trong đầu vào = thay đổi lớn về đầu ra) thì va chạm sinh nhật chỉ đơn giản là một chức năng của các bit trong hàm băm. FNV-1a là tuyệt vời về vấn đề này và bạn có thể có nhiều hoặc ít bit trong hàm băm như bạn muốn (mặc dù phải mất thêm một chút nỗ lực để có được số bit không phải là lũy thừa 2).
Myrddin Emrys

5

Đây là một ví dụ về một cái tốt và cũng là một ví dụ về lý do tại sao bạn sẽ không bao giờ muốn viết nó. Đó là Hash Fowler / Noll / Vo (FNV), là bộ phận thiên tài khoa học máy tính và voodoo thuần túy:

unsigned fnv_hash_1a_32 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned h = 0x811c9dc5;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x01000193;

   return h;
}

unsigned long long fnv_hash_1a_64 ( void *key, int len ) {
    unsigned char *p = key;
    unsigned long long h = 0xcbf29ce484222325ULL;
    int i;

    for ( i = 0; i < len; i++ )
      h = ( h ^ p[i] ) * 0x100000001b3ULL;

   return h;
}

Biên tập:

  • Landon Curt Noll khuyến nghị trên trang web của mình thuật toán FVN-1A so với thuật toán FVN-1 ban đầu: Thuật toán được cải tiến phân tán tốt hơn byte cuối cùng trong hàm băm. Tôi điều chỉnh thuật toán cho phù hợp.

3
Bạn có thể muốn xem trang web này để biết một số thông tin về lý do tại sao các giá trị này được chọn: isthe.com/chongo/tech/comp/fnv/#fnv-prime
Cthutu

Ban phước cho bạn Hàm băm 64 bit ngắn, đơn giản, hiệu quả, chung chung và hiệu quả này chính xác là những gì tôi cần.
mattarod

3

Tôi muốn nói rằng quy tắc chính là không được tự lăn. Cố gắng sử dụng một cái gì đó đã được kiểm tra kỹ lưỡng, ví dụ, SHA-1 hoặc thứ gì đó dọc theo những dòng đó.


Anh ta dường như không cần bất cứ thứ gì an toàn về mật mã, vì vậy SHA-1 sẽ trở nên quá mức cần thiết.
Erik

bằng cách này, mặc dù không có va chạm nào cho SHA-1 đã được tìm thấy nhưng nó được cho là vấn đề của nhiều năm hoặc nhiều tháng trước khi tìm thấy. Tôi sẽ khuyên bạn nên sử dụng SHA-256.
Samuel Allan

1

Hàm băm tốt có các thuộc tính sau:

  1. Đưa ra một hàm băm của một tin nhắn, kẻ tấn công không thể tính toán được để tìm một tin nhắn khác sao cho băm của chúng giống hệt nhau.

  2. Cho một cặp thông điệp, m 'và m, không thể tính toán được hai thông số sao cho h (m) = h (m')

Hai trường hợp không giống nhau. Trong trường hợp đầu tiên, có một hàm băm có sẵn mà bạn đang cố gắng tìm sự va chạm. Trong trường hợp thứ hai, bạn đang cố gắng tìm bất kỳ hai tin nhắn va chạm. Nhiệm vụ thứ hai dễ dàng hơn đáng kể do "nghịch lý" sinh nhật.

Trong đó hiệu suất không phải là vấn đề lớn, bạn nên luôn luôn sử dụng hàm băm an toàn. Có những cuộc tấn công rất thông minh có thể được thực hiện bằng cách buộc các va chạm trong một hàm băm. Nếu bạn sử dụng thứ gì đó mạnh mẽ ngay từ đầu, bạn sẽ tự bảo vệ mình trước những thứ này.

Không sử dụng MD5 hoặc SHA-1 trong các thiết kế mới. Hầu hết các nhà mật mã học, bao gồm tôi, sẽ xem xét chúng bị hỏng. Nguồn gốc của điểm yếu trong cả hai thiết kế này là thuộc tính thứ hai, mà tôi đã nêu ở trên, không giữ cho các công trình này. Nếu kẻ tấn công có thể tạo ra hai tin nhắn, m và m ', cả hai đều băm đến cùng một giá trị, chúng có thể sử dụng những tin nhắn này để chống lại bạn. SHA-1 và MD5 cũng bị tấn công mở rộng tin nhắn, có thể làm suy yếu nghiêm trọng ứng dụng của bạn nếu bạn không cẩn thận.

Một hàm băm hiện đại hơn như Whirpool là một lựa chọn tốt hơn. Nó không bị các cuộc tấn công mở rộng tin nhắn này và sử dụng toán học giống như AES sử dụng để chứng minh bảo mật chống lại một loạt các cuộc tấn công.

Mong rằng sẽ giúp!


1
Tôi nghĩ rằng khuyến nghị của hàm băm mật mã là một lời khuyên thực sự tồi trong trường hợp này.
Slava

@Slava: Tại sao? Lý do của bạn để nói "hàm băm mật mã là một lời khuyên thực sự tồi trong trường hợp này là gì?" Tại sao nó là lời khuyên tồi? Những bất lợi tương đối làm cho nó như vậy là gì?
Hãy để tôi nói về nó

2
@Mowzer vì một hàm băm được sử dụng trong bản đồ băm nên nhanh và nhẹ (giả sử nó vẫn cung cấp hàm băm tốt), băm mật mã rõ ràng là người giúp việc phải trả giá đắt để ngăn chặn tấn công vũ phu.
Slava

1

Những gì bạn đang nói ở đây là bạn muốn có một cái sử dụng có khả năng chống va chạm. Hãy thử sử dụng SHA-2. Hoặc thử sử dụng mật mã khối (tốt) trong chức năng nén một chiều (chưa từng thử trước đó), như AES ở chế độ Miyaguchi-Preenel. Vấn đề với điều đó là bạn cần:

1) có IV. Hãy thử sử dụng 256 bit đầu tiên của các phần phân số của hằng số Khinchin hoặc một cái gì đó tương tự. 2) có sơ đồ đệm. Dễ dàng. Barrow nó từ một hàm băm như MD5 hoặc SHA-3 (Keccak [phát âm là 'ket-chak']). Nếu bạn không quan tâm đến bảo mật (một vài người khác nói điều này), hãy xem FNV hoặc lookup2 của Bob Jenkins (thực sự tôi là người đầu tiên giới thiệu lookup2) Cũng thử MurmurHash, hãy nhanh chóng (kiểm tra điều này: .16 cpb ).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.