const P: u128 = 18446744069414584321;
fn add(a: u64, b: u64) -> u64 {
((a as u128 + b as u128) % P) as u64
}
fn mul(a: u64, b: u64) -> u64 {
((a as u128 * b as u128) % P) as u64
}
fn power7(a: u64) -> u64 {
let mut result = 1;
for _ in 0..7 {
result = mul(result, a);
}
result
}
const M4: [[u64; 4]; 4] = [[5, 7, 1, 3], [4, 6, 1, 1], [1, 3, 5, 7], [1, 1, 4, 6]];
const EXTERNAL: [u64; 64] = [
15949291268843349465,
14644164809401934923,
18420360874837380316,
4756469047455716334,
8685499049481102115,
3799221349720045367,
13676397835037157930,
6566439050423619635,
17428268347612331188,
2833135872454503769,
4767009016213040191,
2797635963551733652,
5312339450141126694,
5356668452102813289,
1234059326449530173,
7724302552453704877,
14868588146468890290,
12825281145595371185,
13097885453579304196,
7905326782341128063,
14167525334039893569,
2082169701994688927,
12190787523818595537,
12602917751946636,
14890907856876319003,
16552240149997473409,
5634093690795187558,
4883714163685656967,
12440776365164557866,
3923800234666204307,
9858064884105950259,
16040043470428402038,
94277733998400326,
10891359798487446420,
18280773820738154043,
13714589910668449566,
10639034072771185213,
14148790895768484219,
18341268649720100165,
3096672942770686236,
12277596046563557393,
400461754528604020,
12955488253560265444,
11773677676764285572,
4833837465239476573,
17645852643693996619,
6605134696140007471,
588040525114200273,
11001741536026769411,
17917086578469406776,
14893530806420712543,
727997185253761138,
3443873847340254325,
13095911531247069692,
8330737046680948619,
6014364575875986011,
16851679856681761121,
17817965496543149594,
12823640325246269760,
13685256787930775147,
4682652317564502291,
4233879762155685988,
11097258179564187322,
10804761421745472094,
];
const INTERNAL: [u64; 22] = [
5226594323142090582,
1243120476974621208,
12100812801659301173,
11228203327983058121,
13891617888374767564,
5742893160230537107,
3763472116988983643,
2466655769425769160,
6254574254498162968,
14183251225809189357,
11565357354521717084,
17300657704266685688,
310485250821938281,
16853586468012618118,
1978800426240373849,
6948188224235462572,
1486402152218690509,
5669161690283398991,
17943970877073781734,
17926851897715769433,
13052837496695000666,
18138113741095562305,
];
const DIAG: [u64; 8] = [
12216033376705242021,
2072934925475504800,
16432743296706583078,
1287600597097751715,
10482065724875379356,
3057917794534811537,
4460508886913832365,
4574242228824269566,
];
fn external(state: &mut [u64; 8]) {
let old = *state;
let mut blocks = [0; 8];
for b in 0..2 {
for r in 0..4 {
for c in 0..4 {
blocks[b * 4 + r] = add(blocks[b * 4 + r], mul(M4[r][c], old[b * 4 + c]));
}
}
}
for i in 0..8 {
state[i] = add(blocks[i], add(blocks[i % 4], blocks[i % 4 + 4]));
}
}
pub fn permute(mut state: [u64; 8]) -> [u64; 8] {
external(&mut state);
for round in 0..30 {
if round < 4 || round >= 26 {
let index = if round < 4 { round } else { round - 22 };
for i in 0..8 {
state[i] = power7(add(state[i], EXTERNAL[index * 8 + i]));
}
external(&mut state);
} else {
state[0] = power7(add(state[0], INTERNAL[round - 4]));
let sum = state.iter().copied().fold(0, add);
for i in 0..8 {
state[i] = add(mul(state[i], DIAG[i]), sum);
}
}
}
state
}
pub fn hash2(a: u64, b: u64) -> u64 {
permute([a, b, 0, 0, 2, 0, 0, 0])[0]
}