Javascript의 문자열에서 해시 생성


585

문자열을 해시 형태로 변환해야합니다. 이것이 JavaScript에서 가능합니까?

서버 측 언어를 사용하지 않으므로 그렇게 할 수 없습니다.


7
MD5는 안전하지 않으므로 그 것을 찾지 마십시오.
— henrikstroem

166
@henrikstroem 해싱하는 내용에 따라 다릅니다. md5를 사용하여 비보안 목적으로 해시를 만드는 것은 아무 문제가 없습니다.
— 브래드 코흐

7
@BradKoch 당신이하고있는 것에 달려있다; 보안 목적으로 md5를 사용하는 데 아무런 문제가 없습니다. 암호를 해싱하는 더 좋은 방법이 있지만 md5는 URL 서명과 같은 작업에 적합합니다.
— Paul Ferrett

81
MD5가 여기 주석에서 비판되는 동안 거의 모든 답변이 훨씬 나쁜 해시 알고리즘을 권장하고 많은 공감을 얻습니다.
— domen

38
MD5를 사용하여 다운로드가 온전한 지 확인하는 것이 마술로 모든 동료에게 암호를 이메일로 보내지는 않습니다.
— James M. Lay

답변:


788
Object.defineProperty(String.prototype, 'hashCode', {
  value: function() {
    var hash = 0, i, chr;
    for (i = 0; i < this.length; i++) {
      chr   = this.charCodeAt(i);
      hash  = ((hash << 5) - hash) + chr;
      hash |= 0; // Convert to 32bit integer
    }
    return hash;
  }
});

출처 : http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/


22
이것은 Java에서 사용 된 것과 동일합니다. 은 hash << 5 - hash과 동일 hash * 31 + char훨씬 빠르지 만. 너무 빠르기 때문에 좋으며 31은 소수입니다. 거기에서 승리하십시오.
— corsiKa

41
jsperf ( jsperf.com/hashing-strings ) 에서 몇 가지 테스트를 수행 했으며 비트 함수는 실제로 숫자 기반 함수보다 느립니다.
— skerit 2016 년

17
@PeterAronZentai 왜 "사용 불가능"입니까? 숫자 기반 코드 (hash * 31) + char로 생성 된 출력 ((hash<<5)-hash)+char은 매우 긴 문자열 (100 만 자 이상을 포함하는 문자열로 테스트 한 경우)에서도 시프트 기반 코드로 생성 된 출력과 동일 하므로 용어로 "사용할 수 없음" 정확성. 숫자 기반 버전과 시프트 기반 버전 모두에서 복잡성은 O (n)이므로 복잡성 측면에서 "사용할 수 없습니다".
— TachyonVortex

13
누구나 출력의 고유성에 대해 언급 할 수 있습니까? 특히 길이가보다 작은 문자열에 대해서만이 해시를 사용 하는 경우 충돌이 발생하지 않는 n가장 큰 문자열은 무엇 n입니까?
— Don McCurdy

34
이것이 필요하거나 String 프로토 타입에 있어야하는 이유가 있습니까? 예를 들어 덜 효과적이고 효율적일까요? var hashCode = function hashCode (str) {etc...}? 그런 다음 hashCode("mystring")?
— rattray

146

편집하다

내 jsperf 테스트를 기반으로 허용되는 답변이 실제로 더 빠릅니다. http://jsperf.com/hashcodelordvlad

기발한

관심이 있다면 개선 된 (더 빠른) 버전이 reduce있습니다.이 기능 은 배열 기능이 없는 오래된 브라우저에서 실패 합니다.

hashCode = function(s){
  return s.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
}

한 줄 화살표 기능 버전 :

hashCode = s => s.split('').reduce((a,b)=>{a=((a<<5)-a)+b.charCodeAt(0);return a&a},0)

3
해시를 얻는 방법이 양수 일뿐입니까?
— Prosto Trader 2013

46
기묘한. 방금 테스트 한 결과 허용되는 답변보다 느립니다. jsperf.com/hashcodelordvlad
— lordvlad

113
좋은 사람 @lordvlad는 실제로 자신의 답변을 테스트 한 다음 속도가 느릴 때보 고합니다.
— mikemaccana

9
방금 깨달았습니다 : 내 버전은 문자열을 먼저 배열로 바꾸어 새 메모리를 할당하고 모든 문자를 복사해야하기 때문에 허용되는 답변이 더 빠르다는 것은 완벽합니다.
— lordvlad

5
[] .reduce.call (str, (p, c, i, a) => (p << 5)-p + a.charCodeAt (i), 0);
— Dizzy

108

참고 : 최상의 32 비트 해시라도 조만간 충돌 이 발생합니다.

해시 충돌 probablility은 다음과 같이 계산 될 수 1-e ^ (-k (k-1) / 2N로 aproximated, k ^ 2 / 2N ( 여기 참조 ). 이는 직감이 제안한 것보다 높을 수 있습니다
. 32 비트 해시 및 k = 10,000 항목을 가정하면 확률 1.2 %로 충돌이 발생합니다. 77,163 개의 샘플에서 확률은 50 %가됩니다! ( 계산기 ).
하단에 해결 방법을 제안합니다.

이 질문에 대한 답변으로 고유성과 속도에 가장 적합한 해싱 알고리즘은 무엇입니까? Ian Boyd는 심층 분석 결과를 올렸다 . 한마디로 (내가 해석 한대로), 그는 Murmur가 최고라는 결론에 도달 한 다음 FNV-1a를 따릅니다.
esmiralha가 제안한 Java의 String.hashCode () 알고리즘은 DJB2의 변형 인 것 같습니다.

  • FNV-1a는 DJB2보다 더 나은 분포를 가지고 있지만 느립니다.
  • DJB2는 FNV-1a보다 빠르지 만 더 많은 충돌을 일으키는 경향이 있습니다.
  • MurmurHash3는 DJB2 및 FNV-1a보다 낫고 빠릅니다 (그러나 최적화 된 구현에는 FNV 및 DJB2보다 더 많은 코드 줄이 필요함)

여기에 큰 입력 문자열 일부 벤치 마크 : http://jsperf.com/32-bit-hash
때 짧은 입력 문자열을 해시, DJ2B 및 FNV-1A에 비해 잡음의 성능 방울 : http://jsperf.com/32- 비트 해시 / 3

따라서 일반적으로 murmur3을 권장합니다.
JavaScript 구현에 대해서는 여기를 참조하십시오 : https://github.com/garycourt/murmurhash-js

입력 문자열이 짧고 분배 품질보다 성능이 더 중요한 경우, esmiralha의 승인 된 답변에서 제안한대로 DJB2를 사용하십시오.

품질과 작은 코드 크기가 속도보다 중요한 경우 FNV-1a 구현 ( 이 코드 기반 )을 사용합니다.

/**
 * Calculate a 32 bit FNV-1a hash
 * Found here: https://gist.github.com/vaiorabbit/5657561
 * Ref.: http://isthe.com/chongo/tech/comp/fnv/
 *
 * @param {string} str the input value
 * @param {boolean} [asString=false] set to true to return the hash value as 
 *     8-digit hex string instead of an integer
 * @param {integer} [seed] optionally pass the hash of the previous chunk
 * @returns {integer | string}
 */
function hashFnv32a(str, asString, seed) {
    /*jshint bitwise:false */
    var i, l,
        hval = (seed === undefined) ? 0x811c9dc5 : seed;

    for (i = 0, l = str.length; i < l; i++) {
        hval ^= str.charCodeAt(i);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }
    if( asString ){
        // Convert to 8 digit hex string
        return ("0000000" + (hval >>> 0).toString(16)).substr(-8);
    }
    return hval >>> 0;
}

충돌 확률 향상

여기 에 설명 된 대로이 트릭을 사용하여 해시 비트 크기를 확장 할 수 있습니다.

function hash64(str) {
    var h1 = hash32(str);  // returns 32 bit (as 8 byte hex string)
    return h1 + hash32(h1 + str);  // 64 bit (as 16 byte hex string)
}

조심해서 사용하고 너무 많이 기대하지 마십시오.


왜합니까 ("0000000" + (hval >>> 0).toString(16)).substr(-8);? 그것과 같지 (hval >>> 0).toString(16)않습니까?
— Manuel Meurer

3
결과적으로 해시의 길이가 항상 8자가되도록 선행 '0'을 추가하십시오. 출력물에서 읽고 인식하기가 쉽지만 제 개인적 의견입니다
— mar10

아 알았어. 작은 들어 hval, (hval >>> 0).toString(16)제로와 당신 때문에 패드가 미만 8 자 수 있습니다. 나는 (hval >>> 0).toString(16)항상 정확히 8 개의 문자열을 얻었 기 때문에 혼란 스러웠다 .
— Manuel Meurer

3
이 답변은 sooo가 훨씬 더 나은 분산 해시를 생성하기 때문에 좋아합니다. 여기에 제안 된 다른 함수는 결과 해시 값을 만듭니다. 예를 들어`hash ( "example1")-hash ( "example2") == 1 "인데, 이것은 훨씬 더 예측할 수 없습니다.
— GavinoGrifoni

1
"FNV-1a는 DJB2보다 더 나은 분포를 갖지만 느리다"에 대한 응답으로 ES6 Math.imul기능을 사용하여 구현할 때 FNV1a가 매우 빠를 수 있다고 합니다. 이것만으로도 최고의 벤치 마크가되며 결국 DJB2보다 더 나은 선택입니다.
— bryc

64

ES6 에서 허용 된 답변 을 기반으로 합니다. 작고 유지 관리가 가능하며 최신 브라우저에서 작동합니다.

function hashCode(str) {
  return str.split('').reduce((prevHash, currVal) =>
    (((prevHash << 5) - prevHash) + currVal.charCodeAt(0))|0, 0);
}

// Test
console.log("hashCode(\"Hello!\"): ", hashCode('Hello!'));

편집 (2019-11-04) :

한 줄 화살표 기능 버전 :

const hashCode = s => s.split('').reduce((a,b) => (((a << 5) - a) + b.charCodeAt(0))|0, 0)

// test
console.log(hashCode('Hello!'))


1
비 문자열이 매개 변수로 전달 될 때 str += ""발생하는 예외를 피하기 위해 해싱 전에 추가 한 공유 주셔서 감사합니다str.split is not a function
— BeetleJuice

4
그러나 다음 중 어느 것보다 훨씬 느리다 : https://jsperf.com/hashing-strings
— AndyO

또한 줄 바꿈을 제거하여 길이가 3 줄 밖에되지 않으면 가장 빠른 "레트로"솔루션이 실제로 더 작다는 것을 알았습니다.
— AndyO

2
이 방법으로 긍정적이지만 여전히 독특한 결과를 얻을 수 있습니까?
— DIDS

3
@deekshith 허용되는 답변은 hash |= 032 비트 int로 변환하는 데 사용 됩니다. 이 구현은 그렇지 않습니다. 이것이 버그입니까?
— Sukima

48

답변의 거의 절반은 Java 구현으로 String.hashCode, 고품질도 빠르지도 않습니다. 너무 특별하지는 않습니다. 각 캐릭터마다 31을 곱하면됩니다. 한 줄로 간단하고 효율적으로 구현할 수 있으며 다음과 같이 훨씬 빠릅니다 Math.imul.

hashCode=s=>{for(var i=0,h;i<s.length;i++)h=Math.imul(31,h)+s.charCodeAt(i)|0;return h}

그런데, better- 여기의 뭔가의 밖으로 cyrb53 , 단순하지만 고품질의 53 비트 해시입니다. 매우 빠르며 매우 우수한 해시 분포를 제공하며 모든 32 비트 해시에 비해 충돌 률이 상당히 낮습니다 .

const cyrb53 = function(str, seed = 0) {
    let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
    for (let i = 0, ch; i < str.length; i++) {
        ch = str.charCodeAt(i);
        h1 = Math.imul(h1 ^ ch, 2654435761);
        h2 = Math.imul(h2 ^ ch, 1597334677);
    }
    h1 = Math.imul(h1 ^ h1>>>16, 2246822507) ^ Math.imul(h2 ^ h2>>>13, 3266489909);
    h2 = Math.imul(h2 ^ h2>>>16, 2246822507) ^ Math.imul(h1 ^ h1>>>13, 3266489909);
    return 4294967296 * (2097151 & h2) + (h1>>>0);
};

잘 알려진 MurmurHash / xxHash 알고리즘과 유사 하게 곱셈과 Xorshift 의 조합을 사용 하여 해시를 생성하지만 철저하지는 않습니다. 결과적으로 JavaScript보다 빠르며 구현이 훨씬 간단합니다.

눈사태 (엄격하지 않음)를 달성합니다. 기본적으로 입력의 작은 변화가 출력에 큰 변화가있어 결과 해시가 무작위로 나타납니다.

0xc2ba782c97901 = cyrb53("a")
0xeda5bc254d2bf = cyrb53("b")
0xe64cc3b748385 = cyrb53("revenge")
0xd85148d13f93a = cyrb53("revenue")

동일한 입력의 대체 스트림에 시드를 제공 할 수도 있습니다.

0xee5e6598ccd5c = cyrb53("revenue", 1)
0x72e2831253862 = cyrb53("revenue", 2)
0x0de31708e6ab7 = cyrb53("revenue", 3)

기술적으로 64 비트 해시 (2 개의 상관되지 않은 32 비트 해시 병렬)이지만 JavaScript는 53 비트 정수로 제한됩니다. 필요한 경우 16 진 문자열 또는 배열의 리턴 라인을 변경하여 완전한 64 비트 출력을 계속 사용할 수 있습니다 .

16 진 문자열을 구성하면 성능이 중요한 상황에서 일괄 처리 속도가 크게 느려질 수 있습니다.

return (h2>>>0).toString(16).padStart(8,0)+(h1>>>0).toString(16).padStart(8,0);
// or
return [h2>>>0, h1>>>0];

그리고 재미로, FNV 또는 DJB2보다 높은 품질의 89 개 문자 로 된 최소 32 비트 해시가 있습니다 .

TSH=s=>{for(var i=0,h=9;i<s.length;)h=Math.imul(h^s.charCodeAt(i++),9**9);return h^h>>>9}

4
와우, 이것은 짧은 (또는 비슷한) 입력에 대해 일반적인 * 31보다 훨씬 낫습니다. :)
— lapo

2
어디에서 ch초기화 되나요?
— hellowill89

3
@ hellowill89 woops, 나는 그것을 선언하는 것을 잊었고 세계적인 범위로 피가 흘렀다.
— 고침

IE 11에서 실패 : 개체가 속성 또는 메서드를 지원하지 않습니다 'imul'.
— BachT

2
@BachT 폴리 필 또는 전체 ES6 심을 사용할 수 있습니다 . 그러나 IE11은 2009 년에 업데이트없이 비극적으로 중단되었습니다.
— bryc

28

그것이 누군가에게 도움이된다면, 상위 2 개의 답변을 구식 브라우저 허용 버전으로 결합 reduce했습니다.

/**
 * @see http://stackoverflow.com/q/7616461/940217
 * @return {number}
 */
String.prototype.hashCode = function(){
    if (Array.prototype.reduce){
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);              
    } 
    var hash = 0;
    if (this.length === 0) return hash;
    for (var i = 0; i < this.length; i++) {
        var character  = this.charCodeAt(i);
        hash  = ((hash<<5)-hash)+character;
        hash = hash & hash; // Convert to 32bit integer
    }
    return hash;
}

사용법은 다음과 같습니다.

var hash = "some string to be hashed".hashCode();

이 코드를 최적화하여 모든 브라우저에서 더 빠르게 실행하는 방법 String.prototype.hashCode = function(){ var hash = 5381; if (this.length === 0) return hash; for (var i = 0; i < this.length; i++) { var character = this.charCodeAt(i); hash = ((hash<<5)+hash)^character; // Convert to 32bit integer } return hash; }
— Musakkhir Sayyed

26

이것은 세련되고 성능이 뛰어난 변형입니다.

String.prototype.hashCode = function() {
    var hash = 0, i = 0, len = this.length;
    while ( i < len ) {
        hash  = ((hash << 5) - hash + this.charCodeAt(i++)) << 0;
    }
    return hash;
};

이것은 Java의 표준 구현과 일치합니다. object.hashCode()

다음은 양의 해시 코드 만 반환하는 것입니다.

String.prototype.hashcode = function() {
    return (this.hashCode() + 2147483647) + 1;
};

그리고 다음은 양의 해시 코드 만 반환하는 Java와 일치하는 것입니다.

public static long hashcode(Object obj) {
    return ((long) obj.hashCode()) + Integer.MAX_VALUE + 1l;
}

즐겨!


2
좋은 대답이지만 << 0의 목적은 무엇입니까?
— koolaang

8
@koolaang 그것은 왼쪽 똥 연산자입니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
— mmm

29
@momomo 왼쪽으로 이동 했습니까 ?
— wdh

2
@ momomo 나는 그것이 왜 0 비트의 왼쪽 시프트인지 묻고 있다고 생각합니다.
— jpfx1342

3
@ Maykonn (2 ^
— 32-1

24

아직 새로운 SubtleCrypto API 에 대해 아무도 이야기하지 않은 것에 약간 놀랐습니다 .

문자열에서 해시를 얻으려면 다음 subtle.digest방법을 사용할 수 있습니다 .

function getHash(str, algo = "SHA-256") {
  let strBuf = new TextEncoder('utf-8').encode(str);
  return crypto.subtle.digest(algo, strBuf)
    .then(hash => {
      window.hash = hash;
      // here hash is an arrayBuffer, 
      // so we'll connvert it to its hex version
      let result = '';
      const view = new DataView(hash);
      for (let i = 0; i < hash.byteLength; i += 4) {
        result += ('00000000' + view.getUint32(i).toString(16)).slice(-8);
      }
      return result;
    });
}

getHash('hello world')
  .then(hash => {
    console.log(hash);
  });


4
동의한다. 16 진수로의 변환은 조금 다를 수 있습니다 ...var promise = crypto.subtle.digest({name: "SHA-256"}, Uint8Array.from(data)); promise.then(function(result){ console.log(Array.prototype.map.call(new Uint8Array(result), x => x.toString(16).padStart(2, '0')).join('')); });
— Denis Giffeler

3
문자열에 대한 암호화 해시 함수는 약간 과잉입니다. crypto정확하게 수행되지 않습니다.
— bryc

테스트를 실행하는 사람들, 내장 (사용자 정의 구현이 필요하지 않음), 시드 가능에 의존하지 않고 신뢰할 수있는 품질의 무작위이며 게임 맵을 생성하기 위해 수백 개의 숫자 만 필요했기 때문에 완벽했습니다. 그러나 동기식으로 수행 할 수있는 방법은 절대적으로 없습니다. 시드 랜덤 엔진을 호출 할 때마다 비동기 콜백을 제공해야하므로 코드를 읽을 수없고 우스운 것처럼 보입니다. 나는이 crappy crypto.subtle 인터페이스를 만든 사람을 얻지 못하므로 결국이 답변에서 xmur3 + sfc32를 사용해야했습니다 : stackoverflow.com/a/47593316/1201863
— Luc

7

mar10의 예제 덕분에 FNV-1a에 대해 C # AND Javascript에서 동일한 결과를 얻는 방법을 찾았습니다. 유니 코드 문자가 있으면 성능 향상을 위해 상단 부분이 삭제됩니다. URL 경로 만 해싱하는 것처럼 해싱 할 때 유지 관리하는 것이 왜 유용한 지 모르겠습니다.

C # 버전

private static readonly UInt32 FNV_OFFSET_32 = 0x811c9dc5;   // 2166136261
private static readonly UInt32 FNV_PRIME_32 = 0x1000193;     // 16777619

// Unsigned 32bit integer FNV-1a
public static UInt32 HashFnv32u(this string s)
{
    // byte[] arr = Encoding.UTF8.GetBytes(s);      // 8 bit expanded unicode array
    char[] arr = s.ToCharArray();                   // 16 bit unicode is native .net 

    UInt32 hash = FNV_OFFSET_32;
    for (var i = 0; i < s.Length; i++)
    {
        // Strips unicode bits, only the lower 8 bits of the values are used
        hash = hash ^ unchecked((byte)(arr[i] & 0xFF));
        hash = hash * FNV_PRIME_32;
    }
    return hash;
}

// Signed hash for storing in SQL Server
public static Int32 HashFnv32s(this string s)
{
    return unchecked((int)s.HashFnv32u());
}

자바 스크립트 버전

var utils = utils || {};

utils.FNV_OFFSET_32 = 0x811c9dc5;

utils.hashFnv32a = function (input) {
    var hval = utils.FNV_OFFSET_32;

    // Strips unicode bits, only the lower 8 bits of the values are used
    for (var i = 0; i < input.length; i++) {
        hval = hval ^ (input.charCodeAt(i) & 0xFF);
        hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24);
    }

    return hval >>> 0;
}

utils.toHex = function (val) {
    return ("0000000" + (val >>> 0).toString(16)).substr(-8);
}

@mathiasrw 유니 코드 문자가 메모리에서 8 비트를 초과 할 수 있으므로 0xFF는 단순히 해당 범위 밖의 모든 것을 마스크로 가정합니다. charCodeAt ()에 대한 자세한 내용은 여기를 참조하십시오 : developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
— djabraham

ES6을 사용할 수있는 경우 (모든 최신 엔진이 지원하는 경우) Math.imul곱셈 단계에 사용할 수 있으므로 성능 이 크게 향상됩니다 . 유일한 문제는 shim 없이 IE11에서 작동하지 않는다는 것입니다 .
— bryc

6

여기 에서 적응 한 빠르고 간결한 것 :

String.prototype.hashCode = function() {
  var hash = 5381, i = this.length
  while(i)
    hash = (hash * 33) ^ this.charCodeAt(--i)
  return hash >>> 0;
}

5

사용자 이름과 현재 시간을 기반으로 고유 ID를 생성하려면 비슷한 기능 (그러나 다른)이 필요했습니다. 그래서:

window.newId = ->
  # create a number based on the username
  unless window.userNumber?
    window.userNumber = 0
  for c,i in window.MyNamespace.userName
    char = window.MyNamespace.userName.charCodeAt(i)
    window.MyNamespace.userNumber+=char
  ((window.MyNamespace.userNumber + Math.floor(Math.random() * 1e15) + new Date().getMilliseconds()).toString(36)).toUpperCase()

생산 :

2DVFXJGEKL
6IZPAKFQFL
ORGOENVMG
... etc 

2015 년 6 월 편집 : 새 코드의 경우 shortid를 사용합니다 : https://www.npmjs.com/package/shortid


2
@ t0r0X 이제 shortid라는 모듈을 사용합니다 : npmjs.com/package/shortid
— jcollum

1
shortid로 사용자 이름을 어떻게 사용하고 있습니까? 단지 ID를 생성하는 것 같다하지만 난 당신이 문자열에서 해시를 생성하는 데 사용하는 표시되지 않습니다
— cyberwombat

1
이 답변에는 3 개의 다운 보트가 있습니다. 내 인생에서 나는 왜 그런지 상상할 수 없다. 아무도 ... 아무 말도하지 않았다 : - /
— jcollum

1
@jcollum 그렇기 때문에 나는 거의 오래된 질문에 대답하지 않습니다. 답을 고친 후에도 아무도 균형을 맞추지 않습니다.
— bryc

5

FNV의 Multiply+Xor방법을 기반으로 한 빠른 (매우 긴) 라이너 :

my_string.split('').map(v=>v.charCodeAt(0)).reduce((a,v)=>a+((a<<7)+(a<<3))^v).toString(16);

5

SubtleCrypto.digest

서버 측 언어를 사용하지 않으므로 그렇게 할 수 없습니다.

당신은 확실히 당신은 그것을 할 수없는 그런 식으로 ?

진화하는 언어 인 Javascript를 사용하고 있다는 사실을 잊었습니까?

시도하십시오 SubtleCrypto. SHA-1, SHA-128, SHA-256 및 SHA-512 해시 기능을 지원합니다.


async function hash(message/*: string */) {
	const text_encoder = new TextEncoder;
	const data = text_encoder.encode(message);
	const message_digest = await window.crypto.subtle.digest("SHA-512", data);
	return message_digest;
} // -> ArrayBuffer

function in_hex(data/*: ArrayBuffer */) {
	const octets = new Uint8Array(data);
	const hex = [].map.call(octets, octet => octet.toString(16).padStart(2, "0")).join("");
	return hex;
} // -> string

(async function demo() {
	console.log(in_hex(await hash("Thanks for the magic.")));
})();


2 년 전 Kaiido의 답변과 다른 점은 무엇입니까?
— Luc

@Luc 분명히 아닙니다.
— Константин Ван

3

나는 파티에 늦었지만이 모듈을 사용할 수 있습니다 : crypto :

const crypto = require('crypto');

const SALT = '$ome$alt';

function generateHash(pass) {
  return crypto.createHmac('sha256', SALT)
    .update(pass)
    .digest('hex');
}

이 함수의 결과는 항상 64문자열입니다. 이 같은:"aa54e7563b1964037849528e7ba068eb7767b1fab74a8d80fe300828b996714a"


2

나는 두 가지 솔루션 (사용자 esmiralha 및 lordvlad)을 결합하여 js 기능 reduce () 를 지원 하고 여전히 이전 브라우저와 호환되는 브라우저에 더 빠른 기능을 얻습니다 .

String.prototype.hashCode = function() {

    if (Array.prototype.reduce) {
        return this.split("").reduce(function(a,b){a=((a<<5)-a)+b.charCodeAt(0);return a&a},0);   
    } else {

        var hash = 0, i, chr, len;
        if (this.length == 0) return hash;
        for (i = 0, len = this.length; i < len; i++) {
        chr   = this.charCodeAt(i);
        hash  = ((hash << 5) - hash) + chr;
        hash |= 0; // Convert to 32bit integer
        }
        return hash;
    }
};

예:

my_string = 'xyz';
my_string.hashCode();

2

충돌을 피하려면 SHA-256 과 같은 보안 해시 를 사용하십시오 . 몇 가지 JavaScript SHA-256 구현이 있습니다.

여러 해시 구현을 비교하는 테스트를 작성했습니다 ( https://github.com/brillout/test-javascript-hash-implementations 참조) .

또는 http://brillout.github.io/test-javascript-hash-implementations/ 로 이동 하여 테스트를 실행하십시오.


1
안전한 암호화 해시 사용은 매우 느릴 수 있습니다. 충돌을 피하는 것은 보안이 아닌 비트 폭의 곱입니다. 128 비트 비 암호 해시 또는 64 비트는 대부분의 목적에 충분해야합니다. MurmurHash3_x86_128 은 매우 빠르며 충돌 가능성이 매우 낮습니다.
— bryc December

2

이것은 다른 답변보다 약간 더 안전한 해시이어야하지만 미리로드 된 소스가없는 함수

기본적으로 단순화 된 sha1 버전을 만들었습니다 .
문자열의 바이트를 가져 와서 4 ~ 32 비트 "워드"로 그룹화합니다.
그런 다음 8 워드를 40 워드로 확장하여 결과에 더 큰 영향을줍니다.
이것은 현재 상태와 입력으로 일부 수학을 수행하는 해싱 함수 (마지막 감소)로 이동합니다. 우리는 항상 4 단어를 꺼냅니다.
이것은 루프 대신 map, reduce ...를 사용하는 거의 한 명령 / 한 줄 버전이지만 여전히 빠릅니다.

String.prototype.hash = function(){
    var rot = (word, shift) => word << shift | word >>> (32 - shift);
    return unescape(encodeURIComponent(this.valueOf())).split("").map(char =>
            char.charCodeAt(0)
        ).reduce((done, byte, idx, arr) =>
            idx % 4 == 0 ? [...done, arr.slice(idx, idx + 4)] : done
        , []).reduce((done, group) =>
            [...done, group[0] << 24 | group[1] << 16 | group[2] << 8 | group[3]]
        , []).reduce((done, word, idx, arr) =>
            idx % 8 == 0 ? [...done, arr.slice(idx, idx + 8)] : done
        , []).map(group => {
            while(group.length < 40)
                group.push(rot(group[group.length - 2] ^ group[group.length - 5] ^ group[group.length - 8], 3));
            return group;
        }).flat().reduce((state, word, idx, arr) => {
            var temp = ((state[0] + rot(state[1], 5) + word + idx + state[3]) & 0xffffffff) ^ state[idx % 2 == 0 ? 4 : 5](state[0], state[1], state[2]);
            state[0] = rot(state[1] ^ state[2], 11);
            state[1] = ~state[2] ^ rot(~state[3], 19);
            state[2] = rot(~state[3], 11);
            state[3] = temp;
            return state;
        }, [0xbd173622, 0x96d8975c, 0x3a6d1a23, 0xe5843775,
            (w1, w2, w3) => (w1 & rot(w2, 5)) | (~rot(w1, 11) & w3),
            (w1, w2, w3) => w1 ^ rot(w2, 5) ^ rot(w3, 11)]
        ).slice(0, 4).map(p =>
            p >>> 0
        ).map(word =>
            ("0000000" + word.toString(16)).slice(-8)
        ).join("");
};

또한 단어 배열 대신 문자열을 얻기 위해 출력을 16 진수로 변환합니다.
사용법이 간단합니다. expample "a string".hash()반환합니다"88a09e8f9cc6f8c71c4497fbb36f84cd"


1

16 진수 문자열로 변환 된 char 코드를 간단히 연결했습니다. 이것은 상대적으로 좁은 목적, 즉 SHORT 문자열 (예 : 제목, 태그)의 해시 표현을 서버 측과 교환하여 관련이없는 이유로 허용 된 hashCode Java 포트를 쉽게 구현할 수 없도록하는 것입니다. 여기에는 보안 응용 프로그램이 없습니다.

String.prototype.hash = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.map.call(range, function(i) {
    return self.charCodeAt(i).toString(16);
  }).join('');
}

Underscore를 사용하면 더 간결하고 브라우저에 잘 견딜 수 있습니다. 예:

"Lorem Ipsum".hash()
"4c6f72656d20497073756d"

비슷한 방식으로 더 큰 문자열을 해시하려면 개별 문자를 함께 연결하는 대신 문자 코드를 줄이고 결과 합계를 16 진수로 만들 수 있다고 가정합니다.

String.prototype.hashLarge = function() {
  var self = this, range = Array(this.length);
  for(var i = 0; i < this.length; i++) {
    range[i] = i;
  }
  return Array.prototype.reduce.call(range, function(sum, i) {
    return sum + self.charCodeAt(i);
  }, 0).toString(16);
}

'One time, I hired a monkey to take notes for me in class. I would just sit back with my mind completely blank while the monkey scribbled on little pieces of paper. At the end of the week, the teacher said, "Class, I want you to write a paper using your notes." So I wrote a paper that said, "Hello! My name is Bingo! I like to climb on things! Can I have a banana? Eek, eek!" I got an F. When I told my mom about it, she said, "I told you, never trust a monkey!"'.hashLarge()
"9ce7"

자연스럽게이 방법과 충돌 할 위험이 있지만 감소의 산술을 피할 수는 있지만 해시를 다양 화하고 길게하고 싶었습니다.


1

@esmiralha의 답변이 약간 단순화 된 버전입니다.

이 버전에서는 String을 재정의하지 않습니다. 원하지 않는 동작이 발생할 수 있습니다.

function hashCode(str) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
        hash = ~~(((hash << 5) - hash) + str.charCodeAt(i));
    }
    return hash;
}

1

아직 아무도 없기 때문에 이것을 추가하면 해시로 많은 것을 요청하고 구현하는 것처럼 보이지만 항상 매우 좋지 않습니다.

이것은 문자열 입력과 해시와 같을 최대 수를 취하고 문자열 입력에 따라 고유 한 숫자를 생성합니다.

이를 사용하여 이미지 배열로 고유 한 인덱스를 생성 할 수 있습니다 (사용자에 대해 특정 아바타를 반환하고 임의로 선택했지만 이름을 기준으로 선택한 경우 항상 해당 이름을 가진 사람에게 할당됩니다) ).

물론 이것을 사용하여 다른 사람의 이름을 기반으로 고유 한 아바타 배경색을 생성하는 것과 같이 색인을 여러 색상으로 반환 할 수도 있습니다.

function hashInt (str, max = 1000) {
    var hash = 0;
    for (var i = 0; i < str.length; i++) {
      hash = ((hash << 5) - hash) + str.charCodeAt(i);
      hash = hash & hash;
    }
    return Math.round(max * Math.abs(hash) / 2147483648);
}

-1

객체 해시 라이브러리 등과 같은 즉시 사용 가능한 솔루션 대신이 복잡하고 복잡한 암호화 코드를 사용해야 할 이유가 없습니다. 공급 업체에 의존하는 것이 더 생산적이고 시간을 절약하며 유지 관리 비용을 절감합니다.

https://github.com/puleos/object-hash를 사용 하십시오.

var hash = require('object-hash');

hash({foo: 'bar'}) // => '67b69634f9880a282c14a0f0cb7ba20cf5d677e9'
hash([1, 2, 2.718, 3.14159]) // => '136b9b88375971dff9f1af09d7356e3e04281951'

그 lib의 소스 코드는 읽을 수 없습니다. 단지 50k의 축소 된 코드입니다.
— bryc

1
@bryc 그 공급 업체 코드가 같은 : 당신은 확인하실 수 있습니다 소스를 찾기 위해 가정 방법 github.com/puleos/object-hash/blob/master/index.js을
— 올렉 Abrazhaev을

축소 된 코드는 35.4KB이고 전체 소스는 14.2KB입니까? 말이되지 않습니다.
— bryc

2
@bryc이 라인을 고려 했습니까? var crypto = require('crypto');. 빌드 중에 축소 버전으로 공급 업체 의이 종속성 코드를 추가한다고 생각합니다.
— Oleg Abrazhaev

객체를 해시 해야하는 경우 정렬 키로 모든 객체를 직렬화 하는 직렬화를 작성한 다음 cyrb53 을 작성하여 base36 해시를 생성합니다.
— Polv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.