github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/crypto/vrf/vrf_test.go (about)

     1  package vrf
     2  
     3  import (
     4  	"crypto/ed25519"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  )
     9  
    10  const (
    11  	SEEDBYTES = ed25519.SeedSize
    12  )
    13  
    14  var (
    15  	Message = []string{
    16  		"0B3BE52BF10F431AB07A44E9F89BBDD886B5B177A08FD54066694213930C9B2E",
    17  		"EB0068756CA1BA8A497055958A50A71AA11E7F9A3CA967F8B3F7D6AF4F67911E",
    18  		"BC77D2E540543BE2112972706EE88B006471E385A1A39E9D11B47F787E2A49AA",
    19  		"F67D0305ABC12664F9F037C55C92CED3FFD6CB5875364E6C4A221534D77B7566",
    20  		"AB609319AFD5EDCE91B3540EF77D83D96688C46CCC55175D8A4E3801F6F17239",
    21  		"0E3921D46CFC6CEBAD33558F1BA38447FC9B3AF0BA034C1FD1DD5481E04C8D54",
    22  		"7D59D1B9B556CC9434A1F0E5350103F3D41BF4C846A1B967B4E3443BF153DF58",
    23  		"C1952358B51634232B39FB2BE2E42105319CE812DFEBD9117CCE9A78F2E6BC44",
    24  		"999228C220CF8BA79B9815E6DB5D2F3C52A73E6CC314DB147A1E6FBD0BCDCC96",
    25  		"B91F62DBCCA98A4453E5DF5AFE2EC521179D400F58B0174237D8D990CDBEFB8A",
    26  	}
    27  )
    28  
    29  func proveAndVerify(t *testing.T, privateKey, publicKey []byte) (bool, error) {
    30  	message := []byte("hello, world")
    31  	proof, err1 := Prove(privateKey, message)
    32  	require.NoError(t, err1)
    33  	require.NotNil(t, proof)
    34  
    35  	output, err2 := ProofToHash(proof)
    36  	require.NoError(t, err2)
    37  	require.NotNil(t, output)
    38  
    39  	return Verify(publicKey, proof, message)
    40  }
    41  
    42  func TestProveAndVerify(t *testing.T) {
    43  	require.NotNil(t, defaultVrf)
    44  	t.Logf("defaultVrf:%T", defaultVrf)
    45  	secret := [SEEDBYTES]byte{}
    46  	privateKey := ed25519.NewKeyFromSeed(secret[:])
    47  	publicKey := privateKey.Public().(ed25519.PublicKey)
    48  
    49  	verified, err := proveAndVerify(t, privateKey, publicKey)
    50  	require.NoError(t, err)
    51  	require.True(t, verified)
    52  }
    53  
    54  func BenchmarkProveAndVerify(b *testing.B) {
    55  	secret := [SEEDBYTES]byte{}
    56  	privateKey := ed25519.NewKeyFromSeed(secret[:])
    57  	publicKey := privateKey.Public().(ed25519.PublicKey)
    58  	message := []byte("hello, world")
    59  
    60  	var proof []byte
    61  	var err error
    62  	b.Run("VRF prove", func(b *testing.B) {
    63  		b.ResetTimer()
    64  		for i := 0; i < b.N; i++ {
    65  			proof, err = Prove(privateKey, message)
    66  		}
    67  	})
    68  	require.NoError(b, err)
    69  	b.Run("VRF verify", func(b *testing.B) {
    70  		b.ResetTimer()
    71  		_, err = Verify(publicKey, proof, message)
    72  	})
    73  	require.NoError(b, err)
    74  }
    75  
    76  // Test avalanche effect for VRF prove hash
    77  // https://en.wikipedia.org/wiki/Avalanche_effect
    78  //
    79  // Test the quality of the VRF prove hash generated
    80  // by the external library(r2ishiguro, libsodium, and etc.) as a pseudo-random number
    81  func TestAvalancheEffect(t *testing.T) {
    82  	secret := [SEEDBYTES]byte{}
    83  	privateKey := ed25519.NewKeyFromSeed(secret[:])
    84  
    85  	for _, messageString := range Message {
    86  		message := []byte(messageString)
    87  
    88  		proof, err := Prove(privateKey, message)
    89  		require.NoError(t, err)
    90  		hash, err := ProofToHash(proof)
    91  		require.NoError(t, err)
    92  
    93  		n := len(message) * 8
    94  		for i := 0; i < n; i++ {
    95  			old := message[i/8]
    96  			message[i/8] ^= byte(uint(1) << (uint(i) % uint(8))) // modify 1 bit
    97  
    98  			proof2, err := Prove(privateKey, message)
    99  			require.NoError(t, err)
   100  			hash2, err := ProofToHash(proof2)
   101  			require.NoError(t, err)
   102  
   103  			// test
   104  			require.InDelta(t, 0.5, getAvalanche(hash, hash2), 0.13)
   105  
   106  			// restore old value
   107  			message[i/8] = old
   108  		}
   109  	}
   110  }
   111  
   112  func getAvalanche(a []byte, b []byte) (avalanche float32) {
   113  	var count int
   114  	for i := 0; i < len(a); i++ {
   115  		for j := 0; j < 8; j++ {
   116  			if (a[i] & byte(uint(1)<<uint(j))) == (b[i] & byte(uint(1)<<uint(j))) {
   117  				count++
   118  			}
   119  		}
   120  	}
   121  	avalanche = float32(count) / float32(len(a)*8)
   122  	return
   123  }