From 77c09653e999222f804e3a36ede26c8fc90ec319 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 3 Feb 2022 08:59:32 -0500 Subject: [PATCH 1/5] Removed hard-coded constant in `sortition.go`. Remove a hardcoded constant in sortition.go which was used as the denominator in determining the selection ratio. This clarifies what the maximum possible output size is of the output VRF based on the SHA algorithm used to generate it. Due to the usage of C src code, a simple `go test -v ./data/committee/sortition/` cannot be executed without the proper configurations. However, circle CI should be able to execute the unit tests automatically and verify the changes. --- data/committee/sortition/sortition.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/data/committee/sortition/sortition.go b/data/committee/sortition/sortition.go index f8a38179d8..bb32ecf91c 100644 --- a/data/committee/sortition/sortition.go +++ b/data/committee/sortition/sortition.go @@ -23,7 +23,9 @@ package sortition // #include "sortition.h" import "C" import ( + "fmt" "math/big" + "strings" "github.com/algorand/go-algorand/crypto" ) @@ -33,15 +35,16 @@ func Select(money uint64, totalMoney uint64, expectedSize float64, vrfOutput cry binomialN := float64(money) binomialP := expectedSize / float64(totalMoney) - t := &big.Int{} - t.SetBytes(vrfOutput[:]) - precision := uint(8 * (len(vrfOutput) + 1)) - max, b, err := big.ParseFloat("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0, precision, big.ToNearestEven) + maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2+1)) + max, b, err := big.ParseFloat(maxFloatString, 0, precision, big.ToNearestEven) if b != 16 || err != nil { panic("failed to parse big float constant in sortition") } + t := &big.Int{} + t.SetBytes(vrfOutput[:]) + h := big.Float{} h.SetPrec(precision) h.SetInt(t) From d27eabd1b1d9b12221f103e8e9fd0ea064efe934 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 3 Feb 2022 09:04:02 -0500 Subject: [PATCH 2/5] Remove the +1 --- data/committee/sortition/sortition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/committee/sortition/sortition.go b/data/committee/sortition/sortition.go index bb32ecf91c..26825b5e55 100644 --- a/data/committee/sortition/sortition.go +++ b/data/committee/sortition/sortition.go @@ -36,7 +36,7 @@ func Select(money uint64, totalMoney uint64, expectedSize float64, vrfOutput cry binomialP := expectedSize / float64(totalMoney) precision := uint(8 * (len(vrfOutput) + 1)) - maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2+1)) + maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2)) max, b, err := big.ParseFloat(maxFloatString, 0, precision, big.ToNearestEven) if b != 16 || err != nil { panic("failed to parse big float constant in sortition") From 9c41c548243b402bb342723e912924b7a78d4d63 Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Thu, 3 Feb 2022 09:12:13 -0500 Subject: [PATCH 3/5] Create a local variable rather than recompute it each time --- data/committee/sortition/sortition.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/committee/sortition/sortition.go b/data/committee/sortition/sortition.go index 26825b5e55..cd52ed51fc 100644 --- a/data/committee/sortition/sortition.go +++ b/data/committee/sortition/sortition.go @@ -30,13 +30,14 @@ import ( "github.com/algorand/go-algorand/crypto" ) +var maxFloatString string = fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2)) + // Select runs the sortition function and returns the number of time the key was selected func Select(money uint64, totalMoney uint64, expectedSize float64, vrfOutput crypto.Digest) uint64 { binomialN := float64(money) binomialP := expectedSize / float64(totalMoney) precision := uint(8 * (len(vrfOutput) + 1)) - maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2)) max, b, err := big.ParseFloat(maxFloatString, 0, precision, big.ToNearestEven) if b != 16 || err != nil { panic("failed to parse big float constant in sortition") From b31c83392c5809933d6eeee1008a825214d9969d Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 4 Feb 2022 10:45:49 -0500 Subject: [PATCH 4/5] Moved maxFloat generation into an init function --- data/committee/sortition/sortition.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/data/committee/sortition/sortition.go b/data/committee/sortition/sortition.go index cd52ed51fc..88e032ee0f 100644 --- a/data/committee/sortition/sortition.go +++ b/data/committee/sortition/sortition.go @@ -22,6 +22,7 @@ package sortition // #include // #include "sortition.h" import "C" + import ( "fmt" "math/big" @@ -30,19 +31,15 @@ import ( "github.com/algorand/go-algorand/crypto" ) -var maxFloatString string = fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2)) +const precision = uint(8 * (crypto.DigestSize + 1)) + +var maxFloat *big.Float // Select runs the sortition function and returns the number of time the key was selected func Select(money uint64, totalMoney uint64, expectedSize float64, vrfOutput crypto.Digest) uint64 { binomialN := float64(money) binomialP := expectedSize / float64(totalMoney) - precision := uint(8 * (len(vrfOutput) + 1)) - max, b, err := big.ParseFloat(maxFloatString, 0, precision, big.ToNearestEven) - if b != 16 || err != nil { - panic("failed to parse big float constant in sortition") - } - t := &big.Int{} t.SetBytes(vrfOutput[:]) @@ -51,7 +48,18 @@ func Select(money uint64, totalMoney uint64, expectedSize float64, vrfOutput cry h.SetInt(t) ratio := big.Float{} - cratio, _ := ratio.Quo(&h, max).Float64() + cratio, _ := ratio.Quo(&h, maxFloat).Float64() return uint64(C.sortition_binomial_cdf_walk(C.double(binomialN), C.double(binomialP), C.double(cratio), C.uint64_t(money))) } + +func init() { + var b int + var err error + maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2)) + maxFloat, b, err = big.ParseFloat(maxFloatString, 0, precision, big.ToNearestEven) + if b != 16 || err != nil { + err = fmt.Errorf("failed to parse big float constant in sortition : %w", err) + panic(err) + } +} From 1645da67a801796c1a60de1f54879eadc4d8556c Mon Sep 17 00:00:00 2001 From: Daniel Olshansky Date: Fri, 4 Feb 2022 10:50:19 -0500 Subject: [PATCH 5/5] Replace the *2 and with --- data/committee/sortition/sortition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/committee/sortition/sortition.go b/data/committee/sortition/sortition.go index 88e032ee0f..5b8300add6 100644 --- a/data/committee/sortition/sortition.go +++ b/data/committee/sortition/sortition.go @@ -56,7 +56,7 @@ func Select(money uint64, totalMoney uint64, expectedSize float64, vrfOutput cry func init() { var b int var err error - maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("f", crypto.DigestSize*2)) + maxFloatString := fmt.Sprintf("0x%s", strings.Repeat("ff", crypto.DigestSize)) maxFloat, b, err = big.ParseFloat(maxFloatString, 0, precision, big.ToNearestEven) if b != 16 || err != nil { err = fmt.Errorf("failed to parse big float constant in sortition : %w", err)