Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Thomas Hoffmann
CryComp
Commits
2b381cc0
Commit
2b381cc0
authored
Sep 26, 2021
by
Anders Jensen Løvig
Browse files
Elgamal implementation
parent
32d58156
Changes
3
Hide whitespace changes
Inline
Side-by-side
internal/blood/crypto/elgamal/elgamal.go
0 → 100644
View file @
2b381cc0
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
}
internal/blood/crypto/elgamal/elgamal_test.go
0 → 100644
View file @
2b381cc0
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
)
}
}
internal/blood/crypto/group/group.go
0 → 100644
View file @
2b381cc0
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
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment