115 lines
1.9 KiB
Go
115 lines
1.9 KiB
Go
package elgamal
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"errors"
|
|
"io"
|
|
"math/big"
|
|
|
|
"xdx.jelly/xgcl/grand"
|
|
)
|
|
|
|
var Reader = grand.Reader
|
|
|
|
type Params struct {
|
|
isMont bool // Is Montgomery represent
|
|
p *big.Int
|
|
q *big.Int
|
|
g *big.Int
|
|
pMont *big.Int
|
|
qMont *big.Int
|
|
gMont *big.Int
|
|
}
|
|
|
|
func (p *Params) P() *big.Int {
|
|
return p.p
|
|
}
|
|
func (p *Params) Q() *big.Int {
|
|
return p.q
|
|
}
|
|
func (p *Params) G() *big.Int {
|
|
return p.g
|
|
}
|
|
|
|
type PublicKey struct {
|
|
y big.Int
|
|
Params *Params
|
|
}
|
|
|
|
type PrivateKey struct {
|
|
x big.Int
|
|
PublicKey
|
|
}
|
|
type Cipher struct {
|
|
u big.Int
|
|
v big.Int
|
|
}
|
|
|
|
func GenerateKey(rnd io.Reader, params *Params) (*PrivateKey, *PublicKey, error) {
|
|
x, err := rand.Int(rnd, params.q)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
y := new(big.Int).Exp(params.g, x, params.p)
|
|
sk := &PrivateKey{
|
|
x: *x,
|
|
PublicKey: PublicKey{
|
|
y: *y,
|
|
Params: P1024,
|
|
},
|
|
}
|
|
pk := &sk.PublicKey
|
|
return sk, pk, nil
|
|
}
|
|
|
|
// m = g^M mod p for some M
|
|
// rnd can be nil, io.Reader or []byte
|
|
func (pk *PublicKey) Encryption(m *big.Int, rnd any) (*Cipher, error) {
|
|
var r *big.Int
|
|
var err error
|
|
p := pk.Params.p
|
|
q := pk.Params.q
|
|
g := pk.Params.g
|
|
|
|
switch rnd := rnd.(type) {
|
|
case nil:
|
|
rnd = Reader
|
|
case io.Reader:
|
|
r, err = rand.Int(rnd, q)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case []byte:
|
|
r = new(big.Int).SetBytes(rnd)
|
|
if r.Cmp(q) >= 0 {
|
|
return nil, errors.New("random bytes too large")
|
|
}
|
|
default:
|
|
return nil, errors.New("rnd must be io.Reader or []bytes")
|
|
}
|
|
|
|
c := &Cipher{}
|
|
c.u.Exp(g, r, p)
|
|
c.v.Exp(&pk.y, r, p)
|
|
c.v.Mul(&c.v, m)
|
|
return c, nil
|
|
}
|
|
|
|
func (sk *PrivateKey) Decryption(c *Cipher) (*big.Int, error) {
|
|
p := sk.PublicKey.Params.p
|
|
u := &c.u
|
|
v := &c.v
|
|
z := new(big.Int)
|
|
z.Exp(u, &sk.x, p)
|
|
z.ModInverse(z, p)
|
|
z.Mul(z, v)
|
|
z.Mod(z, p)
|
|
return z, nil
|
|
}
|
|
|
|
func (c *Cipher) HomoMap(c1 *Cipher, c2 *Cipher) (*Cipher, error) {
|
|
c.u.Mul(&c1.u, &c2.u)
|
|
c.v.Mul(&c1.v, &c2.v)
|
|
return c, nil
|
|
}
|