Skip to content

Instantly share code, notes, and snippets.

@lvsecoto
Last active February 17, 2019 10:32
Show Gist options
  • Save lvsecoto/b1b2ce762b382a5cec28733e2e2e60dc to your computer and use it in GitHub Desktop.
Save lvsecoto/b1b2ce762b382a5cec28733e2e2e60dc to your computer and use it in GitHub Desktop.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TKCalculateUtils {
public static long hexCharAsNumber(char c) {
if (c >= 'a') {
return c - 87;
} else {
return Long.valueOf(String.valueOf(c));
}
}
public static long normalizeHash(long encondindRound2) {
if (encondindRound2 < 0) {
encondindRound2 = (encondindRound2 & 0x7fffffffL) + 0x80000000L;
}
return encondindRound2 % 1000000L;
}
public static List<Long> transformQuery(String query) {
List<Long> result = new ArrayList<>();
for (int i = 0; i < query.length(); i++) {
char c = query.charAt(i);
if (c < 128) {
result.add((long) c); // 0{l[6-0]}
} else if (c < 2048) {
result.add(c >> 6 | 0xC0L); // 110{l[10-6]}
result.add(c & 0x3F | 0x80L); // 10{l[5-0]}
} else if (0xD800L == (c & 0xFC00L) && c + 1 < query.length() && 0xDC00L == (query.charAt(i + 1) & 0xFC00L)) {
// that's pretty rare... (avoid ovf?)
c = (char) ((1 << 16) + ((c & 0x03FF) << 10) + (query.charAt(++i) & 0x03FF));
result.add(c >> 18 | 0xF0L); // 111100{l[9-8*]}
result.add(c >> 12 & 0x3FL | 0x80L); // 10{l[7*-2]}
result.add(c & 0x3FL | 0x80L); // 10{(l+1)[5-0]}
} else {
result.add(c >> 12 | 0xE0L); // 1110{l[15-12]}
result.add(c >> 6 & 0x3FL | 0x80L); // 10{l[11-6]}
result.add(c & 0x3FL | 0x80L); // 10{l[5-0]}
}
}
return result;
}
public static long shiftLeftOrRightThenSumOrXor(List<String> opArray, long num) {
for (String opString : opArray) {
char op1 = opString.charAt(1); // '+' | '-' ~ SUM | XOR
char op2 = opString.charAt(0); // '+' | '^' ~ SLL | SRL
char xd = opString.charAt(2); // [0-9a-f]
long shiftAmount = hexCharAsNumber(xd);
long mask = (op1 == '+') ? num >>> shiftAmount : num << shiftAmount;
num = (op2 == '+') ? (num + mask & 0xffffffffL) : (num ^ mask);
}
return num;
}
/*
/ EXAMPLE:
/
/ INPUT: query: 'hola', windowTkk: '409837.2120040981'
/ OUTPUT: '70528.480109'
/
*/
public static String calcHash(String query, String windowTkk) {
// STEP 1: spread the the query char codes on a byte-array, 1-3 bytes per char
List<Long> bytesArray = transformQuery(query);
// STEP 2: starting with TKK index, add the array from last step one-by-one, and do 2 rounds of shift+add/xor
String[] d = windowTkk.split("\\.");
long tkkIndex = Long.valueOf(d[0]);
long tkkKey = Long.valueOf(d[1]);
long acc = tkkIndex;
for (Long current : bytesArray) {
acc += current;
acc = shiftLeftOrRightThenSumOrXor(Arrays.asList("+-a", "^+6"), acc);
}
long encondingRound1 = acc;
// STEP 3: apply 3 rounds of shift+add/xor and XOR with they TKK key
long encondingRound2 = shiftLeftOrRightThenSumOrXor(Arrays.asList("+-3", "^+b", "+-f"), encondingRound1) ^ tkkKey;
// STEP 4: Normalize to 2s complement & format
long normalizedResult = normalizeHash(encondingRound2);
return normalizedResult + "." + (normalizedResult ^ tkkIndex);
}
}
import org.junit.Test;
import static cn.lskiot.lsapp.TKCalculateUtils.*;
import static com.google.common.truth.Truth.assertThat;
import static java.util.Arrays.asList;
public class TKCalculateUtilsTest {
@Test
public void testHexCharAsNumber() {
assertThat(hexCharAsNumber('3')).isEqualTo(3);
assertThat(hexCharAsNumber('a')).isEqualTo(10);
}
@Test
public void testTransformQuery() {
assertThat(transformQuery("123ABCabc我")).isEqualTo(asList(49L, 50L, 51L, 65L, 66L, 67L, 97L, 98L, 99L, 230L, 136L, 145L));
}
@Test
public void testNormalizeHash() {
assertThat(normalizeHash(8134240)).isEqualTo(134240);
}
@Test
public void testShiftLeftOrRightThenSumOrXor() {
assertThat(shiftLeftOrRightThenSumOrXor(asList("+-a", "^+9"), 12)).isEqualTo(12308);
}
@Test
public void testCalcHash() {
assertThat(calcHash("hola", "409837.2120040981")).isEqualTo("70528.480109");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment