examples

package
v1.1.13 Latest Latest
Warning

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

Go to latest
Published: Aug 4, 2022 License: MPL-2.0 Imports: 0 Imported by: 0

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.

Jump to

Keyboard shortcuts

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