Documentation ¶
Overview ¶
Package examples provides a suite of tests showing how to use the different abstraction and protocols provided by the kyber library. To run the tests, simply do `go test -v` in this directory.
Example (DiffieHellman) ¶
This example illustrates how to use the crypto toolkit's kyber.group API to perform basic Diffie-Hellman key exchange calculations, using the NIST-standard P256 elliptic curve in this case. Any other suitable elliptic curve or other cryptographic group may be used simply by changing the first line that picks the suite.
// A pseudo RNG which makes this code repeatable for testing. rng := blake2xb.New(nil) // Crypto setup: NIST-standardized P256 curve with AES-128 and SHA-256 // For production code, simply use edwards25519.NewBlakeSHA256Ed25519(). suite := edwards25519.NewBlakeSHA256Ed25519WithRand(rng) // Alice's public/private keypair a := suite.Scalar().Pick(rng) // Alice's private key A := suite.Point().Mul(a, nil) // Alice's public key // Bob's public/private keypair b := suite.Scalar().Pick(rng) // Alice's private key B := suite.Point().Mul(b, nil) // Alice's public key // Assume Alice and Bob have securely obtained each other's public keys. // Alice computes their shared secret using Bob's public key. SA := suite.Point().Mul(a, B) // Bob computes their shared secret using Alice's public key. SB := suite.Point().Mul(b, A) // They had better be the same! if !SA.Equal(SB) { panic("Diffie-Hellman key exchange didn't work") } fmt.Println("Shared secret: " + SA.String())
Output: Shared secret: 80ea238cacfdab279626970bba18c69083c7751865dec4c6434bff4351282847
Example (ElGamalEncryption) ¶
This example illustrates how the crypto toolkit may be used to perform "pure" ElGamal encryption, in which the message to be encrypted is small enough to be embedded directly within a group element (e.g., in an elliptic curve point). For basic background on ElGamal encryption see for example http://en.wikipedia.org/wiki/ElGamal_encryption.
Most public-key crypto libraries tend not to support embedding data in points, in part because for "vanilla" public-key encryption you don't need it: one would normally just generate an ephemeral Diffie-Hellman secret and use that to seed a symmetric-key crypto algorithm such as AES, which is much more efficient per bit and works for arbitrary-length messages. However, in many advanced public-key crypto algorithms it is often useful to be able to embedded data directly into points and compute with them: as just one of many examples, the proactively verifiable anonymous messaging scheme prototyped in Verdict (see http://dedis.cs.yale.edu/dissent/papers/verdict-abs).
For fancier versions of ElGamal encryption implemented in this toolkit see for example anon.Encrypt, which encrypts a message for one of several possible receivers forming an explicit anonymity set.
package main import ( "fmt" "github.com/drand/kyber" "github.com/drand/kyber/group/edwards25519" "github.com/drand/kyber/util/random" ) func ElGamalEncrypt(group kyber.Group, pubkey kyber.Point, message []byte) ( K, C kyber.Point, remainder []byte) { // Embed the message (or as much of it as will fit) into a curve point. M := group.Point().Embed(message, random.New()) max := group.Point().EmbedLen() if max > len(message) { max = len(message) } remainder = message[max:] // ElGamal-encrypt the point to produce ciphertext (K,C). k := group.Scalar().Pick(random.New()) // ephemeral private key K = group.Point().Mul(k, nil) // ephemeral DH public key S := group.Point().Mul(k, pubkey) // ephemeral DH shared secret C = S.Add(S, M) // message blinded with secret return } func ElGamalDecrypt(group kyber.Group, prikey kyber.Scalar, K, C kyber.Point) ( message []byte, err error) { // ElGamal-decrypt the ciphertext (K,C) to reproduce the message. S := group.Point().Mul(prikey, K) // regenerate shared secret M := group.Point().Sub(C, S) // use to un-blind the message message, err = M.Data() // extract the embedded data return } /* This example illustrates how the crypto toolkit may be used to perform "pure" ElGamal encryption, in which the message to be encrypted is small enough to be embedded directly within a group element (e.g., in an elliptic curve point). For basic background on ElGamal encryption see for example http://en.wikipedia.org/wiki/ElGamal_encryption. Most public-key crypto libraries tend not to support embedding data in points, in part because for "vanilla" public-key encryption you don't need it: one would normally just generate an ephemeral Diffie-Hellman secret and use that to seed a symmetric-key crypto algorithm such as AES, which is much more efficient per bit and works for arbitrary-length messages. However, in many advanced public-key crypto algorithms it is often useful to be able to embedded data directly into points and compute with them: as just one of many examples, the proactively verifiable anonymous messaging scheme prototyped in Verdict (see http://dedis.cs.yale.edu/dissent/papers/verdict-abs). For fancier versions of ElGamal encryption implemented in this toolkit see for example anon.Encrypt, which encrypts a message for one of several possible receivers forming an explicit anonymity set. */ func main() { suite := edwards25519.NewBlakeSHA256Ed25519() // Create a public/private keypair a := suite.Scalar().Pick(suite.RandomStream()) // Alice's private key A := suite.Point().Mul(a, nil) // Alice's public key // ElGamal-encrypt a message using the public key. m := []byte("The quick brown fox") K, C, _ := ElGamalEncrypt(suite, A, m) // Decrypt it using the corresponding private key. mm, err := ElGamalDecrypt(suite, a, K, C) // Make sure it worked! if err != nil { fmt.Println("decryption failed: " + err.Error()) } if string(mm) != string(m) { fmt.Println("decryption produced wrong output: " + string(mm)) } fmt.Println("Decryption succeeded: " + string(mm)) }
Output: Decryption succeeded: The quick brown fox
Example (Schnorr) ¶
This example shows how to perform a simple Schnorr signature. Please, use this example as a reference to understand the abstraction only. There is a `sign/schnorr` package which provides Schnorr signatures functionality in a more secure manner.
package main import ( "bytes" "crypto/cipher" "encoding/hex" "errors" "fmt" "github.com/drand/kyber" "github.com/drand/kyber/group/edwards25519" ) type Suite interface { kyber.Group kyber.Encoding kyber.XOFFactory } // A basic, verifiable signature type basicSig struct { C kyber.Scalar // challenge R kyber.Scalar // response } // Returns a secret that depends on on a message and a point func hashSchnorr(suite Suite, message []byte, p kyber.Point) kyber.Scalar { pb, _ := p.MarshalBinary() c := suite.XOF(pb) c.Write(message) return suite.Scalar().Pick(c) } // This simplified implementation of Schnorr Signatures is based on // crypto/anon/sig.go // The ring structure is removed and // The anonimity set is reduced to one public key = no anonimity func SchnorrSign(suite Suite, random cipher.Stream, message []byte, privateKey kyber.Scalar) []byte { // Create random secret v and public point commitment T v := suite.Scalar().Pick(random) T := suite.Point().Mul(v, nil) // Create challenge c based on message and T c := hashSchnorr(suite, message, T) // Compute response r = v - x*c r := suite.Scalar() r.Mul(privateKey, c).Sub(v, r) // Return verifiable signature {c, r} // Verifier will be able to compute v = r + x*c // And check that hashElgamal for T and the message == c buf := bytes.Buffer{} sig := basicSig{c, r} _ = suite.Write(&buf, &sig) return buf.Bytes() } func SchnorrVerify(suite Suite, message []byte, publicKey kyber.Point, signatureBuffer []byte) error { // Decode the signature buf := bytes.NewBuffer(signatureBuffer) sig := basicSig{} if err := suite.Read(buf, &sig); err != nil { return err } r := sig.R c := sig.C // Compute base**(r + x*c) == T var P, T kyber.Point P = suite.Point() T = suite.Point() T.Add(T.Mul(r, nil), P.Mul(c, publicKey)) // Verify that the hash based on the message and T // matches the challange c from the signature c = hashSchnorr(suite, message, T) if !c.Equal(sig.C) { return errors.New("invalid signature") } return nil } // This example shows how to perform a simple Schnorr signature. Please, use this // example as a reference to understand the abstraction only. There is a // `sign/schnorr` package which provides Schnorr signatures functionality in a // more secure manner. func main() { // Crypto setup suite := edwards25519.NewBlakeSHA256Ed25519() rand := suite.XOF([]byte("example")) // Create a public/private keypair (X,x) x := suite.Scalar().Pick(rand) // create a private key x X := suite.Point().Mul(x, nil) // corresponding public key X // Generate the signature M := []byte("Hello World!") // message we want to sign sig := SchnorrSign(suite, rand, M, x) fmt.Print("Signature:\n" + hex.Dump(sig)) // Verify the signature against the correct message err := SchnorrVerify(suite, M, X, sig) if err != nil { panic(err.Error()) } fmt.Println("Signature verified against correct message.") }
Output: Signature: 00000000 67 3f 25 fe d1 51 5d 1e 64 3a f7 79 2f 55 53 7c |g?%..Q].d:.y/US|| 00000010 f6 8a 5a 73 d5 c7 db f4 07 58 37 cc 1c b8 bf 02 |..Zs.....X7.....| 00000020 5f 0b a0 ef 0e 3e 9d 2e 08 10 69 b9 82 5f 65 b3 |_....>....i.._e.| 00000030 51 f8 b8 59 9b 72 d1 d0 12 f0 c6 ac 00 2a 09 0f |Q..Y.r.......*..| Signature verified against correct message.