Jkins实现Jenkins Hash?

时间:2010-11-20 19:20:12

标签: javascript hash

我可以使用Jenkins Hash的javascript实现 - 而不是自己实现吗?

我知道有一个python实现我可以用来编写自己的js。但我不是Javascript专家,因此我更喜欢有人在实施。


更新:(我确实尝试转换http://www.burtleburtle.net/bob/c/lookup3.c) 更新2:此代码在lookup3.c

中为您提供与hashlittle2相同的哈希值
var Jenkins = {
rot: function(x,k) {
    return (x<<k) | (x>>>(32-k));
},

mix: function(a,b,c) {
    a = (a - c) | 0;  a ^= Jenkins.rot(c, 4);  c = (c + b) | 0;
    b = (b - a) | 0;  b ^= Jenkins.rot(a, 6);  a = (a + c) | 0;
    c = (c - b) | 0;  c ^= Jenkins.rot(b, 8);  b = (b + a) | 0;
    a = (a - c) | 0;  a ^= Jenkins.rot(c,16);  c = (c + b) | 0;
    b = (b - a) | 0;  b ^= Jenkins.rot(a,19);  a = (a + c) | 0;
    c = (c - b) | 0;  c ^= Jenkins.rot(b, 4);  b = (b + a) | 0;
    return {a : a, b : b, c : c};
},

final: function(a,b,c) {
   c ^= b; c -= Jenkins.rot(b,14) | 0;
   a ^= c; a -= Jenkins.rot(c,11) | 0;
   b ^= a; b -= Jenkins.rot(a,25) | 0;
   c ^= b; c -= Jenkins.rot(b,16) | 0;
   a ^= c; a -= Jenkins.rot(c,4) | 0;
   b ^= a; b -= Jenkins.rot(a,14) | 0;
   c ^= b; c -= Jenkins.rot(b,24) | 0;
   return {a : a, b : b, c : c};
},  

hashlittle2: function(k, initval, initval2) {
    var length = k.length;
    a = b = c = 0xdeadbeef + length + initval;
    c += initval2;

    offset = 0;
    while (length > 12) {
        a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); a = a>>>0;
        b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16) + (k.charCodeAt(offset+7)<<24)); b = b>>>0;
        c += (k.charCodeAt(offset+8) + (k.charCodeAt(offset+9)<<8) + (k.charCodeAt(offset+10)<<16) + (k.charCodeAt(offset+11)<<24)); c = c>>>0;
        o = Jenkins.mix(a,b,c);
        a = o.a; b = o.b; c = o.c;
        length -= 12;
        offset += 12;
    }

    switch(length) {
        case 12: c += (k.charCodeAt(offset+8) + (k.charCodeAt(offset+9)<<8) + (k.charCodeAt(offset+10)<<16) + (k.charCodeAt(offset+11)<<24)); b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16) + (k.charCodeAt(offset+7)<<24)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 11: c += (k.charCodeAt(offset+8) + (k.charCodeAt(offset+9)<<8) + (k.charCodeAt(offset+10)<<16)); b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16) + (k.charCodeAt(offset+7)<<24)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 10: c += (k.charCodeAt(offset+8) + (k.charCodeAt(offset+9)<<8)); b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16) + (k.charCodeAt(offset+7)<<24)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 9: c += (k.charCodeAt(offset+8)); b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16) + (k.charCodeAt(offset+7)<<24)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 8: b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16) + (k.charCodeAt(offset+7)<<24)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 7: b += (k.charCodeAt(offset+4) + (k.charCodeAt(offset+5)<<8) + (k.charCodeAt(offset+6)<<16)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 6: b += ((k.charCodeAt(offset+5)<<8) + k.charCodeAt(offset+4)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 5: b += (k.charCodeAt(offset+4)); a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 4: a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16) + (k.charCodeAt(offset+3)<<24)); break;
        case 3: a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8) + (k.charCodeAt(offset+2)<<16)); break;
        case 2: a += (k.charCodeAt(offset+0) + (k.charCodeAt(offset+1)<<8)); break;
        case 1: a += (k.charCodeAt(offset+0)); break;
        case 0: return {b : b, c : c};
    }

    o = Jenkins.final(a,b,c);
    a = o.a; b = o.b; c = o.c;

    return {b : b>>>0, c : c>>>0};
}    

}

3 个答案:

答案 0 :(得分:3)

这是我为lookup3.c做的JavaScript端口,用于在JavaScript中实现Bloom filter的个人项目。我不能肯定地说它是否会产生与C代码相同的结果。

直接转换为JavaScript的主要内容之一是对指向键输入的指针执行的指针算术。在下面的代码中查找单词offset,看看我是如何处理的。

如果您希望输出就像整数是无符号的那样,则可以使用returnValue >>> 0

var BloomFilter = {
    // Convert a JavaScript string into an array of 32-bit words.
    // This preserves the UTF-16 encoding, padding with the null character if necessary.
    stringToWords: function(s) {
        var b = [];
        if(s.length & 1) {
            s += "\u0000";
        }
        for (var i = 0; i < s.length; i += 2) {
            b.push((s.charCodeAt(i) << 16) | (s.charCodeAt(i + 1)));
        }
        return b;
    },

    // Hash an array of multiple 32-bit words to a single word.
    // Adapted from "lookup3.c, by Bob Jenkins, May 2006, Public Domain."
    // as retrieved 2010-07-03 from http://burtleburtle.net/bob/c/lookup3.c

    hashWord: function(k, initval) {
        // definition of bitwise rotate function
        function rot(x, k) {
            return (x << k) | (x >>> (32 - k));
        }

        // initialization
        var a, b, c, length = k.length, offset = 0;
        a = b = c = (0xdeadbeef + (length << 2) + initval) | 0;

        // handle most of the key
        while(length > 3) {
            a = (a + k[offset]) | 0;
            b = (b + k[offset + 1]) | 0;
            c = (c + k[offset + 2]) | 0;

            // mixing function
            a = (a - c) | 0;  a ^= rot(c, 4);  c = (c + b) | 0;
            b = (b - a) | 0;  b ^= rot(a, 6);  a = (a + c) | 0;
            c = (c - b) | 0;  c ^= rot(b, 8);  b = (b + a) | 0;
            a = (a - c) | 0;  a ^= rot(c,16);  c = (c + b) | 0;
            b = (b - a) | 0;  b ^= rot(a,19);  a = (a + c) | 0;
            c = (c - b) | 0;  c ^= rot(b, 4);  b = (b + a) | 0;

            length -= 3;
            offset += 3;
        }

        // handle the final words if left over; fall-through is intended
        switch(length) {
            case 3: c = (c + k[offset + 2]) | 0;
            case 2: b = (b + k[offset + 1]) | 0;
            case 1: a = (a + k[offset]) | 0;

            // final mixing
            c ^= b; c = (c - rot(b,14)) | 0;
            a ^= c; a = (a - rot(c,11)) | 0;
            b ^= a; b = (b - rot(a,25)) | 0;
            c ^= b; c = (c - rot(b,16)) | 0;
            a ^= c; a = (a - rot(c, 4)) | 0;
            b ^= a; b = (b - rot(a,14)) | 0;
            c ^= b; c = (c - rot(b,24)) | 0;

            case 0: break; // nothing left to do
        }

        // return the result
        return c;
    },

    // Hash a string by converting to UTF-16 before using the lookup3 algorithm.
    hashString: function(s) {
        return BloomFilter.hashWord(BloomFilter.stringToWords(s), 0);
    }
}

答案 1 :(得分:2)

只需进行一些修改,C code on Wikipedia将在JavaScript中完美运行。只需删除数据类型并使用key.length而不必传递长度。

答案 2 :(得分:1)

这是我对lookup3(2006)所做的优化端口:

function lookup3(k, init = 0, init2 = 0) {
    var len = k.length, o = 0,
        a = 0xdeadbeef + len + init | 0,
        b = 0xdeadbeef + len + init | 0,
        c = 0xdeadbeef + len + init + init2 | 0;

    while (len > 12) {
        a += k[o]   | k[o+1] << 8 | k[o+2]  << 16 | k[o+3]  << 24;
        b += k[o+4] | k[o+5] << 8 | k[o+6]  << 16 | k[o+7]  << 24;
        c += k[o+8] | k[o+9] << 8 | k[o+10] << 16 | k[o+11] << 24;

        a -= c; a ^= c<<4  | c>>>28; c = c+b | 0;
        b -= a; b ^= a<<6  | a>>>26; a = a+c | 0;
        c -= b; c ^= b<<8  | b>>>24; b = b+a | 0;
        a -= c; a ^= c<<16 | c>>>16; c = c+b | 0;
        b -= a; b ^= a<<19 | a>>>13; a = a+c | 0;
        c -= b; c ^= b<<4  | b>>>28; b = b+a | 0;

        len -= 12, o += 12;
    }

    if(len > 0) { // final mix only if len > 0
        switch (len) { // incorporate trailing bytes before fmix
            case 12: c += k[o+11] << 24;
            case 11: c += k[o+10] << 16;
            case 10: c += k[o+9] << 8;
            case  9: c += k[o+8];
            case  8: b += k[o+7] << 24;
            case  7: b += k[o+6] << 16;
            case  6: b += k[o+5] << 8;
            case  5: b += k[o+4];
            case  4: a += k[o+3] << 24;
            case  3: a += k[o+2] << 16;
            case  2: a += k[o+1] << 8;
            case  1: a += k[o];
        }

        c ^= b; c -= b<<14 | b>>>18;
        a ^= c; a -= c<<11 | c>>>21;
        b ^= a; b -= a<<25 | a>>>7;
        c ^= b; c -= b<<16 | b>>>16;
        a ^= c; a -= c<<4  | c>>>28;
        b ^= a; b -= a<<14 | a>>>18;
        c ^= b; c -= b<<24 | b>>>8;
    }
    // use c as 32-bit hash; add b for 64-bit hash. a is not mixed well.
    return [b >>> 0, c >>> 0];
}

这里是lookup2(1996),它非常相似(但速度较慢):

function lookup2(k, init = 0) {
    var len = k.length, o = 0, 
        a = 0x9e3779b9 | 0,
        b = 0x9e3779b9 | 0,
        c = init | 0;

    while (len >= 12) {
        a += k[o]   | k[o+1] << 8 | k[o+2]  << 16 | k[o+3]  << 24;
        b += k[o+4] | k[o+5] << 8 | k[o+6]  << 16 | k[o+7]  << 24;
        c += k[o+8] | k[o+9] << 8 | k[o+10] << 16 | k[o+11] << 24;

        a -= b; a -= c; a ^= c >>> 13;
        b -= c; b -= a; b ^= a << 8;
        c -= a; c -= b; c ^= b >>> 13;
        a -= b; a -= c; a ^= c >>> 12;
        b -= c; b -= a; b ^= a << 16;
        c -= a; c -= b; c ^= b >>> 5;
        a -= b; a -= c; a ^= c >>> 3;
        b -= c; b -= a; b ^= a << 10;
        c -= a; c -= b; c ^= b >>> 15;

        len -= 12, o += 12;
    }

    c += k.length;
    switch(len) {
        case 11: c += k[o+10] << 24;
        case 10: c += k[o+9] << 16;
        case  9: c += k[o+8] << 8;
        // the first byte of c is reserved for the length
        case  8: b += k[o+7] << 24;
        case  7: b += k[o+6] << 16;
        case  6: b += k[o+5] << 8;
        case  5: b += k[o+4];
        case  4: a += k[o+3] << 24;
        case  3: a += k[o+2] << 16;
        case  2: a += k[o+1] << 8;
        case  1: a += k[o];
    }

    a -= b; a -= c; a ^= c >>> 13;
    b -= c; b -= a; b ^= a << 8;
    c -= a; c -= b; c ^= b >>> 13;
    a -= b; a -= c; a ^= c >>> 12;
    b -= c; b -= a; b ^= a << 16;
    c -= a; c -= b; c ^= b >>> 5;
    a -= b; a -= c; a ^= c >>> 3;
    b -= c; b -= a; b ^= a << 10;
    c -= a; c -= b; c ^= b >>> 15;
    // c is intended as 32-bit hash only
    return c >>> 0;
}