Path: blob/trunk/third_party/closure/goog/crypt/hash32.js
2868 views
// Copyright 2008 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Implementation of 32-bit hashing functions.16*17* This is a direct port from the Google Java Hash class18*19*/2021goog.provide('goog.crypt.hash32');2223goog.require('goog.crypt');242526/**27* Default seed used during hashing, digits of pie.28* See SEED32 in http://go/base.hash.java29* @type {number}30*/31goog.crypt.hash32.SEED32 = 314159265;323334/**35* Arbitrary constant used during hashing.36* See CONSTANT32 in http://go/base.hash.java37* @type {number}38*/39goog.crypt.hash32.CONSTANT32 = -1640531527;404142/**43* Hashes a string to a 32-bit value.44* @param {string} str String to hash.45* @return {number} 32-bit hash.46*/47goog.crypt.hash32.encodeString = function(str) {48return goog.crypt.hash32.encodeByteArray(goog.crypt.stringToByteArray(str));49};505152/**53* Hashes a string to a 32-bit value, converting the string to UTF-8 before54* doing the encoding.55* @param {string} str String to hash.56* @return {number} 32-bit hash.57*/58goog.crypt.hash32.encodeStringUtf8 = function(str) {59return goog.crypt.hash32.encodeByteArray(60goog.crypt.stringToUtf8ByteArray(str));61};626364/**65* Hashes an integer to a 32-bit value.66* @param {number} value Number to hash.67* @return {number} 32-bit hash.68*/69goog.crypt.hash32.encodeInteger = function(value) {70// TODO(user): Does this make sense in JavaScript with doubles? Should we71// force the value to be in the correct range?72return goog.crypt.hash32.mix32_(73{a: value, b: goog.crypt.hash32.CONSTANT32, c: goog.crypt.hash32.SEED32});74};757677/**78* Hashes a "byte" array to a 32-bit value using the supplied seed.79* @param {Array<number>} bytes Array of bytes.80* @param {number=} opt_offset The starting position to use for hash81* computation.82* @param {number=} opt_length Number of bytes that are used for hashing.83* @param {number=} opt_seed The seed.84* @return {number} 32-bit hash.85*/86goog.crypt.hash32.encodeByteArray = function(87bytes, opt_offset, opt_length, opt_seed) {88var offset = opt_offset || 0;89var length = opt_length || bytes.length;90var seed = opt_seed || goog.crypt.hash32.SEED32;9192var mix = {93a: goog.crypt.hash32.CONSTANT32,94b: goog.crypt.hash32.CONSTANT32,95c: seed96};9798var keylen;99for (keylen = length; keylen >= 12; keylen -= 12, offset += 12) {100mix.a += goog.crypt.hash32.wordAt_(bytes, offset);101mix.b += goog.crypt.hash32.wordAt_(bytes, offset + 4);102mix.c += goog.crypt.hash32.wordAt_(bytes, offset + 8);103goog.crypt.hash32.mix32_(mix);104}105// Hash any remaining bytes106mix.c += length;107switch (keylen) { // deal with rest. Some cases fall through108case 11:109mix.c += (bytes[offset + 10]) << 24;110case 10:111mix.c += (bytes[offset + 9] & 0xff) << 16;112case 9:113mix.c += (bytes[offset + 8] & 0xff) << 8;114// the first byte of c is reserved for the length115case 8:116mix.b += goog.crypt.hash32.wordAt_(bytes, offset + 4);117mix.a += goog.crypt.hash32.wordAt_(bytes, offset);118break;119case 7:120mix.b += (bytes[offset + 6] & 0xff) << 16;121case 6:122mix.b += (bytes[offset + 5] & 0xff) << 8;123case 5:124mix.b += (bytes[offset + 4] & 0xff);125case 4:126mix.a += goog.crypt.hash32.wordAt_(bytes, offset);127break;128case 3:129mix.a += (bytes[offset + 2] & 0xff) << 16;130case 2:131mix.a += (bytes[offset + 1] & 0xff) << 8;132case 1:133mix.a += (bytes[offset + 0] & 0xff);134// case 0 : nothing left to add135}136return goog.crypt.hash32.mix32_(mix);137};138139140/**141* Performs an inplace mix of an object with the integer properties (a, b, c)142* and returns the final value of c.143* @param {Object} mix Object with properties, a, b, and c.144* @return {number} The end c-value for the mixing.145* @private146*/147goog.crypt.hash32.mix32_ = function(mix) {148var a = mix.a, b = mix.b, c = mix.c;149a -= b;150a -= c;151a ^= c >>> 13;152b -= c;153b -= a;154b ^= a << 8;155c -= a;156c -= b;157c ^= b >>> 13;158a -= b;159a -= c;160a ^= c >>> 12;161b -= c;162b -= a;163b ^= a << 16;164c -= a;165c -= b;166c ^= b >>> 5;167a -= b;168a -= c;169a ^= c >>> 3;170b -= c;171b -= a;172b ^= a << 10;173c -= a;174c -= b;175c ^= b >>> 15;176mix.a = a;177mix.b = b;178mix.c = c;179return c;180};181182183/**184* Returns the word at a given offset. Treating an array of bytes a word at a185* time is far more efficient than byte-by-byte.186* @param {Array<number>} bytes Array of bytes.187* @param {number} offset Offset in the byte array.188* @return {number} Integer value for the word.189* @private190*/191goog.crypt.hash32.wordAt_ = function(bytes, offset) {192var a = goog.crypt.hash32.toSigned_(bytes[offset + 0]);193var b = goog.crypt.hash32.toSigned_(bytes[offset + 1]);194var c = goog.crypt.hash32.toSigned_(bytes[offset + 2]);195var d = goog.crypt.hash32.toSigned_(bytes[offset + 3]);196return a + (b << 8) + (c << 16) + (d << 24);197};198199200/**201* Converts an unsigned "byte" to signed, that is, convert a value in the range202* (0, 2^8-1) to (-2^7, 2^7-1) in order to be compatible with Java's byte type.203* @param {number} n Unsigned "byte" value.204* @return {number} Signed "byte" value.205* @private206*/207goog.crypt.hash32.toSigned_ = function(n) {208return n > 127 ? n - 256 : n;209};210211212