cloudflare

package
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2021 License: MIT, BSD-3-Clause Imports: 9 Imported by: 2

Documentation

Overview

Package cloudflare implements a particular bilinear group at the 128-bit security level.

Bilinear groups are the basis of many of the new cryptographic protocols that have been proposed over the past decade. They consist of a triplet of groups (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ (where gₓ is a generator of the respective group). That function is called a pairing function.

This package specifically implements the Optimal Ate pairing over a 256-bit Barreto-Naehrig curve as described in http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible with the implementation described in that paper.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrDangerousPoint occurs when HashToG1 attempts to return a point p
	// in G1 whose value is dangerous when they arise in signature generation;
	// in particular, Infinity (the identity element) or the curve generator
	// or its negation.
	// These points introduce security concerns should they be
	// used as valid hash G1 points for a signature. Therefore, we will
	// raise an error should they ever occur.
	ErrDangerousPoint = errors.New("hashToG1: p == curveGen or p == Inf or p == negCurveGen; dangerous hash point for signatures")

	// ErrInvalidPoint occurs when HashToG1 or HashToG2 produces a point p
	// which is not actually on the corresponding elliptic curve (curve or
	// twist). This should never happen.
	ErrInvalidPoint = errors.New("hashToG1/HashToG2: hash point not on curve")

	// ErrInvalidSharedSecret means that the secret shared by this participant
	// is invalid; this implies this participant performed a malicious action.
	ErrInvalidSharedSecret = errors.New("compareSharedSecret: Failed shared secret")

	// ErrInvalidThreshold occurs when threshold is less than 1, which
	// is not possible.
	ErrInvalidThreshold = errors.New("threshold < 1; not possible")

	// ErrInvalidSignatureLength occurs when marshalled signature is not
	// 6*32 bytes in length.
	ErrInvalidSignatureLength = errors.New("marshalled Signature: incorrect byte length")

	// ErrMissingIndex occurs when a public key is missing from the array
	// of elements meant to store all of the public keys for computing
	// public indices.
	ErrMissingIndex = errors.New("unable to find index for missing public key")

	// ErrBelowThreshold occurs when there are not enough signatures present
	// to sign a message.
	ErrBelowThreshold = errors.New("signatures below required threshold")

	// ErrLIArrayMismatch occurs in LagrangeInterpolationG1 when pointsG1
	// and indices arrays do not have the same length.
	ErrLIArrayMismatch = errors.New("lagrangeInterpolation: Mismatch between interpolation points and indices")

	// ErrInsufficientData occurs when attempting to Unmarshal bytes to form
	// G1, G2, or GT element, which requires 32, 2*32, or 12*32 bytes,
	// respectively.
	ErrInsufficientData = errors.New("cloudflare: Insufficient data to construct point")

	// ErrMalformedPoint occurs when submitted byte slice does not correspond
	// to valid curve point in G1, G2, or GT.
	ErrMalformedPoint = errors.New("cloudflare: Byte slice yielded invalid curve point")

	// ErrDLEQInvalidProof occurs when the submitted DLEQ proof is invalid.
	ErrDLEQInvalidProof = errors.New("invalid DLEQ Proof")

	// ErrInvalidCoordinate occurs when submitted gfP coordinate equals
	// or exceeds modulus P.
	ErrInvalidCoordinate = errors.New("cloudflare: coordinate equals or exceeds modulus")

	// ErrMismatchedSlices occurs when signature and index slices have
	// different lengths.
	ErrMismatchedSlices = errors.New("sig and indices slices have different lengths")

	// ErrArrayMismatch occurs when attempting to condense the encrypted
	// big.Ints from other participants into one array but the lengths
	// do not match.
	ErrArrayMismatch = errors.New("arrays have incompatible lengths")
)
View Source
var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")

Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. Needs to be highly 2-adic for efficient SNARK key and proof generation. Order - 1 = 2^28 * 3^2 * 13 * 29 * 983 * 11003 * 237073 * 405928799 * 1670836401704629 * 13818364434197438864469338081. Refer to https://eprint.iacr.org/2013/879.pdf and https://eprint.iacr.org/2013/507.pdf for more information on these parameters.

View Source
var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583")

P is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1.

Functions

func CompareSharedSecret

func CompareSharedSecret(secret *big.Int, j int, pubCoefs []*G1) error

CompareSharedSecret determines if shared secret is valid, returning nil if true and raising an error otherwise; pubCoefs are from participant i for participant j (who is calling this function).

func CondenseCommitments

func CondenseCommitments(pubK *G1, combinedCommitments [][]*big.Int, pubKs []*G1) ([]*big.Int, error)

CondenseCommitments takes all of the commitments from pubK (assumed to be a member of the appropriately sorted pubKs array) and condenses them into a single array of the correct length which contains all of the encrypted values for pubK.

func ConstructPrivatePolyCoefs

func ConstructPrivatePolyCoefs(r io.Reader, threshold int) ([]*big.Int, error)

ConstructPrivatePolyCoefs makes coefficients for private polynomial for sharing shared secrets. The shared secret is the constant term (first value). This private polynomial is part of the Verifiable Secret Sharing protocol in the distributed key generation protocol.

func Decrypt

func Decrypt(encryptedValue *big.Int, privK *big.Int, pubK *G1, participantIndex int) *big.Int

Decrypt uses privK (participantIndex is the index who called this function) and pubK (who sent encryptedValue) to decrypt encryptedValue to secretValue using the shared secret. Encryption and decryption are based on using the hash of the shared secret from Diffie-Hellman Key Exchange along with the index of the recipient receiving the message as a one-time pad. Including the receiver's index ensures it is only used once.

func DecryptSS

func DecryptSS(encryptedValue *big.Int, sharedSecret *G1, participantIndex int) *big.Int

DecryptSS uses the x coordinate of the shared secret kX to decrypt encryptedValue to secretValue. See Decrypt for more information.

func Encrypt

func Encrypt(secretValue *big.Int, privK *big.Int, pubK *G1, participantIndex int) *big.Int

Encrypt uses the individual's private key privK and participantIndex's public key pubK to encrypt secretValue to encryptedValue. Encryption and decryption are based on using the hash of the shared secret from Diffie-Hellman Key Exchange along with the index of the recipient receiving the message as a one-time pad. Including the receiver's index ensures it is only used once.

func GenerateDLEQProofG1

func GenerateDLEQProofG1(x1, y1, x2, y2 *G1, alpha *big.Int, rIO io.Reader) ([2]*big.Int, error)

GenerateDLEQProofG1 generates the discrete log equality proof, showing

y1 == x1^alpha and y2 == x2^alpha

without disclosing alpha. It is based on the premise that if w is random and

t1 == x1^w    and    t2 == x2^w,

then

x1^r * y1^c == x1^w == t1    and    x2^r * y2^c == x2^w == t2,

where c and r are chosen beforehand to satisfy

c == Hash(x1, y1, x2, y2, t1, t2)

and

r == w - alpha*c.

This is used during the distributed key generation protocol to ensure honest participation.

func GenerateDecryptedShares

func GenerateDecryptedShares(privK *big.Int, encryptedArray []*big.Int, pubKs []*G1) ([]*big.Int, error)

GenerateDecryptedShares generates the n-1 secrets from the encrypted values in encryptedArray which were generated by CondenseCommitments. Here, pubKs are the appropriately sorted public keys.

func GenerateEncryptedShares

func GenerateEncryptedShares(secretsArray []*big.Int, privK *big.Int, pubKs []*G1) ([]*big.Int, error)

GenerateEncryptedShares generates the n-1 commitments which will be submitted to everyone. These submissions are assumed to be coming from participant i. secretsArray are the shared secrets generated by i from GenerateSecretShares for the secret sharing protocol, while privK is i's private key. pubKs is the array of public keys arranged in the correct order.

To match with ETHDKG implementation, we do not include the commitment from i, the participant himself. Even so, this *is* required when computing gskj. We assume pubKs are correctly sorted.

func GenerateGroupSecretKeyPortion

func GenerateGroupSecretKeyPortion(listOfSharedSecrets []*big.Int) *big.Int

GenerateGroupSecretKeyPortion generates the portion of the group secret key gskJ from the shared secrets.

func GenerateSecretShares

func GenerateSecretShares(pubK *G1, privCoefs []*big.Int, pubKs []*G1) ([]*big.Int, error)

GenerateSecretShares creates the secrets which are to be shared among participants during the DKG process. The output of this function will then be used as input for GenerateEncryptedShares to be encrypted.

func GenerateSharedSecret

func GenerateSharedSecret(privK *big.Int, pubK *G1) (*big.Int, *big.Int)

GenerateSharedSecret computes the shared secret with respect to the individual private key privK and the public key pubK and outputs both x and y coordinates as *big.Int.

func HashFunc256

func HashFunc256(msg ...[]byte) []byte

HashFunc256 is our universal hash function with 32-byte digest. Changing this function will change *all* locations.

func MarshalSignature

func MarshalSignature(sig *G1, pubK *G2) ([]byte, error)

MarshalSignature takes in the sig and pubK and outputs byte slice of pubK bytes followed by sig bytes

func PairingCheck

func PairingCheck(a []*G1, b []*G2) bool

PairingCheck calculates the Optimal Ate pairing for a set of points.

func PrivatePolyEval

func PrivatePolyEval(privCoefs []*big.Int, j int) *big.Int

PrivatePolyEval evaluates the private polynomial to share the shared secret with participant j.

func PubkeyFromSig

func PubkeyFromSig(sig []byte) ([]byte, error)

PubkeyFromSig returns the public key bytes from a marshalled signature

func SplitPubkeySig

func SplitPubkeySig(sig []byte) ([]byte, []byte, error)

SplitPubkeySig separates the signature and public key bytes and returns them individually

func UnmarshalSignature

func UnmarshalSignature(marshalledSig []byte) (*G2, *G1, error)

UnmarshalSignature takes the marshalled signature and converts it back to the sig and pubK

func Verify

func Verify(msg []byte, sig *G1, pubK *G2, hashG1Func func(msg []byte) (*G1, error)) (bool, error)

Verify ensures that

e(sig, h2) == e(hashG1Func(msg), pubK).

To do this, we use PairingCheck because this will be called by the Ethereum Virtual Machine. Thus, we check

e(sig, h2Neg) * e(hashG1Func(msg), pubK) == 1.

Here, h2Neg is the negation (in additive notation) of h2, which is the standard generator for G2.

If we return a dangerous hash point (Infinity (the identity element) or the G1 generator or its negation), we cause verification to fail because signatures on these points can easily be forged. Hashing to these points break the security assumptions because the discrete logarithm is known.

func VerifyDLEQProofG1

func VerifyDLEQProofG1(x1, y1, x2, y2 *G1, pi [2]*big.Int) error

VerifyDLEQProofG1 verifies the discrete log proof from GenerateDLEQProofG1; returns nil for a valid proof and an error when invalid. This verifies that

y1 == x1^alpha    and    y2 == x2^alpha

without disclosing alpha. From the proof pi == (c, r), if the above equalities hold, then

x1^r * y1^c == x1^w == t1    and    x2^r * y2^c == x2^w == t2,

where w is a random value found in generating the proof. This is used during the distributed key generation protocol to ensure honest participation.

Types

type G1

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

G1 is an abstract cyclic group. The zero value is suitable for use as the output of an operation, but cannot be used as an input.

func AggregateMarshalledSignatures

func AggregateMarshalledSignatures(marshalledSigs [][]byte, listOfPubKsMarsh [][]byte, threshold int) (*G1, error)

AggregateMarshalledSignatures takes marshalled signatures and forms a group signature assuming there are no errors. See AggregateSignatures for more information specifically about signature aggregation.

listOfPubKsMarsh is the list of (marshalled) public keys in the correct order. This allows the specific order to be chosen outside of the cryptographic routines. marshalledSigs contains both the signature and the corresponding public key, which enables us to call makeIndicesArray in order to correctly perform AggregateSignatures.

func AggregateSignatures

func AggregateSignatures(sigs []*G1, indices []int, threshold int) (*G1, error)

AggregateSignatures computes the group signature from slices of signatures and public keys. In particular, given signature sig_j, we call LagrangeInterpolationG1 in order to produce

grpsig = Prod(sig_j^Rj, j).

Here, Rj is a constant which depends only on the validating set. If mpk is the master public key (the group signing key), then we have the following equality:

e(grpsig, h2) == e(hashG1Func(M), mpk).

func GeneratePrivatePublicKeys

func GeneratePrivatePublicKeys(r io.Reader) (*big.Int, *G1, error)

GeneratePrivatePublicKeys generates a private and public key pair in G1. This private/public key pair is used for the Diffie-Hellman Key Exchange encryption part of the distributed key generation protocol and *not* for signing. This is because, due to Ethereum Virtual Machine constraints, discrete logarithm equality proofs can only take place in G1.

func GeneratePublicCoefs

func GeneratePublicCoefs(privCoefs []*big.Int) []*G1

GeneratePublicCoefs computes the public group coefficients from the private coefficients. These public coefficients are used to ensure the participant is correctly performing the verifiable secret sharing protocol.

func GenerateSharedSecretG1

func GenerateSharedSecretG1(privK *big.Int, pubK *G1) *G1

GenerateSharedSecretG1 computes the shared secret from the private key privK and the public key pubK and outputs the result as an element of G1.

func HashToG1

func HashToG1(msg []byte) (*G1, error)

HashToG1 maps a byte slice into G1; we use the algorithm from Fouque and Tibouchi 2012. Domain separation in hashToBase allows us to compute t0 and t1, two elements of the base field F_p (gfP) which are from independent hash functions. From there, t0 is mapped to h0 and t1 is mapped to h1, with h0 and h1 elements of G1. Adding them together gives us our desired HashToG1 function. Taking the sum of two elements is required so that the hash function is uniform over G1; otherwise, there is a significant portion of the elliptic curve that is missed, which would mean it could not be considered a random oracle. The modification we made following Wahby and Boneh 2019 to improve efficiency invalidates the proof in Fouque and Tibouchi 2012 proving HashToG1 is indistinguishable from a random oracle. It is not currently known if the proof could be modified to match the implementation.

We throw an error whenever we map to Infinity (the identity element), the generator, or the generator's inverse. This breaks security assumptions: when we map to Infinity, anyone can be proven to sign anything; when we map to the generator or its inverse, it is possible to falsely prove the group signed the message (this happens due to the distributed key generation protocol). Thus, these cases should be handled carefully, and we instead choose to return an error.

func LagrangeInterpolationG1

func LagrangeInterpolationG1(pointsG1 []*G1, indices []int, threshold int) (*G1, error)

LagrangeInterpolationG1 will interpolate the G1 values in pointsG1 and output the interpolated value. This is used in AggregateSignatures to combine partial signatures into the final group signature. Lagrange interpolation is the same as though we were performing interpolation over the real numbers, although in this instance we are interpolating over a finite field.

The end result is

val = Prod(pointsG1[j]^Rj, j).

Here, Rj is a constant which depends only on indices. As this relates to AggregateSignatures, the Rj constants only depend upon the signers themselves.

func RandomG1

func RandomG1(r io.Reader) (*big.Int, *G1, error)

RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r.

func Sign

func Sign(msg []byte, privK *big.Int, hashG1Func func(msg []byte) (*G1, error)) (*G1, error)

Sign generates a signature based on the message, private key, and Hash-to-G1 function

func (*G1) Add

func (e *G1) Add(a, b *G1) *G1

Add sets e to a+b and then returns e.

func (*G1) IsEqual

func (e *G1) IsEqual(a *G1) bool

IsEqual checks to see if e and a are equal

func (*G1) Marshal

func (e *G1) Marshal() []byte

Marshal converts e to a byte slice.

func (*G1) Neg

func (e *G1) Neg(a *G1) *G1

Neg sets e to -a and then returns e.

func (*G1) ScalarBaseMult

func (e *G1) ScalarBaseMult(k *big.Int) *G1

ScalarBaseMult sets e to g*k where g is the generator of the group and then returns e.

func (*G1) ScalarMult

func (e *G1) ScalarMult(a *G1, k *big.Int) *G1

ScalarMult sets e to a*k and then returns e.

func (*G1) Set

func (e *G1) Set(a *G1) *G1

Set sets e to a and then returns e.

func (*G1) String

func (e *G1) String() string

func (*G1) Unmarshal

func (e *G1) Unmarshal(m []byte) ([]byte, error)

Unmarshal sets e to the result of converting the output of Marshal back into a group element.

type G2

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

G2 is an abstract cyclic group. The zero value is suitable for use as the output of an operation, but cannot be used as an input.

func HashToG2

func HashToG2(msg []byte) (*G2, error)

HashToG2 maps a byte slice into G2; while baseToTwist maps only to the twist curve, we clear the cofactor to ensure the hash point lies on G2. Because we map from Fp2 to Twist in the same way as above in HashToG1, it is likely the proof carries over, ensuring that “HashToTwist” (HashToG2 without clearing the cofactor) is indistinguishable from a random oracle on Twist. If this were the case, it would follow that HashToG2 is indistinguishable from a random oracle. It is not currently known if HashToG2 is indistinguishable from a random oracle.

func RandomG2

func RandomG2(r io.Reader) (*big.Int, *G2, error)

RandomG2 returns x and g₂ˣ where x is a random, non-zero number read from r.

func (*G2) Add

func (e *G2) Add(a, b *G2) *G2

Add sets e to a+b and then returns e.

func (*G2) IsEqual

func (e *G2) IsEqual(a *G2) bool

IsEqual checks to see if e and a are equal

func (*G2) Marshal

func (e *G2) Marshal() []byte

Marshal converts e into a byte slice.

func (*G2) Neg

func (e *G2) Neg(a *G2) *G2

Neg sets e to -a and then returns e.

func (*G2) ScalarBaseMult

func (e *G2) ScalarBaseMult(k *big.Int) *G2

ScalarBaseMult sets e to g*k where g is the generator of the group and then returns e.

func (*G2) ScalarMult

func (e *G2) ScalarMult(a *G2, k *big.Int) *G2

ScalarMult sets e to a*k and then returns e.

func (*G2) Set

func (e *G2) Set(a *G2) *G2

Set sets e to a and then returns e.

func (*G2) String

func (e *G2) String() string

func (*G2) Unmarshal

func (e *G2) Unmarshal(m []byte) ([]byte, error)

Unmarshal sets e to the result of converting the output of Marshal back into a group element.

type GT

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

GT is an abstract cyclic group. The zero value is suitable for use as the output of an operation, but cannot be used as an input.

func Miller

func Miller(g1 *G1, g2 *G2) *GT

Miller applies Miller's algorithm, which is a bilinear function from the source groups to F_p^12. Miller(g1, g2).Finalize() is equivalent to Pair(g1, g2).

func Pair

func Pair(g1 *G1, g2 *G2) *GT

Pair calculates an Optimal Ate pairing.

func (*GT) Add

func (e *GT) Add(a, b *GT) *GT

Add sets e to a+b and then returns e.

func (*GT) Finalize

func (e *GT) Finalize() *GT

Finalize is a linear function from F_p^12 to GT.

func (*GT) IsEqual

func (e *GT) IsEqual(a *GT) bool

IsEqual checks to see if e and a are equal

func (*GT) Marshal

func (e *GT) Marshal() []byte

Marshal converts e into a byte slice.

func (*GT) Neg

func (e *GT) Neg(a *GT) *GT

Neg sets e to -a and then returns e.

func (*GT) ScalarMult

func (e *GT) ScalarMult(a *GT, k *big.Int) *GT

ScalarMult sets e to a*k and then returns e.

func (*GT) Set

func (e *GT) Set(a *GT) *GT

Set sets e to a and then returns e.

func (*GT) String

func (e *GT) String() string

func (*GT) Unmarshal

func (e *GT) Unmarshal(m []byte) ([]byte, error)

Unmarshal sets e to the result of converting the output of Marshal back into a group element.

Jump to

Keyboard shortcuts

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