summaryrefslogtreecommitdiff
path: root/crypto/vrf_test.go
blob: dc91653e7e4b1f83c73ce7fccddeaee0d2d82e63 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// Copyright (C) 2019-2021 Algorand, Inc.
// This file is part of go-algorand
//
// go-algorand is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// go-algorand is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with go-algorand.  If not, see <https://www.gnu.org/licenses/>.

package crypto

import (
	"crypto/rand"
	"encoding/hex"
	"testing"
)

func mustDecode(t *testing.T, out []byte, hexIn string) {
	_, err := hex.Decode(out, []byte(hexIn))
	if err != nil {
		t.Errorf("hex decode error: %v", err)
	}
}

func testVector(t *testing.T, skHex, pkHex, alphaHex, piHex, betaHex string) {
	var seed [32]byte
	// our "secret keys" are 64 bytes: the spec's 32-byte "secret keys" (which we call the "seed") followed by the 32-byte precomputed public key
	// so the 32-byte "SK" in the test vectors is not directly decoded into a VrfPrivkey, it instead has to go through VrfKeypairFromSeed()

	var pk VrfPubkey
	var alpha []byte
	var pi VrfProof
	var beta VrfOutput

	// Decode hex
	mustDecode(t, seed[:], skHex)
	mustDecode(t, pk[:], pkHex)
	mustDecode(t, pi[:], piHex)
	mustDecode(t, beta[:], betaHex)
	// alpha is variable-length
	alpha = make([]byte, hex.DecodedLen(len(alphaHex)))
	mustDecode(t, alpha, alphaHex)

	pkTest, sk := VrfKeygenFromSeed(seed)
	if pkTest != pk {
		t.Errorf("Computed public key does not match the test vector")
	}

	piTest, ok := sk.proveBytes(alpha)
	if !ok {
		t.Errorf("Failed to produce a proof")
	}
	if piTest != pi {
		t.Errorf("Proof produced by Prove() does not match the test vector")
	}

	ok, betaTest := pk.verifyBytes(pi, alpha)
	if !ok {
		t.Errorf("Verify() fails on proof from the test vector")
	}
	if betaTest != beta {
		t.Errorf("VRF output does not match test vector")
	}
}

// ECVRF-ED25519-SHA512-Elligator2 test vectors from: https://www.ietf.org/id/draft-irtf-cfrg-vrf-03.txt appendix A.4
func TestVRFTestVectors(t *testing.T) {
	testVector(t,
		"9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60", //sk
		"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a", //pk
		"", // alpha
		"b6b4699f87d56126c9117a7da55bd0085246f4c56dbc95d20172612e9d38e8d7ca65e573a126ed88d4e30a46f80a666854d675cf3ba81de0de043c3774f061560f55edc256a787afe701677c0f602900", // pi
		"5b49b554d05c0cd5a5325376b3387de59d924fd1e13ded44648ab33c21349a603f25b84ec5ed887995b33da5e3bfcb87cd2f64521c4c62cf825cffabbe5d31cc",                                 // beta
	)

	testVector(t,
		"4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", //sk
		"3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", //pk
		"72", // alpha
		"ae5b66bdf04b4c010bfe32b2fc126ead2107b697634f6f7337b9bff8785ee111200095ece87dde4dbe87343f6df3b107d91798c8a7eb1245d3bb9c5aafb093358c13e6ae1111a55717e895fd15f99f07", // pi
		"94f4487e1b2fec954309ef1289ecb2e15043a2461ecc7b2ae7d4470607ef82eb1cfa97d84991fe4a7bfdfd715606bc27e2967a6c557cfb5875879b671740b7d8",                                 // beta
	)
}

func BenchmarkVrfVerify(b *testing.B) {
	pks := make([]VrfPubkey, b.N)
	strs := make([][]byte, b.N)
	proofs := make([]VrfProof, b.N)
	for i := 0; i < b.N; i++ {
		var sk VrfPrivkey
		pks[i], sk = VrfKeygen()
		strs[i] = make([]byte, 100)
		_, err := rand.Read(strs[i])
		if err != nil {
			panic(err)
		}
		var ok bool
		proofs[i], ok = sk.proveBytes(strs[i])
		if !ok {
			panic("Failed to construct VRF proof")
		}
	}

	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		_, _ = pks[i].verifyBytes(proofs[i], strs[i])
	}
}