Skip to content

Instantly share code, notes, and snippets.

@tevador
Last active December 18, 2022 12:06
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tevador/5b3fbbd0877a3412ede07263c6b2663d to your computer and use it in GitHub Desktop.
Save tevador/5b3fbbd0877a3412ede07263c6b2663d to your computer and use it in GitHub Desktop.
Monero checksum search

1. Introduction

This document describes the search for a checksum algorithm to be used with Monero's new addressing scheme Jamtis. The purpose of the checksum is to detect accidental corruption of the address string.

Since Jamtis encodes addresses in base32, it allows the use of cyclic codes, which can provide guaranteed error detection, unlike hash-based checksums.

1.1 State of the art

Monero currently uses a 32-bit hash-based checksum for its addresses. Hash-based checksums have a flat false positive rate regardless of the number of errors. Bitcoin's bech32 address format uses a degree-6 cyclic code optimized for short addresses of up to 89 characters. The cashaddr address format of Bitcoin Cash uses a degree-8 cyclic code that can detect 5 errors for lengths of up to 130 characters.

The following table shows the performance of the various checksums when applied to a 196-character Jamtis address. The column "detection" refers to the number of errors that can always be detected. "Max5" and "Max6" are the maximum spans when 5 and 6 errors can always be detected, respectively. "Rate5" and "Rate6" are the worst false positive rates for lengths of up to 196 characters (multiplied by 2^40).

Checksum size used by detection Max5 Max6 Rate5 *2^40 Rate6 *2^40
code(J3PBP3J1) 40 bits BCH (cashaddr) 4 130 33 0.692608 1.001845
40-bit hash 40 bits - 0 - - 1.000000 1.000000
32-bit hash 32 bits XMR 0 - - 256.000000 256.000000
code(TMKLTI) 30 bits BTC (bech32) 3 18 8 1007.952788 1068.701701

This shows that a degree-8 cyclic code can offer the best performance even for relatively long addresses.

1.2 Goals

We will search for a degree-8 cyclic code that has the best performance at 196 characters.

Since there are over 1 trillion (2^40) possible degree-8 codes over GF(2^5), we will only search a random subset of this space and select the best perfoming code.

2. Tools

2.1 gen_crc.py

The gen_crc.py file (attached to this document) is a python script that will deterministically generate random 10 million degree-8 codes (encoded in base32hex). It avoids polynomials with a zero constant term since those perform like degree-7 codes.

2.2 crccollide.cpp

"Crccollide" is a tool written by Bitcoin developers to test the performance of cyclic codes. The source code is available in a forked repository.

The tool accepts a generator polynomial (encoded in base32hex) and will examine its ability to detect a small number of errors up to a specified length.

2.3 crc_res.py

The crc_res.py file (attached to this document) will read the outputs of crccollide in a specified directory and print the best performing codes based on the following 4 indicators:

  1. The maximum length when 4 errors can always be detected. Degree-8 codes can typically always detect 4 errors up to the reference length of 196, so this will filter out codes that don't reach this baseline performance.
  2. The combined maximum error rates for 5 and 6 errors up to the reference length. Degree-8 codes have a 6-error rates typically around 1.0x2^-40 at 196 characters, so this metric allows codes with a slightly worse ability to detect 6 errors if they have an exceptional ability to detect 5 errors.
  3. The average 5-error rate at the reference length of 196 characters.
  4. The average 6-error rate at the reference length of 196 characters.

3. The search

  1. pypy3 gen_crc.py | sort -u > gen_list1.txt
  2. git clone https://github.com/tevador/ezbase32
  3. g++ ezbase32/crccollide.cpp -o crccollide -lpthread -O3
  4. mkdir results1
  5. parallel -a gen_list1.txt ./crccollide {} 5 120 ">" results1/{}.txt
  6. find results1 -name "*.txt" -type f -size -2k -delete
  7. pypy3 crc_res.py results1 196 64 > results1.txt

3.1 Random generators

The first command will generate 9999947 unique generators, which can be checked with wc -l gen_list1.txt.

3.5 Testing

The fifth command will test each generator with the crccollide tool. To speed things up, crccollide is configured to exit early if the generator cannot detect 5 errors at 120 characters. Note that this step may run for days or even weeks (took over 4 days using AMD Threadripper 3970X with 64 threads in parallel).

3.6 Cleanup

The sixth command will clean up the files of the generators that cannot detect 5 errors at 120 characters (these files will have a size of less than 2 KB). The results directory should contain 17122 files after this step, which can be checked with ls results1 | wc -l.

3.7 Processing

The seventh command will print the top 64 generators. The resulting file results1.txt is attached to this document.

The top two codes (U1PIRGA7 and AJ4RJKVB) significantly outperform the remaining ones since they can detect 5 errors at the reference length of 196 characters.

The other 62 codes have 5-error false positive rates roughly 3x lower than a 40-bit hash.

4. Refining

4.1 Beyond 196 characters

The main search only tested the performance of the generators up to the length of 210 characters. Since the checksum might need to be used for longer strings in the future (such as certified addresses or invoices), we tested the performance of the top generators for lengths of up to 500 characters:

  1. grep -oP "^[0-9A-V]{8}" results1.txt | sort -u > gen_list2.txt
  2. g++ ezbase32/crccollide.cpp -o crccollide_500 -lpthread -O3 -DLENGTH=500
  3. mkdir results2
  4. parallel -a gen_list2.txt ./crccollide_500 {} ">" results2/{}.txt
  5. pypy3 crc_res.py results2 196 16 > results2.txt

(The fourth step took about 5 hours using AMD Threadripper 3970X with 64 threads in parallel).

The file results2.txt, attached to this document, lists the best performing 16 generators. This refining process eliminated the generators that cannot always detect 4 error at 500 characters. Notably, the codes U1PIRGA7 and AJ4RJKVB can still detect 5 errors at this length. The remaining 14 codes have very similar performance for both 5 and 6 errors.

4.2 Beyond 6 errors

The main search only tested the performance of the generators for up to 6 errors. To further refine the results, we tested the top 16 generators for their ability to detect 7 and 8 errors in spans of up to 50 characters:

  1. grep -oP "^[0-9A-V]{8}" results2.txt | sort -u > gen_list3.txt
  2. g++ ezbase32/crccollide.cpp -o crccollide_50_4 -lpthread -O3 -DLENGTH=50 -DERRORS=4 -DTHREADS=4
  3. mkdir results3
  4. parallel -a gen_list3.txt ./crccollide_50_4 {} ">" results3/{}.txt

The resulting 16 files were examined manually to extract the maximum false positive rates for 7 and 8 errors.

generator err7 err8
0S7SR3A6 1.790741 4.440434
3EJU3UBP 0.994695 1.776173
5155TAUI 0.999173 1.024186
7RGCN5R5 1.004357 1.937644
AJ4RJKVB 1.133229 1.211027
DEE30B1D 0.994857 4.440434
FKFN98KS 1.564244 1.011930
FVK7D3HH 2.310268 1.211028
JKHOGKBA 1.075304 1.211028
KVDQ5Q0V 0.987055 4.440434
NHU34U1C 0.994869 1.372498
O2IM6DP1 1.150664 1.007043
QKDE8B2P 1.109647 1.121159
RJ7I0PVJ 1.443917 4.440434
U1PIRGA7 1.043527 1.080609
VRSOEBL7 4.692732 1.008940

We have eliminated the 9 codes that have false positive rates for 7 or 8 errors exceeding 1.5.

5. Final results

The remaining 7 codes can be split into two groups.

5.1 "Super-generators"

The two "super-generators" can always detect 5 errors, but have a slightly degraded ability to detect 6 errors, with a false positive rate of 15.346780 at the length of 15 characters (similar rate as a 36-bit hash). The generator U1PIRGA7 has a slightly better performance, so it's the winner in this group.

generator max5 max6 err5 err6 err7 err8
U1PIRGA7 500 13 0.000000 15.346780 1.043527 1.080609
AJ4RJKVB 500 13 0.000000 15.346780 1.133229 1.211027

5.2 "No flaw" generators

The remaining 5 generators do not significantly underperform in any situation compared to a 40-bit hash. The generator 5155TAUI stands out with its overall lowest false positive rates and the ability to detect 5 errors in spans of 146 characters.

generator max5 max6 err5 err6 err7 err8
JKHOGKBA 127 22 0.274547 1.080168 1.075304 1.211028
5155TAUI 146 23 0.315105 0.991495 0.999173 1.024186
QKDE8B2P 132 23 0.287547 1.108732 1.109647 1.121159
O2IM6DP1 121 32 0.327585 0.995260 1.150664 1.007043
NHU34U1C 122 25 0.300546 1.093295 0.994869 1.372498

5.3 Checksum algorithm

The checksum algorithm proposal in file jamtis_polymod.py is attached to this document. The proposal uses the code based on the generator U1PIRGA7 (or 5155TAUI as an alternative).

6. Acknowledgements

Most of the calculations were performed on a Monero Research Computing machine equipped with an AMD Threadripper CPU.

Thanks to Pieter "sipa" Wuille for developing the crccollide tool and providing some consultations.

import sys
import os
CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
def mul2(x):
high = 0x842108421084210 & x
low = 0x7BDEF7BDEF7BDEF & x
return (low << 1) ^ (high >> 4) ^ (high >> 1)
class GenResult:
def __init__(self, name, ref_len):
self.name = name
self.ref_len = ref_len
self.ref4 = 0.0
self.ref5 = 0.0
self.ref6 = 0.0
self.avg5 = 0.0
self.avg6 = 0.0
def add_err(self, curr_len, err4, err5, err6):
if err4 == 0.0:
self.max4 = curr_len
if err5 == 0.0:
self.max5 = curr_len
if err6 == 0.0:
self.max6 = curr_len
if curr_len <= self.ref_len:
self.ref4 = max(err4, self.ref4)
self.ref5 = max(err5, self.ref5)
self.ref6 = max(err6, self.ref6)
self.avg5 += err5 / self.ref_len
self.avg6 += err6 / self.ref_len
def to_array(self):
gen = 0
degree = len(self.name)
for i in range(degree):
c = CHARSET.find(self.name[degree - 1 - i])
gen |= c << (5 * i)
gen_arr = [ gen ]
gen_arr.append(mul2(gen_arr[-1]))
gen_arr.append(mul2(gen_arr[-1]))
gen_arr.append(mul2(gen_arr[-1]))
gen_arr.append(mul2(gen_arr[-1]))
return '[{}]'.format(', '.join([hex(x) for x in gen_arr]))
def get_score(self):
return (-self.max4, #sort descending by max length for 4 errors
self.ref5 * self.ref6, #sort ascending by combined max 5/6 error rate
self.avg5, #sort ascending by avg 5 error rate
self.avg6) #sort ascending by avg 6 error rate
def test_file(filename, ref_len):
gen = None
curr_len = 0
with open(filename) as file:
for line in file:
tokens = line.split()
if len(tokens) == 2 and tokens[1] == "starting":
gen = GenResult(tokens[0].rstrip(':'), ref_len)
continue
if gen and tokens[0] == gen.name:
curr_len = int(tokens[1])
err4 = float(tokens[1 + 4])
err5 = float(tokens[1 + 5])
err6 = float(tokens[1 + 6])
gen.add_err(curr_len, err4, err5, err6)
if curr_len:
return gen
def test_dir(dirpath, ref_len):
gens = []
for entry in os.listdir(dirpath):
filename = os.path.join(dirpath, entry)
if os.path.isfile(filename):
gen = test_file(filename, ref_len)
if gen:
gens.append(gen)
return gens
if len(sys.argv) != 4:
print("Usage: %s [path] [ref_len] [num_res]" % sys.argv[0])
exit()
ref_len = int(sys.argv[2])
num_res = int(sys.argv[3])
results = test_dir(sys.argv[1], ref_len)
num_found = len(results)
print("Found %i generators." % num_found)
num_best = min(num_res, num_found)
results.sort(key=lambda x: x.get_score())
if num_best > 0:
print("Best %i performers for lengths of up to %i characters:" % (num_best, ref_len))
for i in range(num_best):
gen = results[i]
print("%s: max4=%i max5=%i max6=%i err5=%f err6=%f avg5=%f avg6=%f GEN=%s" % (gen.name, gen.max4, gen.max5, gen.max6, gen.ref5, gen.ref6, gen.avg5, gen.avg6, gen.to_array()))
import random
CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
def gen_to_str(val, degree):
gen_str = ""
for i in range(degree):
gen_str = CHARSET[int(val) % 32] + gen_str
val /= 32
return gen_str
def gen_crc(degree, count, seed=None):
random.seed(seed)
for i in range(count):
while True:
r = random.getrandbits(5 * degree)
if (r % 32) != 0:
break
print(gen_to_str(r, degree))
gen_crc(8, 10000000, 0x584d52)
# Jamtis address checksum algorithm proposal
# cyclic code based on the generator U1PIRGA7
# can always detect 1-5 errors
GEN=[0xf0732dc147, 0xa8b6dfa68e, 0x193fabc83c, 0x322fd3b451, 0x640f37688b]
# cyclic code based on the generator 5155TAUI
# can always detect 1-4 errors
#GEN=[0x284a5eabd2, 0x5094a9d2ad, 0xa12947847a, 0xa021f08dd, 0x14042a9193]
M = 0xfffffffff7
def jamtis_polymod(data):
c = 1
for v in data:
b = (c >> 35)
c = ((c & 0x07ffffffff) << 5) ^ v
for i in range(5):
c ^= GEN[i] if ((b >> i) & 1) else 0
return c
def jamtis_verify_checksum(data):
return jamtis_polymod(data) == M
def jamtis_create_checksum(data):
polymod = jamtis_polymod(data + [0,0,0,0,0,0,0,0]) ^ M
return [(polymod >> 5 * (7 - i)) & 31 for i in range(8)]
# test/example
CHARSET = "xmrbase32cdfghijknopqtuwy1456789"
addr_test = (
"xmr1majob1977bw3ympyh2yxd7hjymrw8crc9kinodkm8d3"
"wdu8jdhf3fkdpmgxfkbywbb9mdwkhkya4jtfnod5h7s49bf"
"yji1936w19tyf39o6ypjo9n64runqjrxwp6k2s3phxwm6wr"
"b5cob6c1ntrg2mugeocwdgnnr7u7bgknya9arksrjore7wh")
addr_data = [CHARSET.find(x) for x in addr_test]
addr_enc = addr_data + jamtis_create_checksum(addr_data)
addr = "".join([CHARSET[x] for x in addr_enc])
print(addr)
print("len =", len(addr))
print("valid =", jamtis_verify_checksum(addr_enc))
Found 17122 generators.
Best 64 performers for lengths of up to 196 characters:
U1PIRGA7: max4=210 max5=210 max6=13 err5=0.000000 err6=15.346780 avg5=0.000000 avg6=1.545813 GEN=[0xf0732dc147, 0xa8b6dfa68e, 0x193fabc83c, 0x322fd3b451, 0x640f37688b]
AJ4RJKVB: max4=210 max5=210 max6=13 err5=0.000000 err6=15.346780 avg5=0.000000 avg6=1.564299 GEN=[0x54c9b9d3eb, 0xa3d1f786f6, 0xfa17f08e5, 0x15527a91ca, 0x20e4e1a394]
DKDMB8AK: max4=210 max5=134 max6=21 err5=0.284947 err6=0.995494 avg5=0.043171 avg6=0.785446 GEN=[0x6d1b65a154, 0xd0745b4281, 0xe8baa2a422, 0x9927454844, 0x7a1e1a3488]
JOGSM09P: max4=210 max5=148 max6=22 err5=0.244389 err6=1.167690 avg5=0.029595 avg6=0.880651 GEN=[0x9e21cb0139, 0x7e5312825b, 0xf6e4b501bf, 0xafdb6a0357, 0x1df45083a7]
VRSOEBL7: max4=210 max5=123 max6=26 err5=0.282867 err6=1.025742 avg5=0.047074 avg6=0.817349 GEN=[0xfef9872ea7, 0xbfe39e586e, 0x3dd7b894dc, 0x71edf5a991, 0xe38b7b530b]
FKFN98KS: max4=210 max5=130 max6=26 err5=0.289107 err6=1.009149 avg5=0.042873 avg6=0.831064 GEN=[0x7d1f74a29c, 0xf07c794031, 0xa8aae6a44b, 0x1907cd4896, 0x320d1eb505]
DEE30B1D: max4=210 max5=129 max6=29 err5=0.296906 err6=0.995276 avg5=0.049757 avg6=0.764013 GEN=[0x6b9c302c2d, 0xd73860585a, 0xec62c0149d, 0x9ad7802913, 0x7dad90520f]
FVK7D3HH: max4=210 max5=121 max6=21 err5=0.292227 err6=1.012096 avg5=0.048907 avg6=0.859303 GEN=[0x7fe8768e31, 0xf5c2ed196b, 0xa9c5ceb2d6, 0x1b8919e0a5, 0x3710b7e54a]
JKHOGKBA: max4=210 max5=127 max6=22 err5=0.274547 err6=1.080168 avg5=0.042294 avg6=0.860180 GEN=[0x9d2388516a, 0x78579486d4, 0xf0adb908a1, 0xa90bf69142, 0x1a157d2284]
3EJU3UBP: max4=210 max5=138 max6=26 err5=0.297946 err6=1.015542 avg5=0.033664 avg6=0.841875 GEN=[0x1ba7e1f979, 0x371f5356db, 0x647c360cbf, 0xc2ea6c1957, 0xcd86ccb287]
LNJ7UBQ9: max4=210 max5=124 max6=28 err5=0.306266 err6=1.004244 avg5=0.061050 avg6=0.798827 GEN=[0xade67f2f49, 0x19deeadbb2, 0x33bdc1966d, 0x672b1329fa, 0xc446b653dd]
KVDQ5Q0V: max4=210 max5=126 max6=32 err5=0.311466 err6=0.995733 avg5=0.056371 avg6=0.776661 GEN=[0xa7dba2e81f, 0xdf5d57417, 0x11fb3a4c07, 0x23a6f0bc0e, 0x471fe1781c]
0S7SR3A6: max4=210 max5=145 max6=21 err5=0.289107 err6=1.073390 avg5=0.035648 avg6=0.857036 GEN=[0x70fcd8d46, 0x45d1f9a8c, 0x2f8bbb038, 0x5a363e059, 0x15657649b]
3031GHEQ: max4=210 max5=140 max6=29 err5=0.309906 err6=1.004661 avg5=0.034692 avg6=0.787584 GEN=[0x18061845da, 0x300c24af9d, 0x6018495a33, 0xc03086956f, 0xc8330d2ade]
5155TAUI: max4=210 max5=146 max6=23 err5=0.315105 err6=0.991495 avg5=0.038737 avg6=0.778061 GEN=[0x284a5eabd2, 0x5094a9d2ad, 0xa12947847a, 0xa021f08dd, 0x14042a9193]
RJ7I0PVJ: max4=210 max5=125 max6=29 err5=0.317185 err6=0.995053 avg5=0.054974 avg6=0.719604 GEN=[0xdccf2067f3, 0xfbdcd06eef, 0xbfb9a07cfe, 0x3d63d05dd5, 0x70d7301f83]
7RGCN5R5: max4=210 max5=140 max6=27 err5=0.308866 err6=1.023173 avg5=0.039775 avg6=0.822074 GEN=[0x3ee0cb9765, 0x77d383abea, 0xe5e59752f4, 0x89dbbe04e1, 0x5bb5f889c2]
JEL5LPLD: max4=210 max5=145 max6=26 err5=0.316665 err6=0.999249 avg5=0.039890 avg6=0.819330 GEN=[0x9baa5ae6ad, 0x7f06a1ec7a, 0xf44d437cdd, 0xaad8165d93, 0x1db02c1f0f]
QKDE8B2P: max4=210 max5=132 max6=23 err5=0.287547 err6=1.108732 avg5=0.045631 avg6=0.872560 GEN=[0xd51ae42c59, 0xe875c8589b, 0x98bb14951f, 0x7926b92a17, 0xf21f66d127]
TOPE82T9: max4=210 max5=130 max6=24 err5=0.315105 err6=1.014894 avg5=0.050710 avg6=0.806433 GEN=[0xee32e40ba9, 0x9e77c81272, 0x7eff14a1ed, 0xf7eeb943da, 0xadcf66a6bd]
CVBKC0SF: max4=210 max5=145 max6=25 err5=0.309386 err6=1.034409 avg5=0.037325 avg6=0.862234 GEN=[0x67d746038f, 0xc5ec1c023e, 0xc9ca2c8175, 0xdb944d82c3, 0xff288f80a6]
OENKJL8B: max4=210 max5=137 max6=29 err5=0.323425 err6=0.991366 avg5=0.050003 avg6=0.785827 GEN=[0xc3af49d50b, 0xcf0e178e16, 0xdc5c2f1925, 0xfaf84ab24a, 0xbda281e1b4]
UCA7HVUN: max4=210 max5=140 max6=27 err5=0.287027 err6=1.123890 avg5=0.039593 avg6=0.824798 GEN=[0xf31478ffd7, 0xae28e5dea7, 0x1e43cb1c6e, 0x36c512b8dc, 0x67c8b57191]
O2IM6DP1: max4=210 max5=121 max6=32 err5=0.327585 err6=0.995260 avg5=0.063879 avg6=0.728596 GEN=[0xc0a5633721, 0xc91a566b62, 0xda34ac77e4, 0xfc3b4ccee8, 0xba661dbcf0]
NHU34U1C: max4=210 max5=122 max6=25 err5=0.300546 err6=1.093295 avg5=0.051560 avg6=0.880988 GEN=[0xbc7c32782c, 0x3aea645458, 0x7586c80c99, 0xe14d84991b, 0x8a9999321f]
7C1H8CG7: max4=210 max5=128 max6=28 err5=0.332265 err6=0.991608 avg5=0.066673 avg6=0.786433 GEN=[0x3b03143207, 0x7604b8612e, 0xe64964e65c, 0x8ed0596db1, 0x5fe0a6ff4b]
0L3CQ0ER: max4=210 max5=126 max6=23 err5=0.327585 err6=1.010568 avg5=0.061068 avg6=0.846927 GEN=[0x546cd01db, 0xcd8e839f, 0x199998237, 0x331b78167, 0x633ff02ce]
LVBPGJ7A: max4=210 max5=125 max6=24 err5=0.337984 err6=0.987533 avg5=0.067949 avg6=0.823951 GEN=[0xafd7984cea, 0x1dedb4bdd4, 0x31cbf97b81, 0x639576d622, 0xc7287d0d64]
423KD102: max4=210 max5=132 max6=21 err5=0.335385 err6=0.997757 avg5=0.056900 avg6=0.828343 GEN=[0x2087468402, 0x410c1d0804, 0x82182e9008, 0x4c3049a010, 0x927287c009]
F61FU607: max4=210 max5=138 max6=28 err5=0.336944 err6=1.003506 avg5=0.043583 avg6=0.800996 GEN=[0x7982ff1807, 0xf305eab00e, 0xae0951e01c, 0x1e50336411, 0x36e0666c0b]
A74KMPMC: max4=210 max5=144 max6=27 err5=0.340584 err6=0.993639 avg5=0.035574 avg6=0.748539 GEN=[0x51c94b66cc, 0xa39012ecb8, 0xf20257d59, 0x14524a5e9b, 0x22e4809c3f]
C330FK8I: max4=210 max5=133 max6=24 err5=0.337984 err6=1.003029 avg5=0.056816 avg6=0.810041 GEN=[0x60c607d112, 0xc18c0f060d, 0xcb180a893a, 0xde3001925d, 0xfe720321b3]
CA654JHJ: max4=210 max5=131 max6=31 err5=0.335905 err6=1.011992 avg5=0.049531 avg6=0.765919 GEN=[0x628c524e33, 0xc518a43d6f, 0xc871487ade, 0xd8b214d4b5, 0xf936290d43]
721L961L: max4=210 max5=129 max6=24 err5=0.343704 err6=0.989388 avg5=0.063078 avg6=0.784180 GEN=[0x3883549835, 0x7104393043, 0xe20866e086, 0x8c10cd650c, 0x5a618eee18]
M6F7ED6G: max4=210 max5=123 max6=22 err5=0.337984 err6=1.007063 avg5=0.077138 avg6=0.810322 GEN=[0xb19e7734d0, 0x2b3cee6989, 0x562bc8f712, 0xa64715cf2d, 0xeccbb3f7a]
VE91L1SM: max4=210 max5=128 max6=24 err5=0.330185 err6=1.032566 avg5=0.044089 avg6=0.851704 GEN=[0xfb921a8796, 0xbf24218a25, 0x3c5a43116a, 0x72f48622d4, 0xe5bb0c40a1]
A0DOKLUT: max4=210 max5=141 max6=28 err5=0.341104 err6=1.001693 avg5=0.045346 avg6=0.769848 GEN=[0x501b8a57dd, 0xa035908eb3, 0x83bb1186f, 0x1027f230de, 0x201f746195]
1OS63HF3: max4=210 max5=143 max6=30 err5=0.340584 err6=1.006061 avg5=0.049115 avg6=0.786993 GEN=[0xe3861c5e3, 0x1662c32fc6, 0x26d7865aac, 0x47ed9c1478, 0x85cbbca8d9]
13HUITK7: max4=210 max5=124 max6=25 err5=0.337984 err6=1.017170 avg5=0.052493 avg6=0.838008 GEN=[0x8e3e97687, 0x119756cc2e, 0x232c3d3c5c, 0x460a6ef891, 0x8654c9d50b]
HMQHQRPF: max4=210 max5=124 max6=25 err5=0.337984 err6=1.017170 avg5=0.052493 avg6=0.838008 GEN=[0x8db51d6f2f, 0x597abeff7e, 0xb2a769dff5, 0x2d1e579ee3, 0x507caf38e6]
90MO7GVU: max4=210 max5=141 max6=27 err5=0.345784 err6=0.994723 avg5=0.051982 avg6=0.765223 GEN=[0x482d83c3fe, 0x900b9726f5, 0x6815be48e3, 0xd029f8b5c6, 0xe80375eb8c]
UOF4D6A1: max4=210 max5=127 max6=30 err5=0.345784 err6=0.996116 avg5=0.065481 avg6=0.785526 GEN=[0xf61e469941, 0xae7c8d3282, 0x1eeb0ee024, 0x37c699e448, 0x65cd27ec90]
4LFGIQEI: max4=210 max5=132 max6=27 err5=0.330705 err6=1.043175 avg5=0.061027 avg6=0.848233 GEN=[0x255f0969d2, 0x40fc96f78d, 0x81ab2d4e3a, 0x4b06debd7d, 0x960da9fad3]
U6EIKFDG: max4=210 max5=136 max6=22 err5=0.339544 err6=1.019546 avg5=0.050046 avg6=0.816333 GEN=[0xf19d2a3db0, 0xab38d0fb49, 0x1e23a157b2, 0x3657d20e6d, 0x66ed3419fa]
HA2SM76J: max4=210 max5=126 max6=28 err5=0.344224 err6=1.006319 avg5=0.062992 avg6=0.815784 GEN=[0x8a85cb1cd3, 0x5d0912b98f, 0xb050b5731e, 0x28a16a4735, 0x511250af63]
PU8VN3E2: max4=210 max5=127 max6=30 err5=0.345264 err6=1.004149 avg5=0.061723 avg6=0.799937 GEN=[0xcf91fb8dc2, 0xdd61739b84, 0xf8d2773228, 0xb9a4ee6170, 0x3b1bc8e6c9]
FRKHCPR7: max4=210 max5=125 max6=25 err5=0.346304 err6=1.002521 avg5=0.067356 avg6=0.798780 GEN=[0x7ee9166767, 0xf7c2bc6fee, 0xadc56cfefc, 0x19c85ddcf1, 0x3390af9dcb]
L9G71J3F: max4=210 max5=132 max6=25 err5=0.341624 err6=1.016489 avg5=0.054158 avg6=0.799381 GEN=[0xaa6070cc6f, 0x1c92e13cde, 0x3365c27995, 0x669b145703, 0xc774b80f26]
JHEMQSFQ: max4=210 max5=136 max6=26 err5=0.335905 err6=1.036857 avg5=0.060058 avg6=0.834459 GEN=[0x9c5d6d71fa, 0x7af85ec7dd, 0xf5a2a9aeb3, 0xa95747d86f, 0x1aac1f14de]
BAEPSN0S: max4=210 max5=123 max6=25 err5=0.328625 err6=1.062861 avg5=0.069291 avg6=0.840092 GEN=[0x5a9d9e5c1c, 0xb539b89c11, 0x2863f5b80b, 0x50977b7016, 0xa12c72c405]
VR5MEL0Q: max4=210 max5=122 max6=25 err5=0.308866 err6=1.134219 avg5=0.057698 avg6=0.876640 GEN=[0xfecb67541a, 0xbfd45e0c1d, 0x3de8a89813, 0x71c345b00f, 0xe3841b601e]
OT2171UR: max4=210 max5=127 max6=26 err5=0.347344 err6=1.011530 avg5=0.053863 avg6=0.797858 GEN=[0xc7441387db, 0xccc8270abf, 0xdbd04e1077, 0xffa088a0c7, 0xbd5305c18e]
LV1VDTN7: max4=210 max5=122 max6=26 err5=0.322905 err6=1.090236 avg5=0.077209 avg6=0.836045 GEN=[0xafc3f6f6e7, 0x1dc57d4cee, 0x31c87ebddc, 0x6390e9fb91, 0xc721c7d62b]
3H0CNEID: max4=210 max5=120 max6=29 err5=0.352024 err6=1.002160 avg5=0.066377 avg6=0.809706 GEN=[0x1c40cbba4d, 0x32c183f1ba, 0x658197475d, 0xc141be2fb3, 0xca81f8da6f]
1D53K23E: max4=210 max5=123 max6=25 err5=0.354624 err6=0.998625 avg5=0.064332 avg6=0.825097 GEN=[0xb4a3a086e, 0x16946090dc, 0x2768c12191, 0x44c382430b, 0x83c5942736]
NVP4JT2S: max4=210 max5=120 max6=21 err5=0.351504 err6=1.010071 avg5=0.069844 avg6=0.850759 GEN=[0xbff249f45c, 0x3df687cc91, 0x71ff0f3d0b, 0xe3ae9afa16, 0x8f0f21d525]
HG8JFKQO: max4=210 max5=138 max6=27 err5=0.357224 err6=0.993976 avg5=0.047792 avg6=0.807714 GEN=[0x8c1137d358, 0x5a60ff07b9, 0xb493ea8a7b, 0x2b655191ff, 0x569a3323d7]
8TQS8LQN: max4=210 max5=122 max6=25 err5=0.356704 err6=1.000638 avg5=0.067180 avg6=0.820567 GEN=[0x4775c45757, 0x84fb180fa7, 0x4be6b49a6e, 0x979f6931fc, 0x6d7c56e3d1]
DJ616MDU: max4=210 max5=132 max6=24 err5=0.352024 err6=1.018911 avg5=0.048097 avg6=0.819061 GEN=[0x6ccc1359be, 0xd3d8261755, 0xefb04c2ba3, 0x9d728cd266, 0x78f70d85ec]
B7IR8PTJ: max4=210 max5=121 max6=25 err5=0.354624 err6=1.014902 avg5=0.070924 avg6=0.812798 GEN=[0x59e5b467b3, 0xb39bf86e6f, 0x2f3574fdfe, 0x547a795fd5, 0xa2e6e69ea3]
L02JKINK: max4=210 max5=137 max6=21 err5=0.359823 err6=1.000430 avg5=0.045791 avg6=0.832642 GEN=[0xa8053a4af4, 0x1808f0b4e1, 0x3011e169c2, 0x6021527784, 0xc012344e28]
V81RJNHH: max4=210 max5=130 max6=25 err5=0.351504 err6=1.024311 avg5=0.055203 avg6=0.827706 GEN=[0xfa03b9de31, 0xbc05f79d6b, 0x3a497f3ad6, 0x74907af0a5, 0xe360e1c54a]
2TBIF38A: max4=210 max5=131 max6=26 err5=0.365023 err6=0.989903 avg5=0.059217 avg6=0.773525 GEN=[0x1757278d0a, 0x24ecdf1a14, 0x43cbaab121, 0x8795d1e242, 0x4d693365a4]
FHSAKE8S: max4=210 max5=125 max6=22 err5=0.360343 err6=1.003534 avg5=0.058524 avg6=0.822468 GEN=[0x7c78aa391c, 0xf2e340f211, 0xad9611452b, 0x196c222e56, 0x328a4459a5]
Found 64 generators.
Best 16 performers for lengths of up to 196 characters:
U1PIRGA7: max4=500 max5=500 max6=13 err5=0.000000 err6=15.346780 avg5=0.000000 avg6=1.545813 GEN=[0xf0732dc147, 0xa8b6dfa68e, 0x193fabc83c, 0x322fd3b451, 0x640f37688b]
AJ4RJKVB: max4=500 max5=500 max6=13 err5=0.000000 err6=15.346780 avg5=0.000000 avg6=1.564299 GEN=[0x54c9b9d3eb, 0xa3d1f786f6, 0xfa17f08e5, 0x15527a91ca, 0x20e4e1a394]
VRSOEBL7: max4=500 max5=123 max6=26 err5=0.282867 err6=1.025742 avg5=0.047074 avg6=0.817349 GEN=[0xfef9872ea7, 0xbfe39e586e, 0x3dd7b894dc, 0x71edf5a991, 0xe38b7b530b]
FKFN98KS: max4=500 max5=130 max6=26 err5=0.289107 err6=1.009149 avg5=0.042873 avg6=0.831064 GEN=[0x7d1f74a29c, 0xf07c794031, 0xa8aae6a44b, 0x1907cd4896, 0x320d1eb505]
DEE30B1D: max4=500 max5=129 max6=29 err5=0.296906 err6=0.995276 avg5=0.049757 avg6=0.764013 GEN=[0x6b9c302c2d, 0xd73860585a, 0xec62c0149d, 0x9ad7802913, 0x7dad90520f]
FVK7D3HH: max4=500 max5=121 max6=21 err5=0.292227 err6=1.012096 avg5=0.048907 avg6=0.859303 GEN=[0x7fe8768e31, 0xf5c2ed196b, 0xa9c5ceb2d6, 0x1b8919e0a5, 0x3710b7e54a]
JKHOGKBA: max4=500 max5=127 max6=22 err5=0.274547 err6=1.080168 avg5=0.042294 avg6=0.860180 GEN=[0x9d2388516a, 0x78579486d4, 0xf0adb908a1, 0xa90bf69142, 0x1a157d2284]
3EJU3UBP: max4=500 max5=138 max6=26 err5=0.297946 err6=1.015542 avg5=0.033664 avg6=0.841875 GEN=[0x1ba7e1f979, 0x371f5356db, 0x647c360cbf, 0xc2ea6c1957, 0xcd86ccb287]
KVDQ5Q0V: max4=500 max5=126 max6=32 err5=0.311466 err6=0.995733 avg5=0.056371 avg6=0.776661 GEN=[0xa7dba2e81f, 0xdf5d57417, 0x11fb3a4c07, 0x23a6f0bc0e, 0x471fe1781c]
0S7SR3A6: max4=500 max5=145 max6=21 err5=0.289107 err6=1.073390 avg5=0.035648 avg6=0.857036 GEN=[0x70fcd8d46, 0x45d1f9a8c, 0x2f8bbb038, 0x5a363e059, 0x15657649b]
5155TAUI: max4=500 max5=146 max6=23 err5=0.315105 err6=0.991495 avg5=0.038737 avg6=0.778061 GEN=[0x284a5eabd2, 0x5094a9d2ad, 0xa12947847a, 0xa021f08dd, 0x14042a9193]
RJ7I0PVJ: max4=500 max5=125 max6=29 err5=0.317185 err6=0.995053 avg5=0.054974 avg6=0.719604 GEN=[0xdccf2067f3, 0xfbdcd06eef, 0xbfb9a07cfe, 0x3d63d05dd5, 0x70d7301f83]
7RGCN5R5: max4=500 max5=140 max6=27 err5=0.308866 err6=1.023173 avg5=0.039775 avg6=0.822074 GEN=[0x3ee0cb9765, 0x77d383abea, 0xe5e59752f4, 0x89dbbe04e1, 0x5bb5f889c2]
QKDE8B2P: max4=500 max5=132 max6=23 err5=0.287547 err6=1.108732 avg5=0.045631 avg6=0.872560 GEN=[0xd51ae42c59, 0xe875c8589b, 0x98bb14951f, 0x7926b92a17, 0xf21f66d127]
O2IM6DP1: max4=500 max5=121 max6=32 err5=0.327585 err6=0.995260 avg5=0.063879 avg6=0.728596 GEN=[0xc0a5633721, 0xc91a566b62, 0xda34ac77e4, 0xfc3b4ccee8, 0xba661dbcf0]
NHU34U1C: max4=500 max5=122 max6=25 err5=0.300546 err6=1.093295 avg5=0.051560 avg6=0.880988 GEN=[0xbc7c32782c, 0x3aea645458, 0x7586c80c99, 0xe14d84991b, 0x8a9999321f]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment