Private/Password/Get-SecretSharingRandomAlphabetByte.ps1
|
function Get-SecretSharingRandomAlphabetByte { <# .SYNOPSIS Returns Length cryptographically random bytes, each drawn uniformly from Alphabet. .DESCRIPTION Alphabet sizes are rarely a power of two, so mapping a random byte onto Alphabet with a plain modulo would be biased toward its low end (256 mod Alphabet.Length leftover values map to fewer alphabet entries than the rest). Uses rejection sampling instead: any random byte at or above the largest multiple of Alphabet.Length that still fits in a byte is discarded and redrawn, so every kept byte maps to each alphabet entry with exactly equal probability. #> [CmdletBinding()] [OutputType([byte[]], [System.Object[]])] param( [Parameter(Mandatory)] [ValidateCount(1, 256)] [byte[]]$Alphabet, [Parameter(Mandatory)] [ValidateRange(1, [int]::MaxValue)] [int]$Length ) $rejectionThreshold = 256 - (256 % $Alphabet.Length) $result = [byte[]]::new($Length) for ($i = 0; $i -lt $Length; $i++) { do { $candidate = (Get-SecretSharingRandomByte -Length 1)[0] } while ($candidate -ge $rejectionThreshold) $result[$i] = $Alphabet[$candidate % $Alphabet.Length] } return , $result } |