github.com/onflow/flow-go/crypto@v0.24.8/bls12381_utils_test.go (about)

     1  //go:build relic
     2  // +build relic
     3  
     4  package crypto
     5  
     6  import (
     7  	crand "crypto/rand"
     8  	"encoding/hex"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestDeterministicKeyGen(t *testing.T) {
    16  	// 2 keys generated with the same seed should be equal
    17  	seed := make([]byte, KeyGenSeedMinLen)
    18  	n, err := crand.Read(seed)
    19  	require.Equal(t, n, KeyGenSeedMinLen)
    20  	require.NoError(t, err)
    21  	sk1, err := GeneratePrivateKey(BLSBLS12381, seed)
    22  	require.Nil(t, err)
    23  	sk2, err := GeneratePrivateKey(BLSBLS12381, seed)
    24  	require.Nil(t, err)
    25  	assert.True(t, sk1.Equals(sk2), "private keys should be equal")
    26  }
    27  
    28  // test the deterministicity of the relic PRG (used by the DKG polynomials)
    29  func TestPRGseeding(t *testing.T) {
    30  	blsInstance.reInit()
    31  	// 2 scalars generated with the same seed should be equal
    32  	seed := make([]byte, KeyGenSeedMinLen)
    33  	n, err := crand.Read(seed)
    34  	require.Equal(t, n, KeyGenSeedMinLen)
    35  	require.NoError(t, err)
    36  	// 1st scalar (wrapped in a private key)
    37  	err = seedRelic(seed)
    38  	require.Nil(t, err)
    39  	var sk1 prKeyBLSBLS12381
    40  	randZr(&sk1.scalar)
    41  	// 2nd scalar (wrapped in a private key)
    42  	err = seedRelic(seed)
    43  	require.Nil(t, err)
    44  	var sk2 prKeyBLSBLS12381
    45  	randZr(&sk2.scalar)
    46  	// compare the 2 scalars (by comparing the private keys)
    47  	assert.True(t, sk1.Equals(&sk2), "private keys should be equal")
    48  }
    49  
    50  // G1 and G2 scalar multiplication
    51  func BenchmarkScalarMultG1G2(b *testing.B) {
    52  	blsInstance.reInit()
    53  	seed := make([]byte, securityBits/8)
    54  	_, err := crand.Read(seed)
    55  	require.NoError(b, err)
    56  	_ = seedRelic(seed)
    57  	var expo scalar
    58  	randZr(&expo)
    59  
    60  	// G1 generator multiplication
    61  	b.Run("G1 gen", func(b *testing.B) {
    62  		var res pointG1
    63  		b.ResetTimer()
    64  		for i := 0; i < b.N; i++ {
    65  			generatorScalarMultG1(&res, &expo)
    66  		}
    67  		b.StopTimer()
    68  	})
    69  
    70  	// G1 base point multiplication
    71  	b.Run("G1 generic", func(b *testing.B) {
    72  		var res pointG1
    73  		b.ResetTimer()
    74  		for i := 0; i < b.N; i++ {
    75  			genericScalarMultG1(&res, &expo)
    76  		}
    77  		b.StopTimer()
    78  	})
    79  
    80  	// G2 base point multiplication
    81  	b.Run("G2 gen", func(b *testing.B) {
    82  		var res pointG2
    83  		b.ResetTimer()
    84  		for i := 0; i < b.N; i++ {
    85  			generatorScalarMultG2(&res, &expo)
    86  		}
    87  		b.StopTimer()
    88  	})
    89  }
    90  
    91  // Sanity-check of the map-to-G1 with regards to the IETF draft hash-to-curve
    92  func TestMapToG1(t *testing.T) {
    93  
    94  	// test vectors from https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#appendix-J.9.1
    95  	dst := []byte("QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_")
    96  
    97  	msgs := [][]byte{
    98  		[]byte{},
    99  		[]byte("abc"),
   100  		[]byte("abcdef0123456789"),
   101  		[]byte("q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"),
   102  		[]byte("a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
   103  	}
   104  
   105  	expectedPointString := []string{
   106  		"052926add2207b76ca4fa57a8734416c8dc95e24501772c814278700eed6d1e4e8cf62d9c09db0fac349612b759e79a1",
   107  		"03567bc5ef9c690c2ab2ecdf6a96ef1c139cc0b2f284dca0a9a7943388a49a3aee664ba5379a7655d3c68900be2f6903",
   108  		"11e0b079dea29a68f0383ee94fed1b940995272407e3bb916bbf268c263ddd57a6a27200a784cbc248e84f357ce82d98",
   109  		"15f68eaa693b95ccb85215dc65fa81038d69629f70aeee0d0f677cf22285e7bf58d7cb86eefe8f2e9bc3f8cb84fac488",
   110  		"082aabae8b7dedb0e78aeb619ad3bfd9277a2f77ba7fad20ef6aabdc6c31d19ba5a6d12283553294c1825c4b3ca2dcfe",
   111  	}
   112  
   113  	for i, msg := range msgs {
   114  		pointBytes := hashToG1Bytes(msg, dst)
   115  
   116  		expectedPointBytes, err := hex.DecodeString(expectedPointString[i])
   117  		require.NoError(t, err)
   118  		// skip comparing the first 3 bits that depend on the serialization scheme
   119  		pointBytes[0] = (expectedPointBytes[0] & 0xE0) | (pointBytes[0] & 0x1F)
   120  		assert.Equal(t, expectedPointBytes, pointBytes, "map to G1 should match the IETF draft test vector")
   121  	}
   122  }
   123  
   124  // Hashing to G1 bench
   125  func BenchmarkMapToG1(b *testing.B) {
   126  	blsInstance.reInit()
   127  	input := make([]byte, expandMsgOutput)
   128  	for i := 0; i < len(input); i++ {
   129  		input[i] = byte(i)
   130  	}
   131  	b.ResetTimer()
   132  	for i := 0; i < b.N; i++ {
   133  		mapToG1(input)
   134  	}
   135  	b.StopTimer()
   136  }
   137  
   138  // test subgroup membership check in G1 and G2
   139  func TestSubgroupCheck(t *testing.T) {
   140  	blsInstance.reInit()
   141  	// seed Relic PRG
   142  	seed := make([]byte, securityBits/8)
   143  	_, err := crand.Read(seed)
   144  	require.NoError(t, err)
   145  	_ = seedRelic(seed)
   146  
   147  	t.Run("G1", func(t *testing.T) {
   148  		var p pointG1
   149  		randPointG1(&p) // point in G1
   150  		res := checkMembershipG1(&p)
   151  		assert.Equal(t, res, int(valid))
   152  		randPointG1Complement(&p) // point in E1\G1
   153  		res = checkMembershipG1(&p)
   154  		assert.Equal(t, res, int(invalid))
   155  	})
   156  
   157  	t.Run("G2", func(t *testing.T) {
   158  		var p pointG2
   159  		randPointG2(&p) // point in G2
   160  		res := checkMembershipG2(&p)
   161  		assert.Equal(t, res, int(valid))
   162  		randPointG2Complement(&p) // point in E2\G2
   163  		res = checkMembershipG2(&p)
   164  		assert.Equal(t, res, int(invalid))
   165  	})
   166  }
   167  
   168  // subgroup membership check bench
   169  func BenchmarkSubgroupCheck(b *testing.B) {
   170  	blsInstance.reInit()
   171  
   172  	b.Run("G1", func(b *testing.B) {
   173  		var p pointG1
   174  		randPointG1(&p)
   175  		b.ResetTimer()
   176  		for i := 0; i < b.N; i++ {
   177  			_ = checkMembershipG1(&p) // G1
   178  		}
   179  		b.StopTimer()
   180  	})
   181  
   182  	b.Run("G2", func(b *testing.B) {
   183  		var p pointG2
   184  		randPointG2(&p)
   185  		b.ResetTimer()
   186  		for i := 0; i < b.N; i++ {
   187  			_ = checkMembershipG2(&p) // G2
   188  		}
   189  		b.StopTimer()
   190  	})
   191  }