// For each input modulus 'x' and remainderTree parent 'y', compute z = (y%(x*x))/x; gcd(z, x) func lowmemRemainderTreeFinal(input, moduli chan *gmp.Int, output chan<- Collision) { defer close(output) tmp := new(gmp.Int) for y := range input { for i := 0; i < 2; i++ { modulus, ok := <-moduli if !ok { log.Print("Odd number of moduli? (should only see this once)") continue } tmp.Mul(modulus, modulus) tmp.Rem(y, tmp) tmp.Quo(tmp, modulus) if tmp.GCD(nil, nil, tmp, modulus).BitLen() != 1 { q := new(gmp.Int).Quo(modulus, tmp) output <- Collision{ Modulus: modulus, P: tmp, Q: q, } tmp = new(gmp.Int) } } y.Clear() } }
// For each input modulus 'x' and remainderTree parent 'y', compute z = (y%(x*x))/x; gcd(z, x) func remainderTreeFinal(lastLevel, moduli []*gmp.Int, output chan<- Collision, wg *sync.WaitGroup, start, step int) { tmp := new(gmp.Int) for i := start; i < len(moduli); i += step { modulus := moduli[i] y := lastLevel[i/2] tmp.Mul(modulus, modulus) tmp.Rem(y, tmp) tmp.Quo(tmp, modulus) if tmp.GCD(nil, nil, tmp, modulus).BitLen() != 1 { q := new(gmp.Int).Quo(modulus, tmp) output <- Collision{ Modulus: modulus, P: tmp, Q: q, } tmp = new(gmp.Int) } } wg.Done() }
// This performs the GCD of the product of all previous moduli with the current one. // This uses around double the memory (minus quite a lot of overhead), and identifies // problematic input in O(n) time, but has to do another O(n) scan for each collision // to figure get the private key back. // If there are no collisions, this algorithm isn't parallel at all. // If we get a GCD that is the same as the modulus, we do a manual scan for either colliding Q or identical moduli // If we get a GCD lower than the modulus, we have one private key, then do a manual scan for others. func MulAccumGCD(moduli []*gmp.Int, collisions chan<- Collision) { accum := gmp.NewInt(1) gcd := new(gmp.Int) var wg sync.WaitGroup for i, modulus := range moduli { gcd.GCD(nil, nil, accum, modulus) if gcd.BitLen() != 1 { wg.Add(1) if gcd.Cmp(modulus) == 0 { go findGCD(&wg, moduli, i, collisions) continue } else { go findDivisors(&wg, moduli, i, gcd, collisions) gcd = new(gmp.Int) } } accum.Mul(accum, modulus) } wg.Wait() close(collisions) }