03-15-2018, 01:51 PM
(This post was last modified: 03-16-2018, 01:56 AM by mrfancypants.)
I think I got the rounding in the 589 generator correct now.
should be
The bit with __builtin_clzll it is mainly there to make sure that uint64_t to double rounding is performed correctly, which seems to fail without it on occasion. I'm not sure of the exact form this needs to take, I have about 70 collected passwords of the 589 type, of those only one fails without the if(), and all pass with the if().
And the parallel with the 599 generator is much clearer now. In the 599, the last line becomes
It may be safer to rewrite the whole thing in pure integers, so as not to rely on the behavior of the floating-point unit. It should go something like this (warning: completely untested code, don't have GCC here)
Code:
void genpass589(uint32_t x, unsigned char *psk) {
static const char CHARSET[] = "abcdefghijkmnpqrstuvwxyz23456789#%+=?";
int i;
uint64_t one = x * 465661287.5245797; // thank you mrfancypants for finding this number
should be
Code:
void genpass589(uint32_t x, unsigned char *psk) {
static const char CHARSET[] = "abcdefghijkmnpqrstuvwxyz23456789#%+=?";
int i;
uint64_t y = x;
y += y << 31;
unsigned long idx = 63 - __builtin_clzll(y);
if (idx > 52)
{
y >>= idx - 52 - 1;
y = (y >> 1) + (y & 1);
y <<= idx - 52;
}
uint64_t one = double(y) * (double(1e18) / (1ull << 62));
The bit with __builtin_clzll it is mainly there to make sure that uint64_t to double rounding is performed correctly, which seems to fail without it on occasion. I'm not sure of the exact form this needs to take, I have about 70 collected passwords of the 589 type, of those only one fails without the if(), and all pass with the if().
And the parallel with the 599 generator is much clearer now. In the 599, the last line becomes
Code:
uint64_t one = double(y) * 2;
It may be safer to rewrite the whole thing in pure integers, so as not to rely on the behavior of the floating-point unit. It should go something like this (warning: completely untested code, don't have GCC here)
Code:
uint64_t do_rounding(uint64_t x)
{
int idx = 63 - __builtin_clzll(x);
if (idx > 52)
{
x >>= idx - 52 - 1;
x = (x >> 1) + (x & 1);
x <<= idx - 52;
}
return x;
}
void genpass589(uint32_t x, unsigned char *psk) {
static const char CHARSET[] = "abcdefghijkmnpqrstuvwxyz23456789#%+=?";
int i;
uint64_t y = x;
y = y + (y << 31);
y = do_rounding(y);
y = (uint64_t) ( ((__int128)y * (__int128)1000000000000000000ull) >> 61 );
do_rounding(y);
uint64_t one = y>>1;