package net.i2p.crypto;
/*
* As pulled from https://github.com/nahi/siphash-java-inline
* Last commit was https://github.com/nahi/siphash-java-inline/commit/5be5c84851a28f800fcac66ced658bdbd01f31ef
* 2012-11-06
*
* Copyright 2012 Hiroshi Nakamura <nahi@ruby-lang.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* *WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/**
* SipHash implementation with hand inlining the SIPROUND.
*
* To know details about SipHash, see;
* "a fast short-input PRF" https://www.131002.net/siphash/
*
* SIPROUND is defined in siphash24.c that can be downloaded from the above
* site. Following license notice is subject to change based on the licensing
* policy of siphash24.c.
*
* I2P mods: add off/len version
*
* For constant keys see net.i2p.util.SipHash
*
* @since 0.9.5, Moved to net.i2p.crypto and public since 0.9.27
*/
public final class SipHashInline {
/** @since 0.9.27 */
private SipHashInline() {};
/**
* @param k0 the first 8 bytes of the key
* @param k1 the last 8 bytes of the key
*/
public static long hash24(long k0, long k1, byte[] data) {
return hash24(k0, k1, data, 0, data.length);
}
/**
* @param k0 the first 8 bytes of the key
* @param k1 the last 8 bytes of the key
*/
public static long hash24(long k0, long k1, byte[] data, int off, int len) {
long v0 = 0x736f6d6570736575L ^ k0;
long v1 = 0x646f72616e646f6dL ^ k1;
long v2 = 0x6c7967656e657261L ^ k0;
long v3 = 0x7465646279746573L ^ k1;
long m;
int last = off + (len / 8 * 8);
int i = off;
// processing 8 bytes blocks in data
while (i < last) {
// pack a block to long, as LE 8 bytes
m = ((((long) data[i++]) & 0xff) ) |
((((long) data[i++]) & 0xff) << 8) |
((((long) data[i++]) & 0xff) << 16) |
((((long) data[i++]) & 0xff) << 24) |
((((long) data[i++]) & 0xff) << 32) |
((((long) data[i++]) & 0xff) << 40) |
((((long) data[i++]) & 0xff) << 48) |
((((long) data[i++]) & 0xff) << 56);
// MSGROUND {
v3 ^= m;
/* SIPROUND wih hand reordering
*
* SIPROUND in siphash24.c:
* A: v0 += v1;
* B: v1=ROTL(v1,13);
* C: v1 ^= v0;
* D: v0=ROTL(v0,32);
* E: v2 += v3;
* F: v3=ROTL(v3,16);
* G: v3 ^= v2;
* H: v0 += v3;
* I: v3=ROTL(v3,21);
* J: v3 ^= v0;
* K: v2 += v1;
* L: v1=ROTL(v1,17);
* M: v1 ^= v2;
* N: v2=ROTL(v2,32);
*
* Each dependency:
* B -> A
* C -> A, B
* D -> C
* F -> E
* G -> E, F
* H -> D, G
* I -> H
* J -> H, I
* K -> C, G
* L -> K
* M -> K, L
* N -> M
*
* Dependency graph:
* D -> C -> B -> A
* G -> F -> E
* J -> I -> H -> D, G
* N -> M -> L -> K -> C, G
*
* Resulting parallel friendly execution order:
* -> ABCDHIJ
* -> EFGKLMN
*/
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
v0 ^= m;
// }
}
// packing the last block to long, as LE 0-7 bytes + the length in the top byte
m = 0;
for (i = off + len - 1; i >= last; --i) {
m <<= 8; m |= (long) (data[i] & 0xff);
}
m |= (long) len << 56;
// MSGROUND {
v3 ^= m;
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
v0 ^= m;
// }
// finishing...
v2 ^= 0xff;
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
// SIPROUND {
v0 += v1; v2 += v3;
v1 = (v1 << 13) | v1 >>> 51; v3 = (v3 << 16) | v3 >>> 48;
v1 ^= v0; v3 ^= v2;
v0 = (v0 << 32) | v0 >>> 32; v2 += v1;
v0 += v3; v1 = (v1 << 17) | v1 >>> 47;
v3 = (v3 << 21) | v3 >>> 43; v1 ^= v2;
v3 ^= v0; v2 = (v2 << 32) | v2 >>> 32;
// }
return v0 ^ v1 ^ v2 ^ v3;
}
}