Initial commit.
[fast-key-erasure-rng-java.git] / etc / io / github / deajl3ka / fast_key_erasure / GenerateCounter.java
blob79ba622e333cc543e744421d5696bd2f0b880db0
1 /*
2 * FastKeyErasureRNG: Fast-key-erasure random-number generator for Java
3 * Copyright (c) 2023 "dEajL3kA" <Cumpoing79@web.de>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
6 * associated documentation files (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
8 * sub license, and/or sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions: The above copyright notice and this
10 * permission notice shall be included in all copies or substantial portions of the Software.
12 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
13 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
15 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT
16 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 package io.github.deajl3ka.fast_key_erasure;
20 import java.util.Locale;
21 import java.util.SplittableRandom;
22 import java.util.concurrent.BrokenBarrierException;
23 import java.util.concurrent.CyclicBarrier;
25 public class GenerateCounter {
27 private static final int THREAD_COUNT = 8, WORDS = 6, EXPECTED_DISTANCE = 68;
29 private static final SplittableRandom splittableRandom = new SplittableRandom(0x93C467E37DB0C7A4L);
31 private static int bestDistance = -1;
33 private static final Object mutex = new Object();
35 private static final CyclicBarrier barrier = new CyclicBarrier(THREAD_COUNT);
37 private static class Int128 {
38 final long hi, lo;
40 public Int128(final long hi, final long lo) {
41 this.hi = hi;
42 this.lo = lo;
45 public String toString(final boolean verbose) {
46 final String hexString = toString();
47 if (!verbose) {
48 return hexString;
50 final String upperString = hexString.toUpperCase(Locale.ENGLISH);
51 final StringBuilder sb = new StringBuilder("{ ");
52 int pos = 0;
53 while (pos < hexString.length()) {
54 if (pos > 0) {
55 sb.append(", ");
57 sb.append("(byte)0x");
58 sb.append(upperString.subSequence(pos, pos += 2));
60 return sb.append(" }").toString();
63 @Override
64 public String toString() {
65 return longToHexStr(hi) + longToHexStr(lo);
69 private static int distance(final Int128 a,final Int128 b) {
70 return Long.bitCount(a.hi ^ b.hi) + Long.bitCount(a.lo ^ b.lo);
73 public static void main(String[] args) {
74 final Thread[] threads = new Thread[THREAD_COUNT];
75 for (int tid = 0; tid < THREAD_COUNT; ++tid) {
76 threads[tid] = new Thread(GenerateCounter::threadMain);
77 threads[tid].start();
79 for (final Thread thread : threads) {
80 try {
81 thread.join();
82 } catch (InterruptedException e) {
83 break;
88 private static void threadMain() {
89 final Int128[] values = new Int128[WORDS];
90 final char[][] nibble = new char[WORDS][];
92 final SplittableRandom random;
93 synchronized (mutex) {
94 random = splittableRandom.split();
97 for (;;) {
98 for (int i = 0; i < WORDS; ++i) {
99 generatorLoop:
100 for (;;) {
101 final char[] thisNibbles;
102 try {
103 values[i] = new Int128(random.nextLong(), random.nextLong());
104 thisNibbles = nibble[i] = values[i].toString().toCharArray();
105 } catch(NumberFormatException e) {
106 continue generatorLoop;
108 for (int k = 0; k < 31; ++k) {
109 if (thisNibbles[k] == thisNibbles[k + 1]) {
110 continue generatorLoop;
113 for (int k = 0; k < 30; k += 2) {
114 if ((thisNibbles[k] == thisNibbles[k + 2]) && (thisNibbles[k+1] == thisNibbles[k + 3])) {
115 continue generatorLoop;
118 for (int j = 0; j < i; ++j) {
119 final char[] otherNibbles = nibble[j];
120 for (int k = 0; k < 32; ++k) {
121 if (thisNibbles[k] == otherNibbles[k]) {
122 continue generatorLoop;
126 break; /*okay*/
130 int minDistance = Integer.MAX_VALUE;
131 for (int i = 0; i < WORDS; ++i) {
132 for (int j = i + 1; j < WORDS; ++j) {
133 final int thisDistance = distance(values[i], values[j]);
134 if (thisDistance < minDistance) {
135 minDistance = thisDistance;
140 synchronized (mutex) {
141 if (minDistance >= bestDistance) {
142 bestDistance = minDistance;
143 System.out.printf("[%d]%n", bestDistance);
144 for (int i = 0; i < WORDS; ++i) {
145 final String word = new String(nibble[i]).toUpperCase(Locale.ENGLISH);
146 if (!values[i].toString().equalsIgnoreCase(word)) {
147 throw new AssertionError("Whoops!");
149 System.out.println(word);
151 System.out.println();
152 if (bestDistance >= EXPECTED_DISTANCE) {
153 for (int i = 0; i < WORDS; ++i) {
154 System.out.println(values[i].toString(true));
156 System.out.println();
161 try {
162 barrier.await();
163 } catch (InterruptedException | BrokenBarrierException e) {
164 return;
167 synchronized (mutex) {
168 if (bestDistance >= EXPECTED_DISTANCE) {
169 return;
175 private static String longToHexStr(final long value) {
176 final String str = Long.toHexString(value);
177 switch (str.length()) {
178 case 16:
179 return str;
180 case 15:
181 return '0' + str;
182 case 14:
183 return "00" + str;
184 default:
185 throw new NumberFormatException();