Skip to content

Commit

Permalink
fix: using 2^256 for the vrf denominator (#445)
Browse files Browse the repository at this point in the history
* fix: using 2^256 for the vrf denominator

* test: fixing a broken test
  • Loading branch information
b00f committed Apr 24, 2023
1 parent 54434f4 commit 51f0e3d
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 37 deletions.
14 changes: 7 additions & 7 deletions sortition/proof.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package sortition

import (
"crypto/rand"
"encoding/hex"
"fmt"

"github.com/pactus-project/pactus/crypto/bls"
"github.com/pactus-project/pactus/util"
)

type Proof [48]byte
Expand All @@ -29,10 +31,8 @@ func ProofFromBytes(data []byte) (Proof, error) {
}

func GenerateRandomProof() Proof {
p := Proof{}
_, err := rand.Read(p[:])
if err != nil {
panic(err)
}
return p
sig := bls.GenerateTestSigner().SignData(
util.Int64ToSlice(util.RandInt64(0)))
proof, _ := ProofFromBytes(sig.Bytes())
return proof
}
40 changes: 22 additions & 18 deletions sortition/sortition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import (
)

func TestEvaluation(t *testing.T) {
prv, err := bls.PrivateKeyFromString("SECRET1PPUYUZ0Y8T97CUDAYQU9EAE0HNJ76Q9QYLK4DCT5W5EAJY5C6268SHYQ740")
prv, err := bls.PrivateKeyFromString("SECRET1P838V87AW42JS8YWLYYK0AYFJQ9445VR72H23D6LR7GEJ8KW9UQ0QVE8WHE")
assert.NoError(t, err)
signer := crypto.NewSigner(prv)
seed, _ := VerifiableSeedFromString("b63179137423ab2da8279d7aa3726d7ad05ae7d3ab3f744db0a9a719d12a720e72dc1d1e9222360243007f2f4adf7009")
proof, _ := ProofFromString("8034f4738cbb57a9e64943239973350d29c3a303d63afa1c60c28462f87b558adb8cf4ade28fdc9262bd4407f13b4ca4")
proof, _ := ProofFromString("8cb689ec126465ddadd32493b71dc7ee3bfa2ef5a0a0f4b9b8aa777fb915a5f88def3305a3579e97b96ac862a6d67316")

t.Run("Total stake is zero", func(t *testing.T) {
threshold := util.RandInt64(1 * 1e14)
Expand All @@ -33,36 +33,40 @@ func TestEvaluation(t *testing.T) {
require.False(t, ok)
})

t.Run("Invalid proof (Infinity public key)", func(t *testing.T) {
total := util.RandInt64(1 * 1e14)
t.Run("OK!", func(t *testing.T) {
total := int64(1 * 1e14)

pub, _ := bls.PublicKeyFromString("public1pcqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqglnhh9")
proof, _ := ProofFromString("C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
ok, proof2 := EvaluateSortition(seed, signer, total, total/100)
require.True(t, ok)
require.Equal(t, proof, proof2)

require.False(t, VerifyProof(seed, proof, pub, total, total))
require.True(t, VerifyProof(seed, proof, signer.PublicKey(), total, total/100))
require.False(t, VerifyProof(seed, proof, signer.PublicKey(), total, 0))
require.False(t, VerifyProof(seed, GenerateRandomProof(), signer.PublicKey(), total, total/10))
require.False(t, VerifyProof(seed, Proof{}, signer.PublicKey(), total, total/10))
require.False(t, VerifyProof(GenerateRandomSeed(), proof, signer.PublicKey(), total, total/10))
})
}

func TestInvalidProof(t *testing.T) {
t.Run("Invalid proof (Zero proof)", func(t *testing.T) {
total := util.RandInt64(1 * 1e14)
seed := GenerateRandomSeed()

pub, _ := bls.GenerateTestKeyPair()
proof, _ := ProofFromString("C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
proof, _ := ProofFromString("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")

require.False(t, VerifyProof(seed, proof, pub, total, total))
})

t.Run("OK!", func(t *testing.T) {
total := int64(1 * 1e14)
t.Run("Invalid proof (Infinity proof)", func(t *testing.T) {
total := util.RandInt64(1 * 1e14)
seed := GenerateRandomSeed()

ok, proof2 := EvaluateSortition(seed, signer, total, total/100)
require.True(t, ok)
require.Equal(t, proof, proof2)
pub, _ := bls.GenerateTestKeyPair()
proof, _ := ProofFromString("C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")

require.True(t, VerifyProof(seed, proof, signer.PublicKey(), total, total/100))
require.False(t, VerifyProof(seed, proof, signer.PublicKey(), total, 0))
require.False(t, VerifyProof(seed, GenerateRandomProof(), signer.PublicKey(), total, total/10))
require.False(t, VerifyProof(seed, Proof{}, signer.PublicKey(), total, total/10))
require.False(t, VerifyProof(GenerateRandomSeed(), proof, signer.PublicKey(), total, total/10))
require.False(t, VerifyProof(seed, proof, pub, total, total))
})
}

Expand Down
14 changes: 8 additions & 6 deletions sortition/vrf.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,15 @@ import (
"github.com/pactus-project/pactus/crypto"
"github.com/pactus-project/pactus/crypto/bls"
"github.com/pactus-project/pactus/crypto/hash"
"github.com/pactus-project/pactus/util"
)

var denominator *big.Int

func init() {
denominator = &big.Int{}
denominator.SetString("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16)
}

// evaluate returns a random number between 0 and max with the proof.
func evaluate(seed VerifiableSeed, signer crypto.Signer, max uint64) (index uint64, proof Proof) {
signData := append(seed[:], signer.PublicKey().Bytes()...)
Expand Down Expand Up @@ -41,17 +47,13 @@ func verify(seed VerifiableSeed, publicKey crypto.PublicKey, proof Proof, max ui
func getIndex(proof Proof, max uint64) uint64 {
h := hash.CalcHash(proof[:])

rnd64 := util.SliceToUint64(h.Bytes())

// construct the numerator and denominator for normalizing the proof uint
bigRnd := &big.Int{}
bigMax := &big.Int{}
denominator := &big.Int{}
numerator := &big.Int{}

bigRnd.SetUint64(rnd64)
bigRnd.SetBytes(h.Bytes())
bigMax.SetUint64(max)
denominator.SetUint64(util.MaxUint64)

numerator = numerator.Mul(bigRnd, bigMax)

Expand Down
12 changes: 6 additions & 6 deletions sortition/vrf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,17 @@ func TestRandomUint64(t *testing.T) {
func TestGetIndex(t *testing.T) {
// Total: 1000000

// proof: 1719b896ec1cc66a0f44c4bf90890d988e341cb2c1a808907780af844c854291536c12fdaef9a526bb7ef80da17c0b03
// proofH: a7b8166584387f4ea76f9caa0969bd6b0bb8df4c3bb8e87f8b6e4dad62bf3359
// proof: 0x1719b896ec1cc66a0f44c4bf90890d988e341cb2c1a808907780af844c854291536c12fdaef9a526bb7ef80da17c0b03
// proofH: 0xa7b8166584387f4ea76f9caa0969bd6b0bb8df4c3bb8e87f8b6e4dad62bf3359
//
// 0x4e7f38846516b8a7 * 1000000 / 0xffffffffffffffff = 306628.73489662957134845753
// proofH * 1000000 / denominator = 655152.7021258341
proof1, _ := ProofFromString("1719b896ec1cc66a0f44c4bf90890d988e341cb2c1a808907780af844c854291536c12fdaef9a526bb7ef80da17c0b03")
assert.Equal(t, getIndex(proof1, 1*1e6), uint64(306628))
assert.Equal(t, getIndex(proof1, 1*1e6), uint64(655152))

// proof: 45180defab2daae377977bf09dcdd7d76ff4fc96d1b50cc8ac5a1601c0522fb11641c3ed0fefd4b1e1808c498d699396
// proofH: 80212979d1de1ca4ce1258fc0be66a4453b3804e64a5ca8d95f7def2c291c7fe
//
// 0xa41cded179292180 * 1000000 / 0xffffffffffffffff = 641065.52709668964549350137
// proofH * 1000000 / denominator = 500506.0121928797
proof2, _ := ProofFromString("45180defab2daae377977bf09dcdd7d76ff4fc96d1b50cc8ac5a1601c0522fb11641c3ed0fefd4b1e1808c498d699396")
assert.Equal(t, getIndex(proof2, 1*1e6), uint64(641065))
assert.Equal(t, getIndex(proof2, 1*1e6), uint64(500506))
}

0 comments on commit 51f0e3d

Please sign in to comment.