mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2024-12-25 05:06:45 +00:00
add port of deterministic prng for border wallets word shuffle
This commit is contained in:
parent
af532e7fc9
commit
4d7d897e06
1 changed files with 121 additions and 0 deletions
|
@ -27,6 +27,7 @@ import java.io.FileInputStream;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,6 +149,23 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> shuffle(List<String> mnemonic) {
|
||||||
|
String mnemonicString = String.join(" ", mnemonic);
|
||||||
|
List<String> words = new ArrayList<>(Bip39MnemonicCode.INSTANCE.getWordList());
|
||||||
|
|
||||||
|
UltraHighEntropyPrng uhePrng = new UltraHighEntropyPrng();
|
||||||
|
uhePrng.initState();
|
||||||
|
uhePrng.hashString(mnemonicString);
|
||||||
|
for(int i = words.size() - 1; i > 0; i--) {
|
||||||
|
int j = (int)uhePrng.random(i + 1);
|
||||||
|
String tmp = words.get(i);
|
||||||
|
words.set(i, words.get(j));
|
||||||
|
words.set(j, tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return words;
|
||||||
|
}
|
||||||
|
|
||||||
private class MnemonicGridDialogPane extends DialogPane {
|
private class MnemonicGridDialogPane extends DialogPane {
|
||||||
@Override
|
@Override
|
||||||
protected Node createButton(ButtonType buttonType) {
|
protected Node createButton(ButtonType buttonType) {
|
||||||
|
@ -193,4 +211,107 @@ public class MnemonicGridDialog extends Dialog<List<String>> {
|
||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class UltraHighEntropyPrng {
|
||||||
|
private final int order;
|
||||||
|
private double carry;
|
||||||
|
private int phase;
|
||||||
|
private final double[] intermediates;
|
||||||
|
private int i, j, k; // general purpose locals
|
||||||
|
|
||||||
|
public UltraHighEntropyPrng() {
|
||||||
|
order = 48; // set the 'order' number of ENTROPY-holding 32-bit values
|
||||||
|
carry = 1; // init the 'carry' used by the multiply-with-carry (MWC) algorithm
|
||||||
|
phase = order; // init the 'phase' (max-1) of the intermediate variable pointer
|
||||||
|
intermediates = new double[order]; // declare our intermediate variables array
|
||||||
|
|
||||||
|
for(i = 0; i < order; i++) {
|
||||||
|
// Used to simulate javascript's Math.random
|
||||||
|
Random random = new Random();
|
||||||
|
intermediates[i] = mash(random.nextInt(Integer.MAX_VALUE)); // fill the array with initial mash hash values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double random(int range) {
|
||||||
|
return Math.floor(range * (rawPrng() + ((long)(rawPrng() * 0x200000L)) * 1.1102230246251565e-16)); // 2^-53
|
||||||
|
}
|
||||||
|
|
||||||
|
private String randomString(int count) {
|
||||||
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
|
for(i = 0; i < count; i++) {
|
||||||
|
char newChar = (char) (33 + random(94));
|
||||||
|
stringBuilder.append(newChar);
|
||||||
|
}
|
||||||
|
return stringBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double rawPrng() {
|
||||||
|
if(++phase >= order) {
|
||||||
|
phase = 0;
|
||||||
|
}
|
||||||
|
double t = 1768863 * intermediates[phase] + carry * 2.3283064365386963e-10; // 2^-32
|
||||||
|
long temp = (long)t;
|
||||||
|
return intermediates[phase] = t - (carry = temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hash(String args) {
|
||||||
|
for(i = 0; i < args.length(); i++) {
|
||||||
|
for(j = 0; j < order; j++) {
|
||||||
|
intermediates[j] -= mash(args.charAt(i));
|
||||||
|
if(intermediates[j] < 0) {
|
||||||
|
intermediates[j] = intermediates[j] + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void hashString(String input) {
|
||||||
|
mash(input); // use the string to evolve the 'mash' state
|
||||||
|
|
||||||
|
char[] inputAry = input.toCharArray();
|
||||||
|
for(i = 0; i < inputAry.length; i++) // scan through the characters in our string
|
||||||
|
{
|
||||||
|
k = inputAry[i]; // get the character code at the location
|
||||||
|
for(j = 0; j < order; j++) // "mash" it into the UHEPRNG state
|
||||||
|
{
|
||||||
|
intermediates[j] -= mash(k);
|
||||||
|
if(intermediates[j] < 0) {
|
||||||
|
intermediates[j] += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initState() {
|
||||||
|
mash(null);
|
||||||
|
for(i = 0; i < order; i++) {
|
||||||
|
intermediates[i] = mash(' '); // fill the array with initial mash hash values
|
||||||
|
}
|
||||||
|
carry = 1; // init our multiply-with-carry carry
|
||||||
|
phase = order; // init our phase
|
||||||
|
}
|
||||||
|
|
||||||
|
double n = Integer.toUnsignedLong(0xefc8249d);
|
||||||
|
|
||||||
|
private double mash(Object data) {
|
||||||
|
if(data != null) {
|
||||||
|
String strData = data.toString();
|
||||||
|
for(int i = 0; i < strData.length(); i++) {
|
||||||
|
n += strData.charAt(i);
|
||||||
|
double h = 0.02519603282416938 * n;
|
||||||
|
n = Integer.toUnsignedLong((int)h);
|
||||||
|
h -= n;
|
||||||
|
h *= n;
|
||||||
|
n = Integer.toUnsignedLong((int)h);
|
||||||
|
h -= n;
|
||||||
|
n += h * 0x100000000L; // 2^32
|
||||||
|
}
|
||||||
|
return ((long)n) * 2.3283064365386963e-10; // 2^-32
|
||||||
|
} else {
|
||||||
|
n = Integer.toUnsignedLong(0xefc8249d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue