package examples
import "go.dedis.ch/kyber/v3/examples"
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.
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.
Code:
Output: 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.
Code:play
Output: 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.
Code:play
Output: 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.
Code:play
Output:Example (DiffieHellman)¶
{
// 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) // Bob's private key
B := suite.Point().Mul(b, nil) // Bob'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
}
Shared secret: 80ea238cacfdab279626970bba18c69083c7751865dec4c6434bff4351282847
Example (ElGamalEncryption)¶
package main
import (
"fmt"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/group/edwards25519"
"go.dedis.ch/kyber/v3/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))
return
}
fmt.Println("Decryption succeeded: " + string(mm))
}
Decryption succeeded: The quick brown fox
Example (ElGamalEncryption_bn256)¶
package main
import (
"fmt"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/pairing"
"go.dedis.ch/kyber/v3/util/random"
)
func ElGamalEncryptBn256(suite pairing.Suite, 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 := suite.G1().Point().Embed(message, random.New())
max := suite.G1().Point().EmbedLen()
if max > len(message) {
max = len(message)
}
remainder = message[max:]
// ElGamal-encrypt the point to produce ciphertext (K,C).
k := suite.G1().Scalar().Pick(random.New()) // ephemeral private key
K = suite.G1().Point().Mul(k, nil) // ephemeral DH public key
S := suite.G1().Point().Mul(k, pubkey) // ephemeral DH shared secret
C = suite.G1().Point().Add(S, M) // message blinded with secret
return
}
func ElGamalDecryptBn256(suite pairing.Suite, prikey kyber.Scalar, K, C kyber.Point) (
message []byte, err error) {
// ElGamal-decrypt the ciphertext (K,C) to reproduce the message.
S := suite.G1().Point().Mul(prikey, K) // regenerate shared secret
M := suite.G1().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 := pairing.NewSuiteBn256()
// Create a public/private keypair
a := suite.G1().Scalar().Pick(suite.RandomStream()) // Alice's private key
A := suite.G1().Point().Mul(a, nil) // Alice's public key
// ElGamal-encrypt a message using the public key.
m := []byte("The quick brown fox")
K, C, _ := ElGamalEncryptBn256(suite, A, m)
// Decrypt it using the corresponding private key.
mm, err := ElGamalDecryptBn256(suite, a, K, C)
// Make sure it worked!
if err != nil {
fmt.Println("decryption failed: " + err.Error())
} else if string(mm) != string(m) {
fmt.Println("decryption produced wrong output: " + string(mm))
} else {
fmt.Println("Decryption succeeded: " + string(mm))
}
}
Decryption succeeded: The quick brown fox
Example (Schnorr)¶
package main
import (
"bytes"
"crypto/cipher"
"encoding/hex"
"errors"
"fmt"
"go.dedis.ch/kyber/v3"
"go.dedis.ch/kyber/v3/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.")
}
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.
Index ¶
Examples ¶
- package (DiffieHellman)
- package (ElGamalEncryption)
- package (ElGamalEncryption_bn256)
- package (Schnorr)
Source Files ¶
main.go
- Version
- v3.1.0 (latest)
- Published
- Nov 30, 2022
- Platform
- linux/amd64
- Last checked
- 1 month ago –
Tools for package owners.