tricrypt/tlep/shuffle/int_benchmark.go

103 lines
2.1 KiB
Go
Raw Normal View History

2024-06-04 18:19:11 +02:00
package shuffle
import (
"crypto/rand"
"fmt"
"log"
"math/big"
)
const (
n = 5
samplesNum = 300000
)
func factorial(n int) *big.Int {
return factorial_body(n, big.NewInt(1))
}
func factorial_body(n int, acc *big.Int) *big.Int {
if n == 0 {
return acc
}
acc.Mul(acc, big.NewInt(int64(n)))
return factorial_body(n-1, acc)
}
func ChiSquare(obs, exp []float64) (float64, error) {
if len(obs) != len(exp) {
return 0, BENCHMARK_LEN_DN_MATCH
}
var result float64
result = 0
for i, a := range obs {
b := exp[i]
if a == 0 && b == 0 {
continue
}
result += (a - b) * (a - b) / b
}
return result, nil
}
func bigChiSquare(observed []int, expected *big.Float) *big.Float {
chiSquare := big.NewFloat(0)
for _, obs := range observed {
obsFloat := big.NewFloat(float64(obs))
diff := new(big.Float).Sub(obsFloat, expected)
squaredDiff := new(big.Float).Mul(diff, diff)
term := new(big.Float).Quo(squaredDiff, expected)
chiSquare.Add(chiSquare, term)
}
return chiSquare
}
func GetBenchmarkN() int {
return n
}
func GetBenchmarkForShuffle[T Numeric](alg ShuffleNumericAlg[T], keyLen int, fullDebug bool) error {
perms := map[[n]T]int{}
for i := 0; i < samplesNum; i++ {
if fullDebug {
log.Printf("Running %d sample\n", i)
}
arr := [n]T{zeroValue[T]()}
for i := 0; i < n; i++ {
arr[i] = T(i)
}
//
dummyKey := make([]byte, keyLen)
keyN, err := rand.Read(dummyKey)
if err != nil {
return err
}
if keyN != len(dummyKey) {
return BENCHMARK_INTERNAL_ERROR
}
alg(arr[:], dummyKey)
//
perms[arr]++
}
fact := factorial(n)
factFloat := new(big.Float).SetInt(fact)
// Calculate expected value
samplesFloat := big.NewFloat(float64(samplesNum))
expectedBig := new(big.Float).Quo(samplesFloat, factFloat)
if fullDebug {
log.Printf("expectedBig is %f\n", expectedBig)
log.Printf("factorial is %d\n", factorial(n))
}
observed := make([]int, 0, len(perms))
for _, count := range perms {
// log.Printf("Getting count from perm = %d\n", count)
observed = append(observed, count)
}
val := bigChiSquare(observed, expectedBig)
fmt.Printf("Chi-Square value: %s\n", val.Text('f', 10))
return nil
}