Tests/Private/Field.Tests.ps1

BeforeDiscovery {
    Import-Module (Join-Path $PSScriptRoot '../../Posh-SecretSharing.psd1') -Force
}

Describe 'Private/Field' -Tag Unit {
    InModuleScope 'Posh-SecretSharing' {
        BeforeAll {
            # Independent reference GF(256) multiplication (peasant multiplication with the
            # standard AES reduction constant 0x1B), used to cross-check the module's
            # exp/log-table implementation without trusting the same tables on both sides.
            function Get-ReferenceGF256Product {
                param([byte]$A, [byte]$B)

                $product = 0
                for ($i = 0; $i -lt 8; $i++) {
                    if ($B -band 1) {
                        $product = $product -bxor $A
                    }
                    $highBitSet = $A -band 0x80
                    $A = ($A -shl 1) -band 0xFF
                    if ($highBitSet) {
                        $A = $A -bxor 0x1B
                    }
                    $B = $B -shr 1
                }

                return [byte]$product
            }
        }

        Describe 'Get-SecretSharingFieldTable' {
            It 'returns a 255-entry Exp table and a 256-entry Log table' {
                $table = Get-SecretSharingFieldTable
                $table.Exp.Count | Should -Be 255
                $table.Log.Count | Should -Be 256
            }

            It 'is internally consistent: Exp[Log[v]] = v for every nonzero byte value' {
                $table = Get-SecretSharingFieldTable
                for ($v = 1; $v -le 255; $v++) {
                    $table.Exp[$table.Log[$v]] | Should -Be $v
                }
            }

            It 'returns the same cached instance on repeated calls' {
                (Get-SecretSharingFieldTable) | Should -Be (Get-SecretSharingFieldTable)
            }
        }

        Describe 'Invoke-SecretSharingFieldAddition' {
            It 'is its own inverse (a + a = 0)' {
                Invoke-SecretSharingFieldAddition -A 200 -B 200 | Should -Be 0
            }

            It 'behaves like XOR' {
                Invoke-SecretSharingFieldAddition -A 0x53 -B 0xCA | Should -Be (0x53 -bxor 0xCA)
            }

            It 'is the identity when adding zero' {
                Invoke-SecretSharingFieldAddition -A 77 -B 0 | Should -Be 77
            }
        }

        Describe 'Invoke-SecretSharingFieldMultiplication' {
            It 'returns 0 when either operand is 0' {
                Invoke-SecretSharingFieldMultiplication -A 0 -B 200 | Should -Be 0
                Invoke-SecretSharingFieldMultiplication -A 123 -B 0 | Should -Be 0
            }

            It 'is the identity when multiplying by 1' {
                Invoke-SecretSharingFieldMultiplication -A 91 -B 1 | Should -Be 91
            }

            It 'is commutative' {
                $r1 = Invoke-SecretSharingFieldMultiplication -A 45 -B 200
                $r2 = Invoke-SecretSharingFieldMultiplication -A 200 -B 45
                $r1 | Should -Be $r2
            }

            It 'matches an independent GF(256) reference implementation for every byte pair in a random sample' {
                $random = [System.Random]::new(1337)
                for ($n = 0; $n -lt 500; $n++) {
                    $a = [byte]$random.Next(0, 256)
                    $b = [byte]$random.Next(0, 256)
                    Invoke-SecretSharingFieldMultiplication -A $a -B $b | Should -Be (Get-ReferenceGF256Product -A $a -B $b)
                }
            }
        }

        Describe 'Invoke-SecretSharingFieldDivision' {
            It 'throws when dividing by 0' {
                { Invoke-SecretSharingFieldDivision -A 10 -B 0 } | Should -Throw
            }

            It 'returns 0 when the numerator is 0' {
                Invoke-SecretSharingFieldDivision -A 0 -B 55 | Should -Be 0
            }

            It 'is the inverse of multiplication' {
                $product = Invoke-SecretSharingFieldMultiplication -A 77 -B 200
                Invoke-SecretSharingFieldDivision -A $product -B 200 | Should -Be 77
            }

            It 'divides a value by itself to get 1' {
                Invoke-SecretSharingFieldDivision -A 33 -B 33 | Should -Be 1
            }
        }
    }
}