Path: blob/trunk/third_party/closure/goog/crypt/hashtester.js
2868 views
// Copyright 2011 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 Unit tests for the abstract cryptographic hash interface.16*17*/1819goog.provide('goog.crypt.hashTester');2021goog.require('goog.array');22goog.require('goog.crypt');23goog.require('goog.dom');24goog.require('goog.dom.TagName');25goog.require('goog.testing.PerformanceTable');26goog.require('goog.testing.PseudoRandom');27goog.require('goog.testing.asserts');28goog.setTestOnly('hashTester');293031/**32* Runs basic tests.33*34* @param {!goog.crypt.Hash} hash A hash instance.35*/36goog.crypt.hashTester.runBasicTests = function(hash) {37// Compute first hash.38hash.update([97, 158]);39var golden1 = hash.digest();4041// Compute second hash.42hash.reset();43hash.update('aB');44var golden2 = hash.digest();45assertTrue(46'Two different inputs resulted in a hash collision',47!!goog.testing.asserts.findDifferences(golden1, golden2));4849// Empty hash.50hash.reset();51var empty = hash.digest();52assertTrue(53'Empty hash collided with a non-trivial one',54!!goog.testing.asserts.findDifferences(golden1, empty) &&55!!goog.testing.asserts.findDifferences(golden2, empty));5657// Zero-length array update.58hash.reset();59hash.update([]);60assertArrayEquals(61'Updating with an empty array did not give an empty hash', empty,62hash.digest());6364// Zero-length string update.65hash.reset();66hash.update('');67assertArrayEquals(68'Updating with an empty string did not give an empty hash', empty,69hash.digest());7071// Recompute the first hash.72hash.reset();73hash.update([97, 158]);74assertArrayEquals(75'The reset did not produce the initial state', golden1, hash.digest());7677// Check for a trivial collision.78hash.reset();79hash.update([158, 97]);80assertTrue(81'Swapping bytes resulted in a hash collision',82!!goog.testing.asserts.findDifferences(golden1, hash.digest()));8384// Compare array and string input.85hash.reset();86hash.update([97, 66]);87assertArrayEquals(88'String and array inputs should give the same result', golden2,89hash.digest());9091// Compute in parts.92hash.reset();93hash.update('a');94hash.update([158]);95assertArrayEquals(96'Partial updates resulted in a different hash', golden1, hash.digest());9798// Test update with specified length.99hash.reset();100hash.update('aB', 0);101hash.update([97, 158, 32], 2);102assertArrayEquals(103'Updating with an explicit buffer length did not work', golden1,104hash.digest());105};106107108/**109* Runs block tests.110*111* @param {!goog.crypt.Hash} hash A hash instance.112* @param {number} blockBytes Size of the hash block.113*/114goog.crypt.hashTester.runBlockTests = function(hash, blockBytes) {115// Compute a message which is 1 byte shorter than hash block size.116var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';117var message = '';118for (var i = 0; i < blockBytes - 1; i++) {119message += chars.charAt(i % chars.length);120}121122// Compute golden hash for 1 block + 2 bytes.123hash.update(message + '123');124var golden1 = hash.digest();125126// Compute golden hash for 2 blocks + 1 byte.127hash.reset();128hash.update(message + message + '123');129var golden2 = hash.digest();130131// Almost fill a block, then overflow.132hash.reset();133hash.update(message);134hash.update('123');135assertArrayEquals(golden1, hash.digest());136137// Fill a block.138hash.reset();139hash.update(message + '1');140hash.update('23');141assertArrayEquals(golden1, hash.digest());142143// Overflow a block.144hash.reset();145hash.update(message + '12');146hash.update('3');147assertArrayEquals(golden1, hash.digest());148149// Test single overflow with an array.150hash.reset();151hash.update(goog.crypt.stringToByteArray(message + '123'));152assertArrayEquals(golden1, hash.digest());153154// Almost fill a block, then overflow this and the next block.155hash.reset();156hash.update(message);157hash.update(message + '123');158assertArrayEquals(golden2, hash.digest());159160// Fill two blocks.161hash.reset();162hash.update(message + message + '12');163hash.update('3');164assertArrayEquals(golden2, hash.digest());165166// Test double overflow with an array.167hash.reset();168hash.update(goog.crypt.stringToByteArray(message));169hash.update(goog.crypt.stringToByteArray(message + '123'));170assertArrayEquals(golden2, hash.digest());171};172173174/**175* Runs performance tests.176*177* @param {function():!goog.crypt.Hash} hashFactory A hash factory.178* @param {string} hashName Name of the hashing function.179*/180goog.crypt.hashTester.runPerfTests = function(hashFactory, hashName) {181var body = goog.dom.getDocument().body;182var perfTable = goog.dom.createElement(goog.dom.TagName.DIV);183goog.dom.appendChild(body, perfTable);184185var table = new goog.testing.PerformanceTable(perfTable);186187function runPerfTest(byteLength, updateCount) {188var label =189(hashName + ': ' + updateCount + ' update(s) of ' + byteLength +190' bytes');191192function run(data, dataType) {193table.run(function() {194var hash = hashFactory();195for (var i = 0; i < updateCount; i++) {196hash.update(data, byteLength);197}198var digest = hash.digest();199}, label + ' (' + dataType + ')');200}201202var byteArray = goog.crypt.hashTester.createRandomByteArray_(byteLength);203var byteString = goog.crypt.hashTester.createByteString_(byteArray);204205run(byteArray, 'byte array');206run(byteString, 'byte string');207}208209var MESSAGE_LENGTH_LONG = 10000000; // 10 Mbytes210var MESSAGE_LENGTH_SHORT = 10; // 10 bytes211var MESSAGE_COUNT_SHORT = MESSAGE_LENGTH_LONG / MESSAGE_LENGTH_SHORT;212213runPerfTest(MESSAGE_LENGTH_LONG, 1);214runPerfTest(MESSAGE_LENGTH_SHORT, MESSAGE_COUNT_SHORT);215};216217218/**219* Creates and returns a random byte array.220*221* @param {number} length Length of the byte array.222* @return {!Array<number>} An array of bytes.223* @private224*/225goog.crypt.hashTester.createRandomByteArray_ = function(length) {226var random = new goog.testing.PseudoRandom(0);227var bytes = [];228229for (var i = 0; i < length; ++i) {230// Generates an integer from 0 to 255.231var b = Math.floor(random.random() * 0x100);232bytes.push(b);233}234235return bytes;236};237238239/**240* Creates a string from an array of bytes.241*242* @param {!Array<number>} bytes An array of bytes.243* @return {string} The string encoded by the bytes.244* @private245*/246goog.crypt.hashTester.createByteString_ = function(bytes) {247var str = '';248goog.array.forEach(bytes, function(b) { str += String.fromCharCode(b); });249return str;250};251252253