crypto

package module
v0.25.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 3, 2024 License: Apache-2.0 Imports: 19 Imported by: 10

README

Flow Cryptography

The Flow crypto Go module provides the cryptography tools needed by the Flow blockchain. The primitives and protocols can be used in other projects and are not specific to Flow.

Notes:

  • The package has been audited for security in January 2021 on this version. The package had a major refactor to switch all the BLS12-381 curve implementation to use BLST starting from version v0.25.0.
  • The package used to live under the flow-go repository before being moved out as a separate repository. The move preserved all the module Git history.
  • The module does not provide security against side channel or fault attacks.

Module import

Flow cryptography can be imported as any other Go package and does not require extra setup or pre-build (it used to require a pre-build up to version v0.24.9):

get the package

go get github.com/onflow/crypto

import the package into your Go code

import "github.com/onflow/crypto"

Build

Building your project with Flow crypto and enabling all the supported algorithms requires using cgo to compile the C code underneath. If cgo isn't enabled by default, the GCO_ENABLED environment variable should be set to 1. It is also possible to build without cgo (CGO_ENABLED=0) but this would disable some primitives (the ones related to BLS).

Build with cgo

Building with cgo is required to support all the algorithms of the module, including the algorithms based on the BLS12-381 curve.

If the test or target application crashes with a "Caught SIGILL" exception, rebuild with CGO_CFLAGS set to "-O2 -D__BLST_PORTABLE__" to disable non-portable code. The runtime error can happen if the CPU doesn't support certain instructions. Building with this flag results in a slower performance, it is therefore recommended to not use it when possible for an optimal performance.

CGO_CFLAGS="-O2 -D__BLST_PORTABLE__" go build 

If you're cross-compiling, you need to set the CC environment variable to the target C cross-compiler and set CGO_ENABLED to 1. You also need to set the GOOS and GOARCH variables.For example, to compile the test program for linux arm64:

GOOS=linux GOARCH=arm64 CC=aarch64-linux-gnu-gcc CGO_ENABLED=1 go build
Build without cgo

It is possible to build without cgo but this requires disabling all primitives based on the BLS12-381 curve (BLS signature, BLS threshold signature, BLS-based DKG, BLS-based SPoCK). Refer to algorithms and protocols to check the supported features. Calling any of the non-supported primitives would panic. In order to avoid accidental builds that result in unwanted crashes, disabling cgo must be confirmed with the no_cgo build tag.

CGO_ENABLED=0 go build -tags=no_cgo

Algorithms

Hashing and Message Authentication Code:

crypto/hash provides the hashing and MAC algorithms required for Flow. All algorithm implement the generic interface Hasher. All digests are of the generic type Hash.

  • SHA-3: 256 and 384 output sizes
  • Legacy Kaccak: 256 output size
  • SHA-2: 256 and 384 output sizes
  • KMAC: 128 variant
Signature schemes

All signature schemes use the generic interfaces of PrivateKey and PublicKey. All signatures are of the generic type Signature.

  • ECDSA

    • public keys are compressed or uncompressed.
    • ephemeral key is derived from the private key, hash and the system entropy (based on https://golang.org/pkg/crypto/ecdsa/).
    • supports NIST P-256 (secp256r1) and secp256k1 curves.
  • BLS (requires cgo)

    • supports BLS12-381 curve.
    • is implementing the minimal-signature-size variant: signatures in G1 and public keys in G2.
    • default set-up uses compressed G1/G2 points, but uncompressed format is also supported.
    • hashing to curve uses the Simplified SWU map-to-curve.
    • expanding the message in hash-to-curve uses a cSHAKE-based KMAC128 with a domain separation tag. KMAC128 serves as an expand_message_xof function.
    • this results in the full ciphersuite BLS_SIG_BLS12381G1_XOF:KMAC128_SSWU_RO_POP_ for signatures and BLS_POP_BLS12381G1_XOF:KMAC128_SSWU_RO_POP_ for proofs of possession.
    • signature verification includes the signature membership check in G1.
    • public key membership check in G2 is provided outside of the signature verification.
    • aggregation of signatures, public keys and private keys.
    • verification of an aggregated signature of a single message under multiple public keys.
    • verification of an aggregated signature of multiple messages under multiple public keys.
    • batch verification of multiple signatures of a single message under multiple public keys, using a binary tree of aggregations.
    • SPoCK scheme based on BLS: verifies two signatures have been generated from the same message that is unknown to the verifier.
PRNG
  • ChaCha20-based CSPRNG

Protocols

Threshold Signature
  • BLS-based threshold signature (requires cgo)
    • non interactive threshold signature reconstruction.
    • supports only BLS 12-381 curve with the same features above.
    • (t+1) signatures are required to reconstruct the threshold signature.
    • key generation (single dealer) to provide the set of keys.
    • provides a stateless api and a stateful api.
Discrete-Log based distributed key generation

All supported Distributed Key Generation protocols are discrete log based and are implemented for the same BLS setup on the BLS 12-381 curve. The protocols generate key sets for the BLS-based threshold signature.

  • Feldman VSS (requires cgo)
    • simple verifiable secret sharing with a single dealer.
    • the library does not implement the communication channels between participants. The caller should implement the methods PrivateSend (1-to-1 messaging) and Broadcast (1-to-n messaging)
    • 1-to-1 messaging must be a private channel, the caller must make sure the channel preserves confidentialiy and authenticates the sender.
    • 1-to-n broadcasting is a reliable broadcast, where honest senders are able to reach all honest receivers, and where all honest receivers end up with the same received messages. The channel should also authenticate the broadcaster.
    • It is recommended that both communication channels are unique per protocol instance. This could be achieved by prepending the messages to send/broadcast by a unique protocol instance ID.
  • Feldman VSS Qual (requires cgo)
    • an extension of the simple Feldman VSS.
    • implements a complaint mechanism to qualify/disqualify the dealer.
  • Joint Feldman (Pedersen) (requires cgo)
    • distributed generation.
    • based on multiple parallel instances of Feldman VSS Qual with multiple dealers.
    • same assumptions about the communication channels as in Feldman VSS.

Documentation

Index

Constants

View Source
const (
	// SignatureLenBLSBLS12381 is the serialization size of a `G_1` element.
	SignatureLenBLSBLS12381 = g1BytesLen
	// PubKeyLenBLSBLS12381 is the serialization size of a `G_2` element.
	PubKeyLenBLSBLS12381 = g2BytesLen
	// PrKeyLenBLSBLS12381 is the serialization size of a `F_r` element,
	// where `r` is the order of `G_1` and `G_2`.
	PrKeyLenBLSBLS12381 = frBytesLen
)
View Source
const (

	// keygen seed length conditions
	// enforce seed to be at least double the security bits and have enough entropy.
	// it is still recommened that seed is generated using a secure RNG.
	KeyGenSeedMinLen = 2 * (securityBits / 8)
	KeyGenSeedMaxLen = 256
)
View Source
const (

	// MinimumThreshold is the minimum value of the threshold parameter in all threshold-based protocols.
	MinimumThreshold = 1
	// DKGMinSize is the minimum size of a group participating in a DKG protocol
	DKGMinSize int = MinimumThreshold + 1
	// DKGMaxSize is the maximum size of a group participating in a DKG protocol
	DKGMaxSize int = 254
)
View Source
const (
	// NIST P256
	SignatureLenECDSAP256 = 64
	PrKeyLenECDSAP256     = 32
	// PubKeyLenECDSAP256 is the size of uncompressed points on P256
	PubKeyLenECDSAP256 = 64

	// SECG secp256k1
	SignatureLenECDSASecp256k1 = 64
	PrKeyLenECDSASecp256k1     = 32
	// PubKeyLenECDSASecp256k1 is the size of uncompressed points on secp256k1
	PubKeyLenECDSASecp256k1 = 64
)
View Source
const (
	// ThresholdSignMinSize is the minimum size of a group participating in a threshold signature protocol
	ThresholdSignMinSize = MinimumThreshold + 1
	// ThresholdSignMaxSize is the maximum size of a group participating in a threshold signature protocol
	ThresholdSignMaxSize = DKGMaxSize
)

Variables

View Source
var BLS12381Order = []byte{0x73, 0xED, 0xA7, 0x53, 0x29, 0x9D, 0x7D, 0x48, 0x33, 0x39,
	0xD8, 0x08, 0x09, 0xA1, 0xD8, 0x05, 0x53, 0xBD, 0xA4, 0x02, 0xFF, 0xFE,
	0x5B, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01}

Functions

func BLSThresholdKeyGen

func BLSThresholdKeyGen(size int, threshold int, seed []byte) ([]PrivateKey,
	[]PublicKey, PublicKey, error)

BLSThresholdKeyGen is a key generation for a BLS-based threshold signature scheme with a trusted dealer.

The function returns: - (nil, nil, nil, invalidInputsErrorf) if:

  • seed is too short
  • n is not in [`ThresholdSignMinSize`, `ThresholdSignMaxSize`]
  • threshold value is not in interval [1, n-1]
  • (groupPrivKey, []pubKeyShares, groupPubKey, nil) otherwise

func BLSVerifyPOP

func BLSVerifyPOP(pk PublicKey, s Signature) (bool, error)

BLSVerifyPOP verifies a proof of possession (PoP) for the receiver public key.

The function internally uses the same KMAC hasher used to generate the PoP. The hasher is guaranteed to be orthogonal to any hasher used to generate signature or SPoCK proofs on this package. Note that verifying a PoP against an idenity public key fails.

The function returns:

  • (false, notBLSKeyError) if the input key is not of type BLS BLS12-381
  • (validity, nil) otherwise

func BatchVerifyBLSSignaturesOneMessage

func BatchVerifyBLSSignaturesOneMessage(
	pks []PublicKey, sigs []Signature, message []byte, kmac hash.Hasher,
) ([]bool, error)

BatchVerifyBLSSignaturesOneMessage is a batch verification of multiple BLS signatures of a single message against multiple BLS public keys that is faster than verifying the signatures one by one.

Each signature at index (i) of the input signature slice is verified against the public key of the same index (i) in the input key slice. The input hasher is the same used to generate all signatures. The returned boolean slice is of the same length of the signatures slice, where the boolean at index (i) is true if signature (i) verifies against public key (i), and false otherwise. In the case where an error occurs during the execution of the function, all the returned boolean values are `false`.

The caller must make sure the input public keys's proofs of possession have been verified prior to calling this function (or each input key is sum of public keys of which proofs of possession have been verified).

Membership checks are performed on the input signatures but are not performed on the input public keys (which are guaranteed by the package to be on the correct G2 subgroup). In order to avoid equivocation issues, any identity public key results in the corresponding signature being invalid.

The function returns:

  • ([]false, nilHasherError) if a hasher is nil
  • ([]false, invalidHasherSizeError) if a hasher's output size is not 128 bytes
  • ([]false, notBLSKeyError) if at least one key is not of type BLS BLS12-381
  • ([]false, invalidInputsError) if size of keys is not matching the size of signatures
  • ([]false, blsAggregateEmptyListError) if input key slice is empty
  • ([]false, error) if an unexpected error occurs
  • ([]validity, nil) otherwise

func EnoughShares

func EnoughShares(threshold int, sharesNumber int) (bool, error)

EnoughShares is a stateless function that takes the value of the threshold and a shares number and returns true if the shares number is enough to reconstruct a threshold signature.

The function returns:

  • (false, invalidInputsErrorf) if input threshold is less than 1
  • (false, nil) if threshold is valid but shares are not enough.
  • (true, nil) if the threshold is valid but shares are enough.

func IsBLSAggregateEmptyListError

func IsBLSAggregateEmptyListError(err error) bool

IsBLSAggregateEmptyListError checks if err is an `blsAggregateEmptyListError`. blsAggregateEmptyListError is returned when a BLS aggregation function is called with an empty list which is not allowed in some aggregation cases to avoid signature equivocation issues.

func IsBLSSignatureIdentity

func IsBLSSignatureIdentity(s Signature) bool

IsBLSSignatureIdentity checks whether the input signature is the identity signature (point at infinity in G1).

An identity signature is always an invalid signature even when verified against the identity public key. This identity check is useful when an aggregated signature is suspected to be equal to identity, which avoids failing the aggregated signature verification.

func IsDKGFailureError

func IsDKGFailureError(err error) bool

IsDKGFailureError checks if the input error is of a dkgFailureError type. dkgFailureError is an error returned when a participant detects a failure in the protocol and is not able to compute output keys.

func IsDKGInvalidStateTransitionError

func IsDKGInvalidStateTransitionError(err error) bool

IsDkgInvalidStateTransitionError checks if the input error is of a dkgInvalidStateTransition type. invalidStateTransition is returned when a caller triggers an invalid state transition in the local DKG instance. Such a failure can only happen if the API is misued by not respecting the state machine conditions.

func IsDuplicatedSignerError

func IsDuplicatedSignerError(err error) bool

IsDuplicatedSignerError checks if the input error is a duplicatedSignerError

func IsInvalidHasherSizeError

func IsInvalidHasherSizeError(err error) bool

IsInvalidHasherSizeError checks if the input error is of an invalidHasherSizeError type. invalidHasherSizeError is an error returned when a crypto API is called with a hasher with an output size not suited with the cryptographic operation.

func IsInvalidInputsError

func IsInvalidInputsError(err error) bool

IsInvalidInputsError checks if the input error is of an invalidInputsError type invalidInputsError is returned when the API is provided invalid inputs. Some specific errors are assigned specific sentinel errors for a simpler error check while the remaining input errors trigger an invalidInputsError.

func IsInvalidSignatureError

func IsInvalidSignatureError(err error) bool

IsInvalidSignatureError checks if err is an `invalidSignatureError` invalidSignatureError is returned when a signature input does not serialize to a valid element on E1 of the BLS12-381 curve (but without checking the element is on subgroup G1).

func IsNilHasherError

func IsNilHasherError(err error) bool

IsNilHasherError checks if the input error wraps a nilHasherError. nilHasherError is returned when a nil hasher is used.

func IsNotBLSKeyError

func IsNotBLSKeyError(err error) bool

IsNotBLSKeyError checks if err is an `notBLSKeyError`. notBLSKeyError is returned when a private or public key used is not a BLS on BLS12 381 key.

func IsNotEnoughSharesError

func IsNotEnoughSharesError(err error) bool

IsNotEnoughSharesError checks if the input error is a notEnoughSharesError

func NewBLSThresholdSignatureInspector

func NewBLSThresholdSignatureInspector(
	groupPublicKey PublicKey,
	sharePublicKeys []PublicKey,
	threshold int,
	message []byte,
	dsTag string,
) (*blsThresholdSignatureInspector, error)

NewBLSThresholdSignatureInspector creates a new instance of Threshold signature follower using BLS. It only allows following the threshold signing protocol .

A new instance is needed for each set of public keys and message. If the key set or message change, a new structure needs to be instantiated. Participants are defined by their public key share, and are indexed from 0 to n-1 where n is the length of the public key shares slice.

The function returns: - (nil, invalidInputsError) if:

  • n is not in [`ThresholdSignMinSize`, `ThresholdSignMaxSize`]
  • threshold value is not in interval [1, n-1]
  • (nil, notBLSKeyError) at least one public key is not of type pubKeyBLSBLS12381
  • (pointer, nil) otherwise

func NewBLSThresholdSignatureParticipant

func NewBLSThresholdSignatureParticipant(
	groupPublicKey PublicKey,
	sharePublicKeys []PublicKey,
	threshold int,
	myIndex int,
	myPrivateKey PrivateKey,
	message []byte,
	dsTag string,
) (*blsThresholdSignatureParticipant, error)

NewBLSThresholdSignatureParticipant creates a new instance of Threshold signature Participant using BLS. A participant is able to participate in a threshold signing protocol as well as following the protocol.

A new instance is needed for each set of public keys and message. If the key set or message change, a new structure needs to be instantiated. Participants are defined by their public key share, and are indexed from 0 to n-1. The current participant is indexed by `myIndex` and holds the input private key where n is the length of the public key shares slice.

The function returns: - (nil, invalidInputsError) if:

  • n is not in [`ThresholdSignMinSize`, `ThresholdSignMaxSize`]
  • threshold value is not in interval [1, n-1]
  • input private key and public key at my index do not match
  • (nil, notBLSKeyError) if the private or at least one public key is not of type BLS BLS12-381.
  • (pointer, nil) otherwise

func NewExpandMsgXOFKMAC128

func NewExpandMsgXOFKMAC128(domainTag string) hash.Hasher

NewExpandMsgXOFKMAC128 returns a new expand_message_xof instance for the hash-to-curve function, hashing data to G1 on BLS12 381. This instance must only be used to generate signatures (and not PoP), because the internal ciphersuite is customized for signatures. It is guaranteed to be different than the expand_message_xof instance used to generate proofs of possession.

KMAC128 is used as the underligned extendable-output function (xof) as required by https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-14#section-5.4.4.

`domainTag` is a domain separation tag that defines the protocol and its subdomain. Such tag should be of the format: <protocol>-V<xx>-CS<yy>-with- where <protocol> is the name of the protocol, <xx> the protocol version number and <yy> the index of the ciphersuite in the protocol. The function suffixes the given `domainTag` by the BLS ciphersuite supported by the library.

The returned instance is a `Hasher` and can be used to generate BLS signatures with the `Sign` method.

func SPOCKVerify

func SPOCKVerify(pk1 PublicKey, proof1 Signature, pk2 PublicKey, proof2 Signature) (bool, error)

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 SPOCKVerifyAgainstData

func SPOCKVerifyAgainstData(pk PublicKey, proof Signature, data []byte, kmac hash.Hasher) (bool, error)

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 SignatureFormatCheck

func SignatureFormatCheck(algo SigningAlgorithm, s Signature) (bool, error)

SignatureFormatCheck verifies the format of a serialized signature, regardless of messages or public keys.

This function is only defined for ECDSA algos for now.

If SignatureFormatCheck returns false then the input is not a valid signature and will fail a verification against any message and public key.

func TestHasherErrors

func TestHasherErrors(t *testing.T)

func TestKeyGenErrors

func TestKeyGenErrors(t *testing.T)

func VerifyBLSSignatureManyMessages

func VerifyBLSSignatureManyMessages(
	pks []PublicKey, s Signature, messages [][]byte, kmac []hash.Hasher,
) (bool, error)

VerifyBLSSignatureManyMessages is a multi-signature verification that verifies a BLS signature under multiple messages and public keys.

The input signature could be generated by aggregating multiple signatures of distinct messages under distinct private keys. The verification is performed against the message at index (i) and the public key at the same index (i) of the input messages and public keys. The hasher at index (i) is used to hash the message at index (i).

Since the package only supports the Proof of Possession scheme, the function does not enforce input messages to be distinct. Thereore, the caller must make sure the input public keys's proofs of possession have been verified prior to calling this function (or each input key is sum of public keys of which proofs of possession have been verified).

The verification is optimized to compute one pairing per distinct message, or one pairing per distinct key, whatever way offers less pairings calls. If all messages are the same, the function has the same behavior as VerifyBLSSignatureOneMessage. If there is one input message and input public key, the function has the same behavior as pk.Verify. Membership check is performed on the input signature. In order to avoid equivocation issues, any identity public key results in the overall signature being invalid.

The function returns:

  • (false, nilHasherError) if a hasher is nil
  • (false, invalidHasherSizeError) if a hasher's output size is not 128 bytes
  • (false, notBLSKeyError) if at least one key is not a BLS BLS12-381 key
  • (false, invalidInputsError) if size of keys is not matching the size of messages and hashers
  • (false, blsAggregateEmptyListError) if input key slice `pks` is empty
  • (false, error) if an unexpected error occurs
  • (validity, nil) otherwise

func VerifyBLSSignatureOneMessage

func VerifyBLSSignatureOneMessage(
	pks []PublicKey, s Signature, message []byte, kmac hash.Hasher,
) (bool, error)

VerifyBLSSignatureOneMessage is a multi-signature verification that verifies a BLS signature of a single message against multiple BLS public keys.

The input signature could be generated by aggregating multiple signatures of the message under multiple private keys. The public keys corresponding to the signing private keys are passed as input to this function. The caller must make sure the input public keys's proofs of possession have been verified prior to calling this function (or each input key is sum of public keys of which proofs of possession have been verified).

The input hasher is the same hasher used to generate all initial signatures. The order of the public keys in the slice does not matter. Membership check is performed on the input signature but is not performed on the input public keys (membership is guaranteed by using the package functions). If the input public keys add up to the identity public key, the signature is invalid to avoid signature equivocation issues.

This is a special case function of VerifyBLSSignatureManyMessages, using a single message and hasher.

The function returns:

  • (false, nilHasherError) if hasher is nil
  • (false, invalidHasherSizeError) if hasher's output size is not 128 bytes
  • (false, notBLSKeyError) if at least one key is not of type pubKeyBLSBLS12381
  • (nil, blsAggregateEmptyListError) if input key slice is empty
  • (false, error) if an unexpected error occurs
  • (validity, nil) otherwise

Types

type DKGProcessor

type DKGProcessor interface {
	// PrivateSend sends a message to a destination over
	// a private channel. The channel must preserve the
	// confidentiality of the message and should authenticate
	// the sender.
	// It is recommended that the private channel is unique per
	// protocol instance. This can be achieved by prepending all
	// messages by a unique instance ID.
	PrivateSend(dest int, data []byte)
	// Broadcast broadcasts a message to all participants.
	// This function assumes all participants have received the same message,
	// failing to do so, the protocol can be broken.
	// The broadcasted message is public and not confidential.
	// The broadcasting channel should authenticate the sender.
	// It is recommended that the broadcasting channel is unique per
	// protocol instance. This can be achieved by prepending all
	// messages by a unique instance ID.
	Broadcast(data []byte)
	// Disqualify flags that a participant is misbehaving and that it got
	// disqualified from the protocol. Such behavior deserves
	// disqualifying as it is flagged to all honest participants in
	// the protocol.
	// log describes the disqualification reason.
	Disqualify(participant int, log string)
	// FlagMisbehavior warns that a participant is misbehaving.
	// Such behavior is not necessarily flagged to all participants and therefore
	// the participant is not disqualified from the protocol. Other mechanisms
	// outside DKG could be implemented to synchronize slashing the misbehaving
	// participant by all participating participants, using the api `ForceDisqualify`. Failing to
	// do so, the protocol can be broken.
	// log describes the misbehavior.
	FlagMisbehavior(participant int, log string)
}

DKGProcessor is an interface that implements the DKG output actions.

An instance of a DKGProcessor is needed for each participant in order to particpate in a DKG protocol

type DKGState

type DKGState interface {
	// Size returns the size of the DKG group n
	Size() int
	// Threshold returns the threshold value t
	Threshold() int
	// Start starts running a DKG in the current participant
	Start(seed []byte) error
	// HandleBroadcastMsg processes a new broadcasted message received by the current participant.
	// orig is the message origin index
	HandleBroadcastMsg(orig int, msg []byte) error
	// HandlePrivateMsg processes a new private message received by the current participant.
	// orig is the message origin index
	HandlePrivateMsg(orig int, msg []byte) error
	// End ends a DKG protocol in the current participant.
	// It returns the finalized public data and participant private key share.
	// - the group public key corresponding to the group secret key
	// - all the public key shares corresponding to the participants private
	// key shares
	// - the finalized private key which is the current participant's own private key share
	End() (PrivateKey, PublicKey, []PublicKey, error)
	// NextTimeout set the next timeout of the protocol if any timeout applies.
	// Some protocols could require more than one timeout
	NextTimeout() error
	// Running returns the running state of the DKG protocol
	Running() bool
	// ForceDisqualify forces a participant to get disqualified
	// for a reason outside of the DKG protocol.
	// The caller should make sure all honest participants call this function,
	// otherwise, the protocol can be broken.
	ForceDisqualify(participant int) error
}

func NewFeldmanVSS

func NewFeldmanVSS(size int, threshold int, myIndex int,
	processor DKGProcessor, dealerIndex int) (DKGState, error)

NewFeldmanVSS creates a new instance of Feldman VSS protocol.

An instance is run by a single participant and is usable for only one protocol. In order to run the protocol again, a new instance needs to be created

The function returns: - (nil, InvalidInputsError) if:

  • size if not in [DKGMinSize, DKGMaxSize]
  • threshold is not in [MinimumThreshold, size-1]
  • myIndex is not in [0, size-1]
  • dealerIndex is not in [0, size-1]

- (dkgInstance, nil) otherwise

func NewFeldmanVSSQual

func NewFeldmanVSSQual(size int, threshold int, myIndex int,
	processor DKGProcessor, dealerIndex int) (DKGState, error)

NewFeldmanVSSQual creates a new instance of a Feldman VSS protocol with a qualification mechanism.

An instance is run by a single participant and is usable for only one protocol. In order to run the protocol again, a new instance needs to be created

The function returns:

  • (nil, InvalidInputsError) if:
  • size if not in [DKGMinSize, DKGMaxSize]
  • threshold is not in [MinimumThreshold, size-1]
  • myIndex is not in [0, size-1]
  • dealerIndex is not in [0, size-1]
  • (dkgInstance, nil) otherwise

func NewJointFeldman

func NewJointFeldman(size int, threshold int, myIndex int,
	processor DKGProcessor) (DKGState, error)

NewJointFeldman creates a new instance of a Joint Feldman protocol.

size if the total number of participants (n). threshold is the threshold parameter (t). the DKG protocol is secure in the presence of up to (t) malicious participants when (t < n/2). myIndex is the index of the participant creating the new DKG instance. processor is the DKGProcessor instance required to connect the participant to the communication channels.

An instance is run by a single participant and is usable for only one protocol. In order to run the protocol again, a new instance needs to be created.

The function returns: - (nil, InvalidInputsError) if:

  • size if not in [DKGMinSize, DKGMaxSize]
  • threshold is not in [MinimumThreshold, size-1]
  • myIndex is not in [0, size-1]
  • dealerIndex is not in [0, size-1]

- (dkgInstance, nil) otherwise

type JointFeldmanState added in v0.25.0

type JointFeldmanState struct {
	// contains filtered or unexported fields
}

Joint Feldman protocol, with complaint mechanism, implements DKGState

func (*JointFeldmanState) End added in v0.25.0

End ends the protocol in the current participant It returns the finalized public data and participant private key share. - the group public key corresponding to the group secret key - all the public key shares corresponding to the participants private key shares. - the finalized private key which is the current participant's own private key share

The returned error is:

  • dkgFailureError if the disqualified dealers exceeded the threshold
  • dkgFailureError if the public key share or group public key is identity.
  • dkgInvalidStateTransitionError Start() was not called, or NextTimeout() was not called twice
  • nil otherwise.

func (*JointFeldmanState) ForceDisqualify added in v0.25.0

func (s *JointFeldmanState) ForceDisqualify(participant int) error

ForceDisqualify forces a participant to get disqualified for a reason outside of the DKG protocol The caller should make sure all honest participants call this function, otherwise, the protocol can be broken

The function returns:

  • dkgInvalidStateTransitionError if the instance is not running
  • invalidInputsError if `orig` is not valid (in [0, size-1])
  • nil otherwise

func (*JointFeldmanState) HandleBroadcastMsg added in v0.25.0

func (s *JointFeldmanState) HandleBroadcastMsg(orig int, msg []byte) error

HandleBroadcastMsg processes a new broadcasted message received by the current participant orig is the message origin index

The function returns:

  • dkgInvalidStateTransitionError if the instance is not running
  • invalidInputsError if `orig` is not valid (in [0, size-1])
  • nil otherwise

func (*JointFeldmanState) HandlePrivateMsg added in v0.25.0

func (s *JointFeldmanState) HandlePrivateMsg(orig int, msg []byte) error

HandlePrivateMsg processes a new private message received by the current participant orig is the message origin index

The function returns:

  • dkgInvalidStateTransitionError if the instance is not running
  • invalidInputsError if `orig` is not valid (in [0, size-1])
  • nil otherwise

func (*JointFeldmanState) NextTimeout added in v0.25.0

func (s *JointFeldmanState) NextTimeout() error

NextTimeout sets the next timeout of the protocol if any timeout applies.

The returned error is :

  • dkgInvalidStateTransitionError if the DKG instance was not running.
  • dkgInvalidStateTransitionError if the DKG instance already called the 2 required timeouts.
  • nil otherwise.

func (*JointFeldmanState) Running added in v0.25.0

func (s *JointFeldmanState) Running() bool

Running returns the running state of Joint Feldman protocol

func (JointFeldmanState) Size added in v0.25.0

func (s JointFeldmanState) Size() int

Size returns the size of the DKG group n

func (*JointFeldmanState) Start added in v0.25.0

func (s *JointFeldmanState) Start(seed []byte) error

Start triggers Joint Feldman protocol start for the current participant. The seed is used to generate the FVSS secret polynomial (including the instance group private key) when the current participant is the dealer.

The returned error is :

  • dkgInvalidStateTransitionError if the DKG instance is already running.
  • error if an unexpected exception occurs
  • nil otherwise.

func (JointFeldmanState) Threshold added in v0.25.0

func (s JointFeldmanState) Threshold() int

Threshold returns the threshold value t

type PrivateKey

type PrivateKey interface {
	// Algorithm returns the signing algorithm related to the private key.
	Algorithm() SigningAlgorithm
	// Size return the key size in bytes.
	Size() int
	// String return a hex representation of the key
	String() string
	// Sign generates a signature using the provided hasher.
	Sign([]byte, hash.Hasher) (Signature, error)
	// PublicKey returns the public key.
	PublicKey() PublicKey
	// Encode returns a bytes representation of the private key
	Encode() []byte
	// Equals returns true if the given PrivateKeys are equal. Keys are considered unequal if their algorithms are
	// unequal or if their encoded representations are unequal. If the encoding of either key fails, they are considered
	// unequal as well.
	Equals(PrivateKey) bool
}

PrivateKey is an unspecified signature scheme private key

func AggregateBLSPrivateKeys

func AggregateBLSPrivateKeys(keys []PrivateKey) (PrivateKey, error)

AggregateBLSPrivateKeys aggregates multiple BLS private keys into one.

The order of the keys in the slice does not matter since the aggregation is commutative. The slice should not be empty. No check is performed on the input private keys. Input or output private keys could be equal to the identity element (zero). Note that any signature generated by the identity key is invalid (to avoid equivocation issues).

The function returns:

  • (nil, notBLSKeyError) if at least one key is not of type BLS BLS12-381
  • (nil, blsAggregateEmptyListError) if no keys are provided (input slice is empty)
  • (aggregated_key, nil) otherwise

func DecodePrivateKey

func DecodePrivateKey(algo SigningAlgorithm, data []byte) (PrivateKey, error)

DecodePrivateKey decodes an array of bytes into a private key of the given algorithm

The function returns:

  • (nil, invalidInputsErrors) if the signing algorithm is not supported
  • (nil, invalidInputsErrors) if the input does not serialize a valid private key:
  • ECDSA: bytes(x) where bytes() is the big-endian encoding padded to the curve order.
  • BLS: bytes(x) where bytes() is the big-endian encoding padded to the order of BLS12-381. for all algorithms supported, input is big-endian encoding of a the private scalar less than the curve order and left-padded to 32 bytes
  • (nil, error) if an unexpected error occurs
  • (sk, nil) otherwise

func GeneratePrivateKey

func GeneratePrivateKey(algo SigningAlgorithm, seed []byte) (PrivateKey, error)

GeneratePrivateKey generates a private key of the algorithm using the entropy of the given seed.

The seed minimum length is 32 bytes and it should have enough entropy. It is recommended to use a secure crypto RNG to generate the seed.

The function returns:

  • (false, invalidInputsErrors) if the signing algorithm is not supported or if the seed length is not valid (less than 32 bytes or larger than 256 bytes)
  • (false, error) if an unexpected error occurs
  • (sk, nil) if key generation was successful

type PublicKey

type PublicKey interface {
	// Algorithm returns the signing algorithm related to the public key.
	Algorithm() SigningAlgorithm
	// Size() return the key size in bytes.
	Size() int
	// String return a hex representation of the key
	String() string
	// Verify verifies a signature of an input message using the provided hasher.
	Verify(Signature, []byte, hash.Hasher) (bool, error)
	// Encode returns a bytes representation of the public key.
	Encode() []byte
	// EncodeCompressed returns a compressed byte representation of the public key.
	// The compressed serialization concept is generic to elliptic curves,
	// but we refer to individual curve parameters for details of the compressed format
	EncodeCompressed() []byte
	// Equals returns true if the given PublicKeys are equal. Keys are considered unequal if their algorithms are
	// unequal or if their encoded representations are unequal. If the encoding of either key fails, they are considered
	// unequal as well.
	Equals(PublicKey) bool
}

PublicKey is an unspecified signature scheme public key.

func AggregateBLSPublicKeys

func AggregateBLSPublicKeys(keys []PublicKey) (PublicKey, error)

AggregateBLSPublicKeys aggregate multiple BLS public keys into one.

The order of the keys in the slice does not matter since the aggregation is commutative. The slice should not be empty. No check is performed on the input public keys. The input keys are guaranteed by the package constructors to be on the G2 subgroup. Input or output keys can be equal to the identity key. Note that any signature verified against the identity key is invalid (to avoid equivocation issues).

The function returns:

  • (nil, notBLSKeyError) if at least one key is not of type BLS BLS12-381
  • (nil, blsAggregateEmptyListError) no keys are provided (input slice is empty)
  • (aggregated_key, nil) otherwise

func DecodePublicKey

func DecodePublicKey(algo SigningAlgorithm, data []byte) (PublicKey, error)

DecodePublicKey decodes an array of bytes into a public key of the given algorithm

The function returns:

func DecodePublicKeyCompressed

func DecodePublicKeyCompressed(algo SigningAlgorithm, data []byte) (PublicKey, error)

DecodePublicKeyCompressed decodes an array of bytes given in a compressed representation into a public key of the given algorithm Only ECDSA is supported (BLS uses the compressed serialzation by default).

The function returns:

  • (nil, invalidInputsErrors) if the signing algorithm is not supported (is not ECDSA)
  • (nil, invalidInputsErrors) if the input does not serialize a valid public key:
  • ECDSA: sign_byte||bytes(x) according to X9.62 section 4.3.6.
  • (nil, error) if an unexpected error occurs
  • (sk, nil) otherwise

func IdentityBLSPublicKey

func IdentityBLSPublicKey() PublicKey

IdentityBLSPublicKey returns an identity public key which corresponds to the point at infinity in G2 (identity element g2).

func RemoveBLSPublicKeys

func RemoveBLSPublicKeys(aggKey PublicKey, keysToRemove []PublicKey) (PublicKey, error)

RemoveBLSPublicKeys removes multiple BLS public keys from a given (aggregated) public key.

The common use case assumes the aggregated public key was initially formed using the keys to be removed (directly or using other aggregated forms). However the function can still be called in different use cases. The order of the keys to be removed in the slice does not matter since the removal is commutative. The slice of keys to be removed can be empty. No check is performed on the input public keys. The input keys are guaranteed by the package constructors to be on the G2 subgroup. Input or output keys can be equal to the identity key.

The function returns:

  • (nil, notBLSKeyError) if at least one input key is not of type BLS BLS12-381
  • (remaining_key, nil) otherwise

type Signature

type Signature []byte

Signature is a generic type, regardless of the signature scheme

func AggregateBLSSignatures

func AggregateBLSSignatures(sigs []Signature) (Signature, error)

AggregateBLSSignatures aggregates multiple BLS signatures into one.

Signatures could be generated from the same or distinct messages, they could also be the aggregation of other signatures. The order of the signatures in the slice does not matter since the aggregation is commutative. The slice should not be empty. No G1 membership check is performed on the input signatures.

The function returns:

func BLSGeneratePOP

func BLSGeneratePOP(sk PrivateKey) (Signature, error)

BLSGeneratePOP returns a proof of possession (PoP) for the receiver private key.

The KMAC hasher used in the function is guaranteed to be orthogonal to all hashers used for signatures or SPoCK proofs on this package. This means a specific domain tag is used to generate PoP and is not used by any other application.

The function returns:

  • (nil, notBLSKeyError) if the input key is not of type BLS BLS12-381
  • (pop, nil) otherwise

func BLSInvalidSignature

func BLSInvalidSignature() Signature

BLSInvalidSignature returns an invalid signature that fails when verified with any message and public key, which can be used for testing.

The signature bytes represent an invalid serialization of a point which makes the verification fail early. The verification would return (false, nil).

func BLSReconstructThresholdSignature

func BLSReconstructThresholdSignature(size int, threshold int,
	shares []Signature, signers []int) (Signature, error)

BLSReconstructThresholdSignature is a stateless BLS api that takes a list of BLS signatures and their signers' indices and returns the threshold signature.

size is the number of participants, it must be in the range [ThresholdSignMinSize..ThresholdSignMaxSize]. threshold is the threshold value, it must be in the range [MinimumThreshold..size-1]. The function does not accept any input public key. Therefore, it does not check the validity of the shares against individual public keys, and does not check the validity of the resulting signature against the group public key. BLSReconstructThresholdSignature returns:

  • (nil, invalidInputsError) if : -- numbers of shares does not match the number of signers -- the inputs are not in the correct range.
  • (nil, notEnoughSharesError) if the threshold is not reached.
  • (nil, duplicatedSignerError) if input signers are not distinct.
  • (nil, invalidSignatureError) if at least one of the first (threshold+1) signatures. does not serialize to a valid E1 point.
  • (threshold_sig, nil) otherwise.

If the number of shares reaches the required threshold, only the first threshold+1 shares are considered to reconstruct the signature.

func SPOCKProve

func SPOCKProve(sk PrivateKey, data []byte, kmac hash.Hasher) (Signature, error)

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 (Signature) Bytes

func (s Signature) Bytes() []byte

Bytes returns a byte array of the signature data

func (Signature) String

func (s Signature) String() string

String returns a String representation of the signature data

type SigningAlgorithm

type SigningAlgorithm int

SigningAlgorithm is an identifier for a signing algorithm (and parameters if applicable)

const (
	// Supported signing algorithms
	UnknownSigningAlgorithm SigningAlgorithm = iota
	// BLSBLS12381 is BLS on BLS 12-381 curve
	BLSBLS12381
	// ECDSAP256 is ECDSA on NIST P-256 curve
	ECDSAP256
	// ECDSASecp256k1 is ECDSA on secp256k1 curve
	ECDSASecp256k1
)

func (SigningAlgorithm) String

func (f SigningAlgorithm) String() string

String returns the string representation of this signing algorithm.

type ThresholdSignatureInspector

type ThresholdSignatureInspector interface {
	// VerifyShare verifies the input signature against the stored message and stored
	// key at the input index. This function does not update the internal state.
	// The function is thread-safe.
	// Returns:
	//  - (true, nil) if the signature is valid
	//  - (false, nil) if `orig` is a valid index but the signature share is invalid
	//  - (false, InvalidInputsError) if `orig` is an invalid index value
	//  - (false, error) for all other unexpected errors
	VerifyShare(orig int, share Signature) (bool, error)

	// VerifyThresholdSignature verifies the input signature against the stored
	// message and stored group public key. It does not update the internal state.
	// The function is thread-safe.
	// Returns:
	//  - (true, nil) if the signature is valid
	//  - (false, nil) if the signature is invalid
	//  - (false, error) for all other unexpected errors
	VerifyThresholdSignature(thresholdSignature Signature) (bool, error)

	// EnoughShares indicates whether enough shares have been accumulated in order to reconstruct
	// a group signature. This function is thread safe and locks the internal state.
	// Returns:
	//  - true if and only if at least (threshold+1) shares were added
	EnoughShares() bool

	// TrustedAdd adds a signature share to the internal pool of shares
	// without verifying the signature against the message and the participant's
	// public key. This function is thread safe and locks the internal state.
	//
	// The share is only added if the signer index is valid and has not been
	// added yet. Moreover, the share is added only if not enough shares were collected.
	// The function returns:
	//  - (true, nil) if enough signature shares were already collected and no error occurred
	//  - (false, nil) if not enough shares were collected and no error occurred
	//  - (false, InvalidInputsError) if index is invalid
	//  - (false, duplicatedSignerError) if a signature for the index was previously added
	TrustedAdd(orig int, share Signature) (bool, error)

	// VerifyAndAdd verifies a signature share (same as `VerifyShare`),
	// and may or may not add the share to the local pool of shares.
	// This function is thread safe and locks the internal state.
	//
	// The share is only added if the signature is valid, the signer index is valid and has not been
	// added yet. Moreover, the share is added only if not enough shares were collected.
	// Boolean returns:
	//  - First boolean output is true if the share is valid and no error is returned, and false otherwise.
	//  - Second boolean output is true if enough shares were collected and no error is returned, and false otherwise.
	// Error returns:
	//  - invalidInputsError if input index is invalid. A signature that doesn't verify against the signer's
	//    public key is not considered an invalid input.
	//  - duplicatedSignerError if signer was already added.
	//  - other errors if an unexpected exception occurred.
	VerifyAndAdd(orig int, share Signature) (bool, bool, error)

	// HasShare checks whether the internal map contains the share of the given index.
	// This function is thread safe.
	// The function errors with InvalidInputsError if the index is invalid.
	HasShare(orig int) (bool, error)

	// ThresholdSignature returns the threshold signature if the threshold was reached.
	// The threshold signature is reconstructed only once and is cached for subsequent calls.
	//
	// Returns:
	// - (signature, nil) if no error occurred
	// - (nil, notEnoughSharesError) if not enough shares were collected
	// - (nil, invalidSignatureError) if at least one collected share does not serialize to a valid BLS signature.
	// - (nil, invalidInputsError) if the constructed signature failed to verify against the group public key and stored message. This post-verification
	//    is required  for safety, as `TrustedAdd` allows adding invalid signatures.
	// - (nil, error) for any other unexpected error.
	ThresholdSignature() (Signature, error)
}

ThresholdSignatureInspector is an inspector of the threshold signature protocol. The interface only allows inspecting the threshold signing protocol without taking part in it.

type ThresholdSignatureParticipant

type ThresholdSignatureParticipant interface {
	ThresholdSignatureInspector
	// SignShare generates a signature share using the current private key share.
	//
	// The function does not add the share to the internal pool of shares and do
	// not update the internal state.
	// This function is thread safe
	// No error is expected unless an unexpected exception occurs
	SignShare() (Signature, error)
}

ThresholdSignatureParticipant is a participant in a threshold signature protocol. A participant is able to participate in a threshold signing protocol as well as inspecting the protocol.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL