blob: 4237a0d98fef13485597aafaec3b09ea80c13118 [file] [log] [blame] [edit]
// ShiftRows is a hot function in the implementation of the Rijndael cipher
// For documentation see: http://asmaes.sourceforge.net/rijndael/rijndaelImplementation.pdf
// Author: Peter Jensen
(function() {
// Kernel configuration
var kernelConfig = {
kernelName: "ShiftRows",
kernelInit: init,
kernelCleanup: cleanup,
kernelSimd: simdShiftRowsN,
kernelNonSimd: shiftRowsN,
kernelIterations: 1000
};
// Hook up to the harness
benchmarks.add(new Benchmark(kernelConfig));
// Do the object allocations globally, so the performance of the kernel
// functions aren't overshadowed by object creations
var state = new Int32Array(16); // 4x4 state matrix
var temp = new Int32Array (1000); // Big enough for 1000 columns
function printState() {
for (var r = 0; r < 4; ++r) {
var str = "";
var ri = r*4;
for (var c = 0; c < 4; ++c) {
var value = state[ri + c];
if (value < 10) {
str += " ";
}
str += " " + state[ri + c];
}
print(str);
}
}
// initialize the 4x4 state matrix
function initState() {
for (var i = 0; i < 16; ++i) {
state[i] = i;
}
}
// Verify the result of calling shiftRows(state, 4)
function checkState() {
var expected = new Uint32Array(
[ 0, 1, 2, 3,
5, 6, 7, 4,
10, 11, 8, 9,
15, 12, 13, 14]);
for (var i = 0; i < 16; ++i) {
if (state[i] !== expected[i]) {
return false;
}
}
return true;
}
function init() {
// Check that shiftRows yields the right result
initState();
shiftRowsN(1);
if (!checkState()) {
return false;
}
// Check that simdShiftRows yields the right result
initState();
simdShiftRowsN(1);
if (!checkState()) {
return false;
}
return true;
}
function cleanup() {
return init(); // Sanity checking before and after are the same
}
// This is the typical implementation of the shiftRows function
function shiftRows(state, Nc) {
for (var r = 1; r < 4; ++r) {
var ri = r*Nc; // get the starting index of row 'r'
var c;
for (c = 0; c < Nc; ++c) {
temp[c] = state[ri + ((c + r) % Nc)];
}
for (c = 0; c < Nc; ++c) {
state[ri + c] = temp[c];
}
}
}
// The SIMD optimized version of the shiftRows function
// The function is special cased for a 4 column setting (Nc == 4).
// This is the value used for AES blocks (see documentation for details)
function simdShiftRows(state, Nc) {
if (Nc !== 4) {
shiftRows(state, Nc);
}
for (var r = 1; r < 4; ++r) {
var rx4 = SIMD.Int32x4.load(state, r << 2);
if (r == 1) {
SIMD.Int32x4.store(state, 4, SIMD.Int32x4.swizzle(rx4, 1, 2, 3, 0));
}
else if (r == 2) {
SIMD.Int32x4.store(state, 8, SIMD.Int32x4.swizzle(rx4, 2, 3, 0, 1));
}
else { // r == 3
SIMD.Int32x4.store(state, 12, SIMD.Int32x4.swizzle(rx4, 3, 0, 1, 2));
}
}
}
function shiftRowsN(iterations) {
for (var i = 0; i < iterations; ++i) {
shiftRows(state, 4);
}
}
function simdShiftRowsN(iterations) {
for (var i = 0; i < iterations; ++i) {
simdShiftRows(state, 4);
}
}
} ());