Private/Shamir/Split-SecretSharingShamirSecret.ps1
|
function Split-SecretSharingShamirSecret { <# .SYNOPSIS Splits a byte-array secret into Shamir share points over GF(256). .DESCRIPTION Constructs a degree-(Threshold-1) polynomial that passes through the secret (at SecretXCoordinate) and any caller-supplied FixedPoint anchors (e.g. a SLIP-0039 digest share), then returns one share point per requested XCoordinate: the first (Threshold - 1 - FixedPoint.Count) of them are literal cryptographically random byte arrays, and the remainder are derived from the random and fixed points via Lagrange interpolation. This is the same construction the SLIP-0039 reference implementation uses - it is equivalent to generating random polynomial coefficients directly, since a degree-(Threshold-1) polynomial is uniquely determined by any Threshold points on it. When Threshold is 1, every requested share is simply the secret itself, and no randomness or FixedPoint anchors are used or accepted (matching SLIP-0039's treatment of the threshold=1 case, where no digest share is needed either). #> [CmdletBinding()] [OutputType([PSObject[]], [System.Object[]])] param( [Parameter(Mandatory)] [byte[]]$Secret, [Parameter(Mandatory)] [byte]$SecretXCoordinate, [Parameter(Mandatory)] [ValidateRange(1, 255)] [int]$Threshold, [Parameter(Mandatory)] [byte[]]$XCoordinate, [PSObject[]]$FixedPoint = @() ) $allXCoordinates = @($SecretXCoordinate) + @($FixedPoint | ForEach-Object { $_.X }) + $XCoordinate $uniqueCount = ($allXCoordinates | Select-Object -Unique | Measure-Object).Count if ($uniqueCount -ne $allXCoordinates.Count) { throw 'Invalid request. SecretXCoordinate, FixedPoint, and XCoordinate values must all be distinct.' } if ($Threshold -eq 1) { if ($FixedPoint.Count -gt 0) { throw 'A threshold of 1 does not use FixedPoint anchors.' } return , @($XCoordinate | ForEach-Object { [PSCustomObject]@{ X = $_; Value = $Secret } }) } $randomCount = $Threshold - 1 - $FixedPoint.Count if ($randomCount -lt 0) { throw 'Threshold is too small for the number of FixedPoint anchors supplied.' } if ($randomCount -gt $XCoordinate.Count) { throw 'Not enough XCoordinate values requested to hold the random shares this threshold requires.' } $shares = New-Object System.Collections.Generic.List[PSObject] for ($i = 0; $i -lt $randomCount; $i++) { $shares.Add([PSCustomObject]@{ X = $XCoordinate[$i] Value = Get-SecretSharingRandomByte -Length $Secret.Length }) } $basePoint = @($shares.ToArray()) + @($FixedPoint) + @([PSCustomObject]@{ X = $SecretXCoordinate; Value = $Secret }) for ($i = $randomCount; $i -lt $XCoordinate.Count; $i++) { $shares.Add([PSCustomObject]@{ X = $XCoordinate[$i] Value = Invoke-SecretSharingShamirInterpolation -Point $basePoint -X $XCoordinate[$i] }) } return , $shares.ToArray() } |