Private/Share/ConvertFrom-SecretSharingShareWord.ps1
|
function ConvertFrom-SecretSharingShareWord { <# .SYNOPSIS Unpacks a SLIP-0039 share's header fields and value from its data words. .DESCRIPTION The inverse of ConvertTo-SecretSharingShareWord. Index must be the share's data words only - the header and value, with the trailing 3-word checksum already stripped and verified by the caller (Test-SecretSharingChecksum), exactly mirroring the boundary ConvertTo-SecretSharingShareWord produces. The number of padding bits in the first value word is derived from Index's length rather than passed in, the same way the reference implementation derives it from the mnemonic's total word count. A value that doesn't fit in the resulting byte count - which only happens if the padding bits were not all zero, i.e. a corrupted or invalid share - raises an error rather than silently truncating. #> [CmdletBinding()] [OutputType([PSCustomObject])] param( [Parameter(Mandatory)] [int[]]$Index ) $minimumValueWordCount = [int][System.Math]::Ceiling(128 / 10.0) if ($Index.Count -lt (4 + $minimumValueWordCount)) { throw "Invalid share data. Expected at least $(4 + $minimumValueWordCount) words, got $($Index.Count)." } $paddingBitLength = (10 * ($Index.Count - 4)) % 16 if ($paddingBitLength -gt 8) { throw 'Invalid share data length.' } $idExpInt = ConvertFrom-SecretSharingWordIndex -Index $Index[0..1] -RadixBit 10 $iterationExponent = [int]($idExpInt % 16) $remaining = [System.Numerics.BigInteger]::Divide($idExpInt, 16) $extendableBit = [int]($remaining % 2) $identifier = [int]([System.Numerics.BigInteger]::Divide($remaining, 2)) $paramInt = ConvertFrom-SecretSharingWordIndex -Index $Index[2..3] -RadixBit 10 $memberThreshold = [int]($paramInt % 16) + 1 $remaining = [System.Numerics.BigInteger]::Divide($paramInt, 16) $memberIndex = [int]($remaining % 16) $remaining = [System.Numerics.BigInteger]::Divide($remaining, 16) $groupCount = [int]($remaining % 16) + 1 $remaining = [System.Numerics.BigInteger]::Divide($remaining, 16) $groupThreshold = [int]($remaining % 16) + 1 $remaining = [System.Numerics.BigInteger]::Divide($remaining, 16) $groupIndex = [int]$remaining if ($groupCount -lt $groupThreshold) { throw 'Invalid share data. Group threshold cannot be greater than group count.' } $valueWord = $Index[4..($Index.Count - 1)] $valueBitLength = (10 * $valueWord.Count) - $paddingBitLength $valueByteCount = [int][System.Math]::Ceiling($valueBitLength / 8.0) $valueInt = ConvertFrom-SecretSharingWordIndex -Index $valueWord -RadixBit 10 $value = ConvertFrom-SecretSharingBigIntegerToByte -Value $valueInt -Length $valueByteCount return [PSCustomObject]@{ Identifier = $identifier Extendable = [bool]$extendableBit IterationExponent = $iterationExponent GroupIndex = $groupIndex GroupThreshold = $groupThreshold GroupCount = $groupCount MemberIndex = $memberIndex MemberThreshold = $memberThreshold Value = $value } } |