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  }