package captcha import ( "fmt" "strings" ) const prngMask = 0xFFFFFFFF // prng generates a deterministic lowercase-hex string of length chars from // seed, matching the Cap.js widget PRNG exactly: FNV-1a seeds a 32-bit state, // then xorshift32 produces the hex output. Must stay byte-for-byte compatible // with the widget or solutions will never verify. func prng(seed string, length int) string { state := fnv1a(seed) var b strings.Builder for b.Len() < length { state ^= (state << 13) & prngMask state ^= state >> 17 state ^= (state << 5) & prngMask state &= prngMask fmt.Fprintf(&b, "%08x", state) } return b.String()[:length] } // fnv1a returns the 32-bit FNV-1a hash of s. Iterates over runes (code points) // to match the JS/Python reference (which use charCodeAt / ord). func fnv1a(s string) uint32 { var h uint32 = 2166136261 for _, ch := range s { h ^= uint32(ch) h = (h + (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24)) & prngMask } return h }