github.com/onflow/flow-go/crypto@v0.24.8/spock.go (about) 1 //go:build relic 2 // +build relic 3 4 package crypto 5 6 // SPoCK design based on the BLS signature scheme. 7 // BLS is using BLS12-381 curve and the same settings in bls.go. 8 9 // #cgo CFLAGS: -g -Wall -std=c99 10 // #cgo LDFLAGS: -L${SRCDIR}/relic/build/lib -l relic_s 11 // #include "bls_include.h" 12 import "C" 13 import ( 14 "fmt" 15 16 "github.com/onflow/flow-go/crypto/hash" 17 ) 18 19 // SPOCKProve generates a spock poof for data under the private key sk. 20 // 21 // The function returns: 22 // - (false, nilHasherError) if the hasher is nil 23 // - (false, invalidHasherSiseError) if hasher's output size is not 128 bytes 24 // - (nil, notBLSKeyError) if input key is not a BLS key 25 // - (nil, error) if an unexpected error occurs 26 // - (proof, nil) otherwise 27 func SPOCKProve(sk PrivateKey, data []byte, kmac hash.Hasher) (Signature, error) { 28 if sk.Algorithm() != BLSBLS12381 { 29 return nil, notBLSKeyError 30 } 31 32 // BLS signature of data 33 return sk.Sign(data, kmac) 34 } 35 36 // SPOCKVerifyAgainstData verifies a SPoCK proof is generated from the given data 37 // and the prover's public key. 38 // 39 // This is a simple BLS signature verifictaion of the proof under the input data 40 // and public key. 41 // 42 // The function returns: 43 // - (false, notBLSKeyError) if input key is not a BLS key 44 // - (false, nilHasherError) if the hasher is nil 45 // - (false, invalidHasherSiseError) if hasher's output size is not 128 bytes 46 // - (false, error) if an unexpected error occurs 47 // - (validity, nil) otherwise 48 func SPOCKVerifyAgainstData(pk PublicKey, proof Signature, data []byte, kmac hash.Hasher) (bool, error) { 49 if pk.Algorithm() != BLSBLS12381 { 50 return false, notBLSKeyError 51 } 52 // BLS verification of data 53 return pk.Verify(proof, data, kmac) 54 } 55 56 // SPOCKVerify checks whether two couples of (SPoCK proof, public key) are consistent. 57 // 58 // Two (SPoCK proof, public key) couples are consistent if there exists a message such 59 // that each proof could be generated from the message and the private key corresponding 60 // to the respective public key. 61 // 62 // If the input proof slices have an invalid length or fail to deserialize into curve 63 // points, the function returns false without an error. 64 // The proofs membership checks in G1 are included in the verifcation. 65 // 66 // The function does not check the public keys membership in G2 because it is 67 // guaranteed by the package. However, the caller must make sure each input public key has been 68 // verified against a proof of possession prior to calling this function. 69 // 70 // The function returns: 71 // - (false, notBLSKeyError) if at least one key is not a BLS key. 72 // - (false, error) if an unexpected error occurs. 73 // - (validity, nil) otherwise 74 func SPOCKVerify(pk1 PublicKey, proof1 Signature, pk2 PublicKey, proof2 Signature) (bool, error) { 75 blsPk1, ok1 := pk1.(*pubKeyBLSBLS12381) 76 blsPk2, ok2 := pk2.(*pubKeyBLSBLS12381) 77 if !(ok1 && ok2) { 78 return false, notBLSKeyError 79 } 80 81 if len(proof1) != signatureLengthBLSBLS12381 || len(proof2) != signatureLengthBLSBLS12381 { 82 return false, nil 83 } 84 85 // if pk1 and proof1 are identities of their respective groups, any couple (pk2, proof2) would 86 // verify the pairing equality which breaks the unforgeability of the SPoCK scheme. This edge case 87 // is avoided by not allowing an identity pk1. Similarly, an identity pk2 is not allowed. 88 if blsPk1.isIdentity || blsPk2.isIdentity { 89 return false, nil 90 } 91 92 // verify the spock proof using the secret data 93 verif := C.bls_spock_verify((*C.ep2_st)(&blsPk1.point), 94 (*C.uchar)(&proof1[0]), 95 (*C.ep2_st)(&blsPk2.point), 96 (*C.uchar)(&proof2[0])) 97 98 switch verif { 99 case invalid: 100 return false, nil 101 case valid: 102 return true, nil 103 default: 104 return false, fmt.Errorf("SPoCK verification failed") 105 } 106 }