Commit 2b381cc0 authored by Anders Jensen Løvig's avatar Anders Jensen Løvig
Browse files

Elgamal implementation

parent 32d58156
package elgamal
import (
"crycomp/internal/blood/crypto/group"
"crypto/rand"
"errors"
"io"
"math/big"
)
var one = big.NewInt(1)
var two = big.NewInt(2)
type PublicKey struct {
P, Q, G, H *big.Int
}
type PrivateKey struct {
PublicKey
X *big.Int
}
// GenerateKey returns an Elgamal private key by choosing an element x in Zq
// and then computing h = g^x mod p in Gq for the public key. The private key
// is (G, x) and public key is (G, h).
func GenerateKey(random io.Reader, params *group.Params) (priv *PrivateKey, err error) {
x, err := rand.Int(random, params.Q)
if err != nil {
return nil, err
}
h := new(big.Int).Exp(params.G, x, params.P)
pub := PublicKey{
P: params.P,
Q: params.Q,
G: params.G,
H: h,
}
priv = &PrivateKey{
PublicKey: pub,
X: x,
}
return // return priv and err
}
// Encrypt msg using textbook Elgamal
func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
m := new(big.Int).SetBytes(msg)
if m.Cmp(pub.Q) != -1 {
return nil, nil, errors.New("elgamal: message to large")
}
m = encodeMessage(pub, m)
// TODO m must not b zero
r, err := randInt(random, pub.Q)
if err != nil {
return
}
c1 = new(big.Int).Exp(pub.G, r, pub.P)
s := new(big.Int).Exp(pub.H, r, pub.P)
c2 = s.Mul(s, m)
c2.Mod(c2, pub.P)
return
}
func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
s := new(big.Int).Exp(c1, priv.X, priv.P)
if s.ModInverse(s, priv.P) == nil {
return nil, errors.New("elgamal: invalid private key")
}
s.Mul(s, c2)
s.Mod(s, priv.P)
m := decodeMessage(priv, s)
msg = m.Bytes()
return
}
func encodeMessage(pub *PublicKey, x *big.Int) (m *big.Int) {
m = new(big.Int).Add(x, one)
exp := new(big.Int).Set(pub.Q)
if exp.Exp(m, exp, pub.P).Cmp(one) == 0 {
return m
} else {
m.Neg(m)
return m.Mod(m, pub.P)
}
}
func decodeMessage(priv *PrivateKey, x *big.Int) (m *big.Int) {
m = new(big.Int)
if x.Cmp(priv.Q) != 1 {
m.Set(x)
} else {
m.Neg(x)
m.Mod(m, priv.P)
}
return m.Sub(m, one)
}
func randInt(random io.Reader, q *big.Int) (r *big.Int, err error) {
tmp := new(big.Int).Set(q)
tmp.Sub(tmp, one)
r, err = rand.Int(random, tmp)
if err != nil {
return
}
r.Add(r, one)
return
}
package elgamal
import (
"bytes"
"crycomp/internal/blood/crypto/group"
"crypto/rand"
"fmt"
"math/big"
"testing"
)
func TestEncryptIntegers(t *testing.T) {
priv := &PrivateKey{
PublicKey: PublicKey{
P: big.NewInt(11),
Q: big.NewInt(5),
G: big.NewInt(3),
},
X: big.NewInt(3),
}
priv.H = new(big.Int).Exp(priv.G, priv.X, priv.P)
for i := 0; i < 5; i++ {
t.Run(fmt.Sprintf("Encrypt %d", i), func(t *testing.T) {
message := []byte{byte(i)}
c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
if err != nil {
t.Errorf("error encrypting: %s", err)
}
message2, err := Decrypt(priv, c1, c2)
if err != nil {
t.Errorf("error decrypting: %s", err)
}
msg1 := new(big.Int).SetBytes(message)
msg2 := new(big.Int).SetBytes(message2)
if msg1.Cmp(msg2) != 0 {
t.Errorf("decryption failed, got %x, want %x", message2, message)
}
})
}
}
func TestEncryptDecrypt(t *testing.T) {
params := group.Default()
priv, err := GenerateKey(rand.Reader, params)
if err != nil {
t.Fatalf("error generating key: %s", err)
}
message := []byte("hello world")
c1, c2, err := Encrypt(rand.Reader, &priv.PublicKey, message)
if err != nil {
t.Errorf("error encrypting: %s", err)
}
message2, err := Decrypt(priv, c1, c2)
if err != nil {
t.Errorf("error decrypting: %s", err)
}
if !bytes.Equal(message2, message) {
t.Errorf("decryption failed, got: %x, want: %x", message2, message)
}
}
package group
import "math/big"
// String constants for default primes
const (
// 2048 bits
pHex = "df0df2d4d4320d6f562ddf3ef2ba7b96463e8ba2b6d965a7b377521434dea91ffc299287efc0d495e58fc33cacfc02d2ed819c83bd66b4ebf5373a001adf1b18b0a80c4df6bb372708479c3afa081ae913b99c6b74906b6d497f7752a54869d9542097b98e7373d6643cc3533197ff8160a7d79791ce3e5f53c43a89cf8f4f9fd3afd5cdc6902784daa97715ef73ba8f5d69c2f8e0e901c35917b8d081f38ae07e59df580515fdcb38a718de4c512353658f4e622ed88b7379893907e7d59df22c427f4b04fd0bfbb40e650907c25d61f0cdc7dc2f677841ee06a60ed8206e7ec46684a8716a9470aa19cb221ea1bce00f59067ce4439fd04be0c370e9f3f487"
qHex = "6f86f96a6a1906b7ab16ef9f795d3dcb231f45d15b6cb2d3d9bba90a1a6f548ffe14c943f7e06a4af2c7e19e567e016976c0ce41deb35a75fa9b9d000d6f8d8c58540626fb5d9b938423ce1d7d040d7489dcce35ba4835b6a4bfbba952a434ecaa104bdcc739b9eb321e61a998cbffc0b053ebcbc8e71f2fa9e21d44e7c7a7cfe9d7eae6e34813c26d54bb8af7b9dd47aeb4e17c707480e1ac8bdc6840f9c5703f2cefac028afee59c538c6f262891a9b2c7a731176c45b9bcc49c83f3eacef916213fa5827e85fdda07328483e12eb0f866e3ee17b3bc20f70353076c10373f6233425438b54a38550ce5910f50de7007ac833e7221cfe825f061b874f9fa43"
gHex = "2"
)
var one = big.NewInt(1)
// Params contains the paramerets for discrete-logarithm public key cryptology.
type Params struct {
P, Q, G *big.Int
}
func New(p, q, g *big.Int) *Params {
temp := new(big.Int)
if !p.ProbablyPrime(20) {
panic("p is not prime")
}
if !q.ProbablyPrime(20) {
panic("q is not prime")
}
if temp.Exp(g, q, p).Cmp(one) != 0 {
panic("g is not a generator for Gq")
}
return &Params{p, q, g}
}
func Default() *Params {
return New(
fromHex(pHex),
fromHex(qHex),
fromHex(gHex))
}
func fromHex(hex string) *big.Int {
n, ok := new(big.Int).SetString(hex, 16)
if !ok {
panic("failed to parse hex")
}
return n
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment