Modulo-bias-free sampling
Naïve approaches use `random32 % charsetSize`, which is biased when charsetSize doesn't divide 2^32 evenly. The generator uses rejection sampling against the largest multiple of charsetSize that fits in a uint32 — discarded values trigger a re-draw — so the distribution is exactly uniform.