forked from onflow/flow-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
spock.go
106 lines (94 loc) · 3.62 KB
/
spock.go
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
//go:build relic
// +build relic
package crypto
// SPoCK design based on the BLS signature scheme.
// BLS is using BLS12-381 curve and the same settings in bls.go.
// #cgo CFLAGS: -g -Wall -std=c99
// #cgo LDFLAGS: -L${SRCDIR}/relic/build/lib -l relic_s
// #include "bls_include.h"
import "C"
import (
"fmt"
"github.com/onflow/flow-go/crypto/hash"
)
// SPOCKProve generates a spock poof for data under the private key sk.
//
// The function returns:
// - (false, nilHasherError) if the hasher is nil
// - (false, invalidHasherSiseError) if hasher's output size is not 128 bytes
// - (nil, notBLSKeyError) if input key is not a BLS key
// - (nil, error) if an unexpected error occurs
// - (proof, nil) otherwise
func SPOCKProve(sk PrivateKey, data []byte, kmac hash.Hasher) (Signature, error) {
if sk.Algorithm() != BLSBLS12381 {
return nil, notBLSKeyError
}
// BLS signature of data
return sk.Sign(data, kmac)
}
// SPOCKVerifyAgainstData verifies a SPoCK proof is generated from the given data
// and the prover's public key.
//
// This is a simple BLS signature verifictaion of the proof under the input data
// and public key.
//
// The function returns:
// - (false, notBLSKeyError) if input key is not a BLS key
// - (false, nilHasherError) if the hasher is nil
// - (false, invalidHasherSiseError) if hasher's output size is not 128 bytes
// - (false, error) if an unexpected error occurs
// - (validity, nil) otherwise
func SPOCKVerifyAgainstData(pk PublicKey, proof Signature, data []byte, kmac hash.Hasher) (bool, error) {
if pk.Algorithm() != BLSBLS12381 {
return false, notBLSKeyError
}
// BLS verification of data
return pk.Verify(proof, data, kmac)
}
// SPOCKVerify checks whether two couples of (SPoCK proof, public key) are consistent.
//
// Two (SPoCK proof, public key) couples are consistent if there exists a message such
// that each proof could be generated from the message and the private key corresponding
// to the respective public key.
//
// If the input proof slices have an invalid length or fail to deserialize into curve
// points, the function returns false without an error.
// The proofs membership checks in G1 are included in the verifcation.
//
// The function does not check the public keys membership in G2 because it is
// guaranteed by the package. However, the caller must make sure each input public key has been
// verified against a proof of possession prior to calling this function.
//
// The function returns:
// - (false, notBLSKeyError) if at least one key is not a BLS key.
// - (false, error) if an unexpected error occurs.
// - (validity, nil) otherwise
func SPOCKVerify(pk1 PublicKey, proof1 Signature, pk2 PublicKey, proof2 Signature) (bool, error) {
blsPk1, ok1 := pk1.(*pubKeyBLSBLS12381)
blsPk2, ok2 := pk2.(*pubKeyBLSBLS12381)
if !(ok1 && ok2) {
return false, notBLSKeyError
}
if len(proof1) != signatureLengthBLSBLS12381 || len(proof2) != signatureLengthBLSBLS12381 {
return false, nil
}
// if pk1 and proof1 are identities of their respective groups, any couple (pk2, proof2) would
// verify the pairing equality which breaks the unforgeability of the SPoCK scheme. This edge case
// is avoided by not allowing an identity pk1. Similarly, an identity pk2 is not allowed.
if blsPk1.isIdentity || blsPk2.isIdentity {
return false, nil
}
// verify the spock proof using the secret data
verif := C.bls_spock_verify((*C.ep2_st)(&blsPk1.point),
(*C.uchar)(&proof1[0]),
(*C.ep2_st)(&blsPk2.point),
(*C.uchar)(&proof2[0]))
switch verif {
case invalid:
return false, nil
case valid:
return true, nil
default:
return false, fmt.Errorf("SPoCK verification failed")
}
}