maraudir/common/lcg.go

52 lines
1.1 KiB
Go

package common
import (
"crypto/rand"
"encoding/binary"
"fmt"
"math/big"
"net"
)
func iptouint(ip net.IP) uint32 {
ip = ip.To4()
return uint32(ip[0])<<24 | uint32(ip[1])<<16 | uint32(ip[2])<<8 | uint32(ip[3])
}
func toip(num uint32) string {
return fmt.Sprintf("%d.%d.%d.%d",
(num>>24)&255,
(num>>16)&255,
(num>>8)&255,
num&255)
}
func seed() int64 {
var n int64
if err := binary.Read(rand.Reader, binary.LittleEndian, &n); err != nil {
return 1337
}
return n
}
// per-cidr linear congruential generator for efficient randomized target ip ordering, ty claude
func LCG(cidr string, out chan<- string) {
// lcg constants
const a uint64 = 1664525
const c uint64 = 1013904223
_, ipnet, _ := net.ParseCIDR(cidr)
start := iptouint(ipnet.IP)
ones, bits := ipnet.Mask.Size()
addrcount := new(big.Int).Lsh(big.NewInt(1), uint(bits-ones))
x := uint64(seed()) ^ uint64(start) // seed for unique randomization per execution
m := uint64(addrcount.Uint64())
for i := uint64(0); i < m; i++ {
x = (a*x + c) % (1 << 32) // mod of full 32bit addr count
ip := toip(uint32((x % m) + uint64(start)))
out <- ip
}
}