고유성과 속도에 가장 적합한 해싱 알고리즘은 무엇입니까? 예 (좋은) 사용에는 해시 사전이 포함됩니다.
SHA-256 과 같은 것이 있다는 것을 알고 있지만 이러한 알고리즘은 가 안전하도록 설계되었습니다. 이는 일반적으로 알고리즘보다 느리다는 것을 의미합니다. 덜 고유 합니다. 나는 빠르도록 설계된 해시 알고리즘을 원하지만 충돌을 피하기 위해 상당히 독특합니다.
코멘트
- 어떤 목적, 보안 또는 기타?
- @Orbling, 해시 사전 구현 용. 따라서 충돌은 최소한으로 유지해야하지만 보안 목적이 전혀 없습니다.
- 해시 테이블에서 최소한 일부 충돌을 예상해야합니다. 그렇지 않으면 상대적으로 적은 수의 키도 처리 할 수 있으려면 테이블이 엄청나게 커야합니다 …
- 좋은 소식입니다! Murmur보다 두 배 빠른 ‘의 Yann Collet ‘의 xxHash (크리에이터 또는 LZ4)도 확인할 수 있습니까? 홈페이지 : code.google.com/p/xxhash 추가 정보 : fastcompression.blogspot.fr/2012/ 04 / …
- @zvrba 알고리즘에 따라 다릅니다. bcrypt는 느리게 설계되었습니다.
Answer
속도와 충돌 횟수를 측정하는 몇 가지 다른 알고리즘을 테스트했습니다. .
다음 세 가지 키 세트를 사용했습니다.
- 216,553 개의 영어 단어 목록 🕗 보관 (소문자)
- 숫자
"1"
에서"216553"
(우편 번호를 생각하고 불량한 해시가 msn.com을 다운시킨 방법 🕗 보관 ) - 216,553 ” 임의 “(예 : 유형 4 uuid ) GUID
각 말뭉치에 대한 충돌 수 및 해싱에 소요 된 평균 시간 기록되었습니다.
테스트 :
- DJB2
- DJB2a (
+
di가 아닌xor
를 사용하는 변형) v>) - FNV-1 (32 비트)
- FNV-1a (32 비트)
- SDBM
- CRC32
- Murmur2 (32 비트)
- SuperFastHash
결과
각 결과에는 평균 해시 시간과 충돌 횟수가 포함됩니다.
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
참고 :
- LoseLose 알고리즘 (해시 = 해시 + 문자)은 진정으로 끔찍합니다 입니다. 모든 것이 동일한 1,375 개의 버킷에 충돌합니다.
- SuperFastHash는 빠르며 사물이 꽤 흩어져있는 것처럼 보입니다. 내 선하로 숫자 충돌. 나는 이것을 포팅 한 사람이 뭔가 잘못 했길 바라고 있습니다. 꽤 나쁩니다.
- CRC32는 꽤 좋은 em>. 느리고 1k 조회 테이블
충돌이 실제로 발생합니까?
예. 나는 해시 충돌이 실제로 발생하는지 확인하기 위해 테스트 프로그램을 작성하기 시작했습니다.실제로 발생합니다.
FNV-1 충돌
-
creamwove
가quists
FNV와 충돌합니다. -1a 충돌
-
costarring
가liquid
-
declinate
가macallums
-
altarage
는zinke
-
altarages
는zinkes
와 충돌합니다.
와 충돌합니다.
와 충돌합니다.
Murmur2 충돌
-
cataract
가periti
와 충돌 -
roquette
가 -
shawl
가stormbound
-
dowlases
가tramontane
li와 충돌합니다. > -
cricketings
가twanger
-
longans
가 충돌합니다.whigs
와 충돌합니다.
DJB2 충돌
-
hetairas
가mentioner
- 는
neurospora
-
depravement
는serafins
-
stylist
가subgenera
-
joyful
는synaphea
-
redescribed
는urites
-
dram
가vivency
와 충돌합니다.
와 충돌합니다.
DJB2a 충돌
-
haggadot
가 -
adorablenesses
rentability
-
playwright
와 충돌snush
li와 충돌 > -
playwrighting
가snushing
-
treponematoses
가 충돌합니다.waterbeds
와 충돌합니다.
CRC32 충돌
-
codding
가gnu
- 가
schlager
SuperFastHash 충돌
-
dahabiah
가drapability
-
encharm
는enclave
-
grahams
는gramary
- … 79 개 충돌 자르기 …
-
night
가 - 가
vigils
와 충돌합니다. -
finks
가vinic
와 충돌합니다.
무작위 화
다른 주관적인 척도는 해시가 얼마나 무작위로 분포되어 있는지입니다. 결과 HashTables를 매핑하면 데이터가 얼마나 균등하게 분산되는지 알 수 있습니다. 모든 해시 함수는 테이블을 선형으로 매핑 할 때 좋은 분포를 보여줍니다.
또는 Hilbert지도 ( XKCD는 항상 관련이 있습니다 ) :
숫자 문자열을 해싱하는 경우 제외 ("1"
, "2"
, …, "216553"
) (예 : 우편 번호 ), 패턴이 시작되는 위치 대부분의 해싱 알고리즘에서 등장 :
SDBM :
DJB2a :
FNV-1 :
FNV-1a , 나에게는 여전히 무작위로 보입니다.
사실, Murmur2 는 Numbers
FNV-1a
:
FNV-1a
“숫자”지도를 보면 생각 미묘한 수직 패턴이 보입니다. Murmur를 사용하면 패턴이 전혀 보이지 않습니다. 어떻게 생각해?
추가 *
는 임의성이 얼마나 나쁜지를 나타냅니다. FNV-1a
가 최고이고 DJB2x
최악의 경우 :
Murmur2: . FNV-1a: . FNV-1: ▪ DJB2: ▪▪ DJB2a: ▪▪ SDBM: ▪▪▪ SuperFastHash: . CRC: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ Loselose: ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪ ▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪▪
저는 원래 충돌에 대해 걱정 해야하는지 결정하기 위해이 프로그램을 작성했습니다. 그렇습니다.
그런 다음 해시 함수가 충분히 무작위인지 확인했습니다.
FNV-1a 알고리즘
FNV1 해시는 다음과 같은 변형으로 제공됩니다. 32, 64, 128, 256, 512 및 1024 비트 해시를 반환합니다.
FNV-1a 알고리즘 은 다음과 같습니다.
hash = FNV_offset_basis for each octetOfData to be hashed hash = hash xor octetOfData hash = hash * FNV_prime return hash
상수 FNV_offset_basis
및 FNV_prime
가 원하는 반환 해시 크기에 따라 달라지는 경우 :
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
자세한 내용은 기본 FNV 페이지 를 참조하세요.
모든 결과는 32 비트 변형입니다.
FNV-1이 FNV-1a보다 낫습니까?
아니요. FNV-1a가 더 좋습니다. 영어 단어 corpus를 사용할 때 FNV-1a와 더 많은 충돌이있었습니다.
Hash Word Collisions ====== =============== FNV-1 1 FNV-1a 4
이제 소문자와 대문자를 비교하세요.
Hash lowercase word Collisions UPPERCASE word collisions ====== ========================= ========================= FNV-1 1 9 FNV-1a 4 11
이 경우 FNV-1a는 FN-1보다” “400 %” 더 나쁘지 않고 단지 20 % 더 나쁩니다.
나는 더 중요한 점은 충돌과 관련하여 두 가지 알고리즘 클래스가 있다는 것입니다.
- 충돌 드문 : FNV-1, FNV-1a, DJB2, DJB2a, SDBM
- 일반적인 충돌 : SuperFastHash, Loselose
그런 다음 해시가 얼마나 균등하게 분산되는지가 있습니다.
- 뛰어난 배포 : Murmur2, FNV-1a, SuperFastHas
- 뛰어난 배포 : FNV-1
- 좋은 배포 : SDBM, DJB2, DJB2a
-
끔찍한 배포 : Loselose
업데이트
중얼 거리나요? 물론입니다.
업데이트
@whatshisname은 CRC32 의 성능을 궁금해하고 테이블에 숫자를 추가했습니다.
CRC32 꽤 좋습니다 . 충돌은 적지 만 느리고 1k 조회 테이블의 오버 헤드가 발생합니다.
CRC 배포에 대한 모든 잘못된 정보를 캡처합니다. 내 잘못입니다.
Up 오늘까지 저는 FNV-1a를 사실상 해시 테이블 해싱 알고리즘으로 사용하려고했습니다. 하지만 지금은 Murmur2로 전환합니다.
- 더 빠르게
- 모든 입력 클래스의 무작위 화 향상
그리고 정말 제가 찾은 SuperFastHash
알고리즘에 문제가 있기를 바랍니다. ; 인기가있는만큼 좋지 않습니다.
업데이트 : Google의 MurmurHash3 홈페이지 :
(1)-SuperFastHash는 충돌 속성이 매우 낮습니다. 다른 곳에서 문서화되었습니다.
그래서 나 뿐만이 아니라고 생각합니다.
업데이트 : Murmur
가 다른 것보다 빠른 이유를 깨달았습니다. MurmurHash2는 한 번에 4 바이트로 작동합니다. 대부분의 알고리즘은 바이트 단위 입니다.
for each octet in Key AddTheOctetToTheHash
이는 키가 길어질수록 Murmur가 빛을 발할 수 있음을 의미합니다.
업데이트
GUID는 무작위가 아닌 고유하도록 설계되었습니다.
Raymond Chen이 적시에 게시 한 게시물은 “무작위” GUID를 사용하기위한 것이 아니라는 사실을 반복합니다. 무작위성. 이들 또는 그 하위 집합은 해시 키로 적합하지 않습니다.
버전 4 GUID 알고리즘조차도 예측 불가능하다는 보장은 없습니다. 난수 생성기의 품질을 지정하지 않습니다. GUID에 대한 Wikipedia 기사에는 생성기가 암호화 방식이 아니기 때문에 난수 생성기 상태에 대한 지식을 기반으로 미래 및 이전 GUID를 예측할 수 있음을 제시하는 기본 연구가 포함되어 있습니다. 강한.
랜덤은 충돌 방지와 동일하지 않습니다. 그렇기 때문에 “무작위”guid의 일부 하위 집합을 취하여 자신의 “해싱”알고리즘을 발명하는 것은 실수입니다.
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); }
참고 : “무작위”이기 때문에 “무작위 GUID”를 따옴표로 묶었습니다. GUID의 변형입니다.보다 정확한 설명은 Type 4 UUID
입니다. 그러나 유형 4 또는 유형 1, 3 및 5가 무엇인지 아무도 모릅니다. 따라서 “무작위”라고 부르는 것이 더 쉽습니다. “GUID.
모든 영어 단어 미러
- https://web.archive.org/web/20070221060514/http://www.sitopreferito.it/html/all_english_words.html
- https://drive.google.com/file/d/0B3BLwu7Vb2U-dEw1VkUxc3U4SG8/view?usp=sharing
댓글
- SHA가 어떻게 비교되는지 보는 것은 정말 흥미로울 것입니다. ‘ 여기에서는 해싱 알고리즘에 적합한 후보이지만 암호화 해시가 속도 알고리즘을 위해 만들어진 해시와 어떻게 비교되는지 보면 정말 흥미로울 것입니다.
- 남의 새로운 해시 Yann Collet의 ‘ xxHash ‘의 e가 최근 라운드를 진행했습니다. 저는 ‘ 항상 새로운 해시를 의심합니다. 비교해 보면 흥미로울 것입니다 (‘ 사람들이 임의의 해시를 제안하는 것에 지치지 않는다면 ‘ 추가 예정 …)
- 그렇습니다. xxHash 프로젝트 페이지에서 발표 한 성능 수치는 인상적이며 사실이 아닐 수도 있습니다. 최소한 ‘는 오픈 소스 프로젝트입니다. code.google.com/p/xxhash
- 안녕하세요, 제 델파이의 SuperFastHash 구현이 맞습니다. 구현할 때 구현 결과와 참조 구현을 비교하기 위해 C와 Delphi로 테스트 세트를 만들었습니다. 차이가 없습니다. 그래서 당신이 보는 것은 해시의 실제 나쁜 점입니다 … (그래서 MurmurHash 구현도 게시했습니다 : landman-code.blogspot.nl/2009/02/ … )
- 포스터가 이것이 단지 멋진 답변이 아니라는 것을 알고 있습니까? 이것이 바로 세상입니다. ‘ 주제에 대한 사실상의 참조 리소스? 해시를 처리해야 할 때마다 내 문제를 매우 빠르고 신뢰할 수있게 해결하여 ‘ 다른 것이 필요하지 않습니다.
Answer
변경되지 않는 사전에서 해시 맵을 생성하려는 경우 완벽한 해싱을 고려할 수 있습니다. https://en.wikipedia.org/wiki/Perfect_hash_function -해시 함수 및 해시 테이블을 생성하는 동안 주어진 데이터 세트에 대해 충돌이 없음을 보장 할 수 있습니다.
댓글
- 여기 ‘ (최소) 완벽한 해싱에 대한 자세한 정보 burtleburtle.net/bob/hash/perfect.html 은 성능 데이터를 포함하지만 ‘ 최신 프로세서 등을 사용하지 않습니다.
- ‘ 매우 분명하지만 충돌이 발생하지 않도록하려면 키의 크기가 값과 같아야합니다. 알고리즘이 사용할 수있는 값에 대한 제약이 있습니다.
- @ devios1 귀하의 진술은 의미가 없습니다. 첫째, 해시 테이블의 값은 완전하든 아니든 키와 무관합니다. 둘째, 완벽한 해시 테이블은 모든 인덱스가 고유하도록 만들어진 함수의 결과로 인덱싱 된 값의 선형 배열 일뿐입니다.
- @MarcusJ 퍼펙트 해싱은 일반적으로 100 미만으로 사용됩니다. 키,하지만 cmph.sourceforge.net 을 살펴보십시오 … 여전히 범위에 훨씬 못 미칩니다.
- @DavidCary 링크는 귀하의 주장을 뒷받침합니다. O (1)을 ” 충돌 없음 “과 혼동했을 수 있지만, 그렇지 않습니다 ‘ 전혀 같은 일이 아닙니다. 물론 완벽한 해싱은 충돌이 없음을 보장하지만 모든 키를 미리 알고 있고 상대적으로 적은 수의 키가 있어야합니다. (하지만 위의 cmph 링크를 참조하십시오.)
답변
여기 는 해시 함수 목록이지만 짧은 버전은 다음과 같습니다.
좋은 해시 함수를 원할 경우 기다릴 수없는
djb2
는 내가 아는 최고의 문자열 해시 함수 중 하나입니다. 다양한 키 및 테이블 크기 세트에서 탁월한 배포 및 속도를 제공합니다.
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; }
댓글
- 사실 djb2는 대부분의 간단한 해시 함수처럼 0에 민감하므로 이러한 해시를 쉽게 깨뜨릴 수 있습니다.편견이 너무 많고 충돌이 많고 분포가 잘못되어 대부분의 smhasher 품질 테스트에서 중단됩니다. github.com/rurban/smhasher/blob/master/doc/bernstein 그의 cdb 데이터베이스에서 사용하지만 ‘ 공개 액세스와 함께 사용하지 않습니다.
- DJB는 성능 및 배포 측면에서 상당히 나쁩니다. 저는 ‘ 오늘은 사용하지 않을 것입니다.
- @ConradMeyer I ‘ 내기, DJB는 이 질문 에서와 마찬가지로 3의 요인이었고, ‘ 아마 가장 유용한 알고리즘을 능가했습니다. 배포에 대해서는 동의합니다. 두 글자 문자열에 대해서도 충돌을 일으키는 해시는 ‘ 정말 좋지 않습니다.
- 여러분, 의심 스럽습니다.
djb2
가 나쁘다고 말하고 있지만 허용 된 답변의 테스트 결과는 좋은 것으로 나타났습니다. - 적어도 충돌을 덜 일으키는 합리적인 소수를 사용할 수 있습니다. 33 대신. stackoverflow.com/a/2816747/21499
답변
CityHash by Google은 귀하가 찾고있는 알고리즘입니다. 암호화에는 좋지 않지만 고유 한 해시 생성에는 좋습니다.
자세한 내용은 블로그 와 코드는 여기에서 사용할 수 있습니다 .
CityHash는 C ++로 작성되었습니다. 일반 C 포트 도 있습니다.
모든 CityHash 함수는 64 비트 프로세서에 맞게 조정되었습니다. 즉, 32 비트 코드에서 실행됩니다 (SSE4.2를 사용하는 새 코드 제외). 하지만 그다지 빠르지는 않을 것입니다. Murmur 또는 다른 것을 32 비트 코드로 사용할 수 있습니다.
댓글
- CityHash가 ” City Sushi와 비슷하게 발음됩니까? ”
- SipHash도보세요. MurmurHash / CityHash / etc를 대체하기위한 것입니다. : 131002.net/siphash
- 또한 FarmHash도 참조하세요. CitHash의 후속 제품입니다. code.google.com/p/farmhash
- xxHash 는 CityHash보다 5 배 빠르다고 주장합니다.
-
plain C port
링크가 끊어졌습니다.
답변
파일을 해싱 할 때 다른 해싱 알고리즘의 짧은 속도 비교를 그렸습니다.
모든 파일이 tmpfs에 저장 되었기 때문에 개별 플롯은 읽기 방법에서 약간만 다르며 여기서 무시할 수 있습니다. 따라서 궁금한 점이 있다면 벤치 마크는 IO- 바운드가 아닙니다.
알고리즘에는 다음이 포함됩니다. SpookyHash, CityHash, Murmur3, MD5, SHA{1,256,512}
.
결론 :
- Murmur3, Cityhash 및 Spooky와 같은 비 암호화 해시 함수는 매우 가깝습니다. Cityhash는 CPU에없는 SSE 4.2s
CRC
명령을 사용하는 CPU에서 더 빠를 수 있습니다. SpookyHash는 제 경우에는 항상 CityHash보다 약간 앞서있었습니다. - MD5는 암호화 해시 함수를 사용할 때 좋은 절충안 인 것처럼 보이지만 SHA256은 충돌 취약성
- 모든 알고리즘의 복잡성은 선형 적입니다. 이는 블록 단위로 작동하기 때문에 놀라운 일이 아닙니다. (읽는 방법이 차이가 나는지 확인하고 싶었 기 때문에 가장 오른쪽 값만 비교할 수 있습니다.)
- SHA256은 SHA512보다 느 렸습니다.
- 나는 무작위성을 조사하지 않았습니다. 해시 함수. 그러나 여기 는 Ian Boyds 답변 에서 누락 된 해시 함수의 좋은 비교입니다. 이것은 CityHash가 코너 케이스에 몇 가지 문제가 있음을 나타냅니다.
플롯에 사용 된 소스 :
- https://github.com/sahib/rmlint/tree/gh-pages/plots (추악한 코드로 인해 죄송합니다)
댓글
- 선형 스케일 그래프는 그것이 플로팅하고있는 양을 나타내는 y 축 레이블을 잘라냅니다. 아마 로그 스케일과 같은 ” 초 단위 시간 ” 일 것입니다. 수정할 가치가있는 ‘
답변
SHA-256과 같은 것이 있다는 것을 알고 있지만 이러한 알고리즘은 설계됨 는 보안 이어야합니다. 이는 일반적으로 고유 덜한 알고리즘보다 느리다는 것을 의미합니다.
암호화 해시 함수가 더 고유하다는 가정은 잘못되었으며 실제로 실제로는 종종 거꾸로 표시 될 수 있습니다. 사실 :
- 암호화 해시 함수는 이상적으로는 무작위와 구별 할 수 있어야합니다. ;
- 하지만 비 암호화 해시 함수의 경우 가능성이 높은 입력과 호의적으로 상호 작용하는 것이 바람직합니다 .
비 암호화 해시 함수의 충돌이 적을 수 있음을 의미합니다. “좋은”데이터 세트에 대한 암호화 데이터 세트 — 설계된 데이터 세트입니다.
우리는 실제로 Ian Boyd의 답변과 약간의 수학 : 생일 문제 . [1, d]
집합에서 무작위로 n
정수를 선택하는 경우 예상 충돌 쌍 수에 대한 공식은 다음과 같습니다 (Wikipedia에서 가져옴).
n - d + d * ((d - 1) / d)^n
플러깅 n
= 216,553 및 d
= 2 ^ 32 우리는 약 5.5 예상 충돌 을 얻습니다. Ian s 테스트는 대부분 해당 지역 주변의 결과를 보여 주지만 한 가지 극적인 예외를 제외하고는 대부분의 함수가 제로 충돌 을 얻었습니다. 연속적인 숫자 테스트. 무작위로 216,553 개의 32 비트 숫자를 선택하고 충돌이 0이 될 확률은 약 0.43 %입니다. 이는 단지 하나의 함수에 대한 것입니다. 여기서는 0을 가진 5 개의 고유 한 해시 함수 계열 이 있습니다. 충돌!
여기에서 우리가보고있는 것은 Ian이 테스트 한 해시가 연속 된 숫자 데이터 세트와 우호적으로 상호 작용한다는 것입니다. 즉, 그들은 최소하게 분산되고 있습니다. 입력 은 이상적인 암호화 해시 함수보다 더 광범위합니다. (참고 : 이것은 숫자 데이터 세트에서 FNV-1a 및 MurmurHash2가 “무작위로 보인다”는 Ian의 그래픽 평가를 자신의 데이터에서 반박 할 수 있음을 의미합니다. 해당 크기의 데이터 세트에서 충돌이 전혀 발생하지 않는 경우 둘 다 해시 함수는 놀랍도록 무작위가 아닙니다!)
이것은 해시 함수의 많은 사용에 바람직한 동작이기 때문에 놀라운 일이 아닙니다. 예를 들어 해시 테이블 키는 종종 매우 유사합니다. Ian의 답변은 MSN이 한때 ZIP 코드 해시 테이블에서 겪었던 문제 를 언급합니다. 이것은 가능성이 높은 입력에 대한 충돌 회피가 임의의 동작보다 우세한 용도입니다.
여기에서 또 다른 유익한 비교는 CRC와 암호화 해시 함수 간의 설계 목표의 대조입니다.
- CRC는 잡음이 많은 통신 채널로 인해 발생하는 오류 를 포착하도록 설계되었습니다. 적은 수의 비트 플립;
- Crypto 해시는 악의적 인 공격자가 만든 수정 을 포착하도록 설계되었습니다. 제한된 계산 리소스가 할당되지만 임의로 훨씬 영리합니다.
CRC의 경우 최소한의 다른 입력에서 무작위보다 충돌이 적은 것이 다시 좋습니다 . 암호화 해시를 사용하면 안됩니다!
답변
SHA 알고리즘 (SHA-256 포함)은 가 빠르게 설계됨 .
사실 때때로 속도가 문제가 될 수 있습니다. 특히 암호에서 파생 된 토큰을 저장하는 일반적인 기술은 표준 고속 해시 알고리즘을 10,000 번 실행하는 것입니다 (… 암호 해시의 해시 해시 저장).
#!/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
출력 :
Rehearsal ------------------------------------ 1.480000 0.000000 1.480000 ( 1.391229) --------------------------- total: 1.480000sec user system total real 1.400000 0.000000 1.400000 ( 1.382016)
댓글
- ‘는 암호화 해싱 알고리즘 에 대해 상대적으로 빠르고 확실합니다. 하지만 OP는 값을 해시 테이블에 저장하기를 원하며 ‘ 암호화 해시 함수가 실제로 적합하다고 생각하지 않습니다.
- 질문이 제기되었습니다. (접선 적으로, 이제 나타납니다) 암호화 해시 함수의 주제입니다. ‘가 제가 대응하는 부분입니다.
- 사람들이 ” 특히 , 암호에서 파생 된 토큰을 저장하는 일반적인 기술은 표준 고속 해시 알고리즘을 10,000 번 실행하는 것입니다 “-일반적이지만 ‘ 그냥 멍청 하군. 이러한 시나리오를 위해 설계된 알고리즘이 있습니다 (예 :
bcrypt
). 올바른 도구를 사용하세요. - 암호화 해시는 높은 처리량을 갖도록 설계되었지만 이는 종종 높은 설정, 분해,
.rodata
및 / 또는 상태 비용이 있음을 의미합니다. .해시 테이블에 대한 알고리즘을 원할 때 일반적으로 매우 짧은 키와 많은 키가 있지만 암호화에 대한 추가 보장은 필요하지 않습니다. 저는 한 번에 하나씩 조정 된 Jenkins를 사용합니다. - @ChrisMorgan : 암호 학적으로 안전한 해시를 사용하는 대신 HashTable DoS는 해시 무작위 화를 사용하여 훨씬 더 효율적으로 해결할 수 있습니다. 프로그램 또는 모든 해시 테이블에서 데이터가 매번 동일한 버킷으로 그룹화되지 않도록 ‘합니다.
답변
SipHash 를 사용합니다. 많은 바람직한 속성이 있습니다.
-
빠름. 최적화 된 구현은 바이트 당 약 1주기가 걸립니다.
-
보안. SipHash는 강력한 PRF (의사 난수 함수)입니다. 즉, 128 비트 비밀 키를 알지 못하는 경우 임의의 함수와 구별 할 수 없습니다. 따라서 :
-
해시 테이블 프로브가 충돌로 인해 선형 시간이되는 것에 대해 걱정할 필요가 없습니다. SipHash를 사용하면 입력에 관계없이 평균적으로 평균적인 성능을 얻을 수 있음을 알 수 있습니다.
-
해시 기반 서비스 거부 공격에 대한 내성.
-
SipHash (특히 128 비트 출력 버전)를 MAC으로 사용할 수 있습니다. (메시지 인증 코드). 메시지와 SipHash 태그를 수신하고 그 태그가 비밀 키로 SipHash를 실행 한 것과 동일하다면 해시를 만든 사람도 비밀 키를 소유하고 있다는 것을 알 수 있습니다. 해시는 이후 변경되었습니다.
-
댓글
- Isn ‘ 보안이 필요하지 않으면 SipHash가 과도하게 사용되지 않습니까? 영광스러운 해시 시드 인 128 비트 키가 필요합니다. MurmurHash3에는 128 비트 출력이 있고 SipHash에는 64 비트 출력 만 있습니다. 분명히 다이제스트가 클수록 충돌 가능성이 낮습니다.
- @bryc 차이점은 SipHash가 악의적 인 입력에도 계속 잘 작동한다는 것입니다. SipHash를 기반으로하는 해시 테이블은 잠재적으로 적대적인 소스의 데이터에 사용할 수 있으며 해시 함수의 세부 사항에 매우 민감한 선형 프로빙과 같은 알고리즘을 사용할 수 있습니다.
- Siphash (및 관련 최신 제품) 스타일 함수)는 보안을위한 기본 선택입니다. 성능면에서 xxhash는 이길 수 없습니다. 인터넷에는 여기에있는 토론에서도 해싱에 대한 나쁜 조언이 많습니다. 무작위 또는 반 무작위 입력에서 좋은 성능은 의미가 없습니다. 실제 입력에서 최악의 성능은 무엇입니까? 악의적 인 입력의 결과는 무엇입니까? 해시 테이블은 결국 공격 벡터가됩니다.
답변
해시하는 데이터에 따라 다릅니다. 일부 해싱은 텍스트와 같은 특정 데이터에서 더 잘 작동합니다. 일부 해싱 알고리즘은 특정 데이터에 적합하도록 특별히 설계되었습니다.
Paul Hsieh는 한 때 빠른 해시 를 만들었습니다. 그는 소스 코드와 설명을 나열합니다. 그러나 이미 구타당했습니다. 🙂
답변
Java는 this 단순 곱하기를 사용합니다. -and-add 알고리즘 :
String 객체의 해시 코드는 다음과 같이 계산됩니다.
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
정수 산술 사용. 여기서
s[i]
는 문자열의 i 번째 문자입니다.n
는 문자열의 길이이고^
는 지수를 나타냅니다. (빈 문자열의 해시 값은 0입니다.)
아마 훨씬 더 나은 것이있을 수 있지만 이것은 상당히 널리 퍼져 있고 좋은 것 같습니다. 속도와 고유성 사이의 균형.
댓글
- 나는 ‘ 정확히 동일한 여기에 사용 된 하나는 ‘ 여전히 상대적으로 충돌을 일으키기 쉽기 때문입니다. ‘ 확실히 끔찍하지는 않지만 훨씬 더 나은 것이 있습니다. 그리고 ‘ Java와 호환되어야하는 중요한 이유가 없다면 선택하지 않아야 합니다.
- 그래도 이것을 선택한다면 어떤 이유로 해싱 방법으로, 적어도 92821과 같은 더 나은 소수를 곱셈기로 사용할 수 있습니다. 그것은 충돌을 많이 줄입니다. stackoverflow.com/a/2816747/21499
- 대신 FNV1a를 사용할 수도 있습니다. 또한 ‘는 단순한 곱셈 기반 해시이지만 더 큰 배율을 사용하여 해시를 더 잘 분산시킵니다.
- 당신은 ‘
s[0]*31^3 + s[1]*31^2 + s[2]*31 + s[3]
를 원하지 않습니다. 거듭 제곱 연산자 (^)를 피하고 다음과 같이하십시오.((s[0]*31 + s[1])*31 + s[2])*31 + s[3]
. - @LeopoldoSanczyk 예, 코드에서는 반복적으로 수행되어야하며 닫힌 수식으로 이해하기가 더 쉬웠습니다.
답변
먼저 자신 만의 해싱을 구현해야하는 이유는 무엇입니까? 대부분의 작업에서 표준 라이브러리의 데이터 구조를 사용하여 좋은 결과를 얻어야합니다 (사용 가능한 구현이 있다고 가정).
실제 해싱 알고리즘에 관한 한 제가 개인적으로 좋아하는 것은 FNV입니다. 1
다음은 C에서 32 비트 버전의 구현 예입니다.
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; }
코멘트
- FNV-1a 변형은 임의성이 약간 더 좋습니다.
*
및^
:h = (h * 16777619) ^ p[i]
== >h = (h ^ p[i]) * 16777619