init: v1.0.0

This commit is contained in:
yaole
2026-05-27 23:03:00 +08:00
commit 8d97f750eb
466 changed files with 80067 additions and 0 deletions
+60
View File
@@ -0,0 +1,60 @@
//go:build ignore
// +build ignore
package paillier
import (
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/sm/sm4"
)
func TestEnv(t *testing.T) {
sk, pk, err := GenerateKey(2048)
assert.Nil(t, err)
for i := 0; i < 1000; i++ {
kek := grand.GetRandom(16) //[]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
mykey := grand.GetRandom(16)
mykeyPaillierCipher, err := EncryptKey(mykey, pk)
assert.Nil(t, err)
iv, mykeyEnvelopeCipher, err := GenEnvelope(mykeyPaillierCipher, kek, pk)
assert.Nil(t, err)
mykeyEnvelope, err := DecryptEnvelope(mykeyEnvelopeCipher, sk) // mykeyEnvelope = SM4CTREnc(kek, mykey) = sm4.Enc(kek, iv) ^ key
assert.Nil(t, err)
// recover mykey from mykeyEnvelope
mykey2 := DecryptKey(iv []byte, keyEnvelope []byte, pk *PublicKey)
// check
key2, err := sm4.EncryptECB(nil, kek, iv)
assert.Nil(t, err)
for i := range key2 {
key2[i] ^= ctrEncKey[i]
}
assert.Equal(t, key, key2)
}
}
func TestEncKey(t *testing.T) {
key := grand.GetRandom(128)
sk, pk, err := GenerateKey(2048)
assert.Nil(t, err)
c, err := EncryptKey(key, pk)
assert.Nil(t, err)
key2, err := DecryptKey(c, 128, sk)
assert.Nil(t, err)
assert.Equal(t, key, key2)
}
+110
View File
@@ -0,0 +1,110 @@
//go:build ignore
// +build ignore
package paillier
// envelope provide hybrid encryption for a user with a remote cryptographic server.
// The server has a KEK and the user wants to encrypt a file.
// 1. The user generate a random user key ukey
// 2. The user use ukey to encrypt the file
// 3. The user do the followings to encrypt the ukey with KEK without leaking ukey to the server:
// 3-0. The user generate a (temporary or long term) paillier key pair (sk, pk).
// 3-1. The user encrypt ukey with paillier encryption: ukeyCipher = PaiEnc(ukey, pk)
// 3-2. The server HOMOMORPHICLY encrypt ukey with KEK: ukeyEnvelopeCipher = PaiEnc(SM4Enc(ukey, KEK), pk)
// 3-3. The user decrypt ukeyEnvelopeCipher and get ukeyEnvelope = SM4Enc(ukey, KEK)
//
// The user do the following to decrypt the ukey and then to decrypt the file.
// Also without leaking ukey.
// 1. The user generate a (temporary or long term) paillier key pair (sk, pk).
// 2. User encrypt ukeyEnvelope: ukeyEnvelopeCipher = PaiEnc(ukeyEnvelope, pk)
// 3. The server HOMORPHICLY decrypt ukeyEnvelopeCipher: ukeyCipher = PaiEnc(ukey, pk)
// 4. The user decrypt ukeyCipher, with ukey.
import (
"fmt"
"math/big"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/sm/sm4"
)
// xyzw => 0x0y0z0w
var tbl = []byte{0, 1, 4, 5, 16, 17, 20, 21, 64, 65, 68, 69, 80, 81, 84, 85}
type EnvelopeUser struct{}
type EnvelopeServer struct{}
// EncryptUserKey
func (EnvelopeUser) EncryptUserKey(ukey []byte, pk *PublicKey) (ukeyCipher *Cipher, err error) {
if len(ukey)*8*2 > pk.Bits() {
return nil, fmt.Errorf("input key too long, should less than %d bytes", pk.Bits()/8/2)
}
buf := make([]byte, 0, len(ukey)*2)
for _, k := range ukey {
buf = append(buf, tbl[k&0xf])
buf = append(buf, tbl[k>>4])
}
return pk.Encrypt(new(big.Int).SetBytes(buf), grand.Reader)
}
func DecryptKey(c *Cipher, keyLength int, priKey *PrivateKey) ([]byte, error) {
k, err := priKey.Decrypt(c)
_ = err
key2 := make([]byte, keyLength*2)
k.FillBytes(key2)
key := make([]byte, keyLength)
for i := 0; i < len(key); i++ {
x := key2[2*i]
y := key2[2*i+1]
n := byte(0)
n |= (x >> 0) & 1
n |= (x >> 1) & 2
n |= (x >> 2) & 4
n |= (x >> 3) & 8
key[i] = n
n = byte(0)
n |= (y >> 0) & 1
n |= (y >> 1) & 2
n |= (y >> 2) & 4
n |= (y >> 3) & 8
key[i] |= (n << 4)
}
return key, nil
}
func GenEnvelope(c0 *Cipher, kek []byte, pubkey *PublicKey) ([]byte, *Cipher, error) {
iv := grand.GetRandom(16)
c1, err := sm4.EncryptECB(nil, kek, iv) // c1 = sm4.Enc(iv)
c2, err := EncryptUserKey(c1, pubkey) // c2 = PaiEnc(sm4.Enc(iv))
c2.HomomorphicAdd(c2, c0, pubkey) // c2 = PaiEnc(sm4.Enc(iv) ^ key)
_ = err
return iv, c2, nil
}
func DecryptEnvelope(c *Cipher, prikey *PrivateKey) ([]byte, error) {
k, err := prikey.Decrypt(c)
_ = err
key2 := make([]byte, 32)
k.FillBytes(key2)
key := make([]byte, 16)
for i := 0; i < 16; i++ {
x := key2[2*i]
y := key2[2*i+1]
n := byte(0)
n |= (x >> 0) & 1
n |= (x >> 1) & 2
n |= (x >> 2) & 4
n |= (x >> 3) & 8
key[i] = n
n = byte(0)
n |= (y >> 0) & 1
n |= (y >> 1) & 2
n |= (y >> 2) & 4
n |= (y >> 3) & 8
key[i] |= (n << 4)
}
return key, nil
}
+363
View File
@@ -0,0 +1,363 @@
package paillier
import (
"crypto/rand"
"crypto/rsa"
"sync"
"errors"
"io"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/pbkd"
)
//
// PublicKey ::= INTEGER
//
// PrivateKey ::= SEQUENCE{
// lambda INTEGER,
// N INTEGER
// }
//
// Cipher ::= INTEGER
type PublicKey struct {
N *big.Int
N2 *big.Int
mu sync.Mutex // guard rn
rn *big.Int
}
type PrivateKey struct {
PublicKey
lambda *big.Int
// option
lambdaInv *big.Int
p, q *big.Int
}
func (k *PrivateKey) Public() *PublicKey {
if k.PublicKey.N2 == nil {
k.PublicKey.N2 = new(big.Int).Mul(k.PublicKey.N, k.PublicKey.N)
}
if k.rn == nil {
k.Precompute(grand.Reader)
}
return &k.PublicKey
}
// Cipher the member variable D is for gcl's internal use.
// You should never use it except you know what you're doing.
type Cipher struct {
D *big.Int
}
func newPrivateKey(p *big.Int, q *big.Int) *PrivateKey {
sk := &PrivateKey{
PublicKey: PublicKey{
N: new(big.Int).Mul(p, q),
},
lambda: new(big.Int),
lambdaInv: new(big.Int),
}
pk := sk.Public()
// lambda = LCM(p-1, q-1) or just (p-1)*(q-1)
// lcm(sk.lambda, new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
sk.lambda.Mul(new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
sk.lambdaInv.ModInverse(sk.lambda, pk.N)
return sk
}
// return l = lcm(a,b)
func lcm(l, a, b *big.Int) {
d := new(big.Int).GCD(nil, nil, a, b)
l.Mul(a, b)
l.Div(l, d)
}
// GenerateKey 生成同态密钥. bits 应为2048.
// rnd_opt 可选, 忽略则使用grand.Reader.
func GenerateKey(bits int, rnd_opt ...io.Reader) (*PrivateKey, *PublicKey, error) {
var rnd io.Reader
if len(rnd_opt) > 0 {
rnd = rnd_opt[0]
} else {
rnd = grand.Reader
}
priKey := &PrivateKey{}
rsaKey, err := rsa.GenerateKey(rnd, bits)
if err != nil {
return nil, nil, err
}
priKey = newPrivateKey(rsaKey.Primes[0], rsaKey.Primes[1])
return priKey, &priKey.PublicKey, nil
}
func (k *PrivateKey) Decrypt(c *Cipher) (*big.Int, error) {
if c.D == nil || c.D.Cmp(k.N2) >= 0 {
return nil, errors.New("invalid cipher")
}
if k.lambdaInv == nil {
k.lambdaInv = new(big.Int).ModInverse(k.lambda, k.N)
}
pk := k.Public()
d := c.D
L := new(big.Int)
L.Exp(d, k.lambda, pk.N2) // L = c^lambda mod n^2
L.Sub(L, gmath.BigInt1)
L.Div(L, pk.N) // L = (c^lambda - 1)/n
L.Mul(L, k.lambdaInv)
L.Mod(L, pk.N)
return L, nil
}
func (k *PublicKey) Bits() int {
return k.N.BitLen()
}
// Precompute computes r^N mod N^2 for a random r.
func (k *PublicKey) Precompute(rnd io.Reader) error {
if k.rn != nil {
return nil
}
k.mu.Lock()
defer k.mu.Unlock()
if k.N2 == nil {
k.N2 = new(big.Int).Mul(k.N, k.N)
}
if k.rn != nil {
return nil
}
buf := make([]byte, k.N.BitLen()/2)
_, err := rnd.Read(buf)
if err != nil {
return err
}
buf[0] |= 1 // at least one
r := new(big.Int).SetBytes(buf)
r.Exp(r, k.N, k.N2) // r = r^n mod n^2
k.rn = r
return nil
}
func (k *PublicKey) Encrypt(m *big.Int, rnd io.Reader) (*Cipher, error) {
if true {
k.Precompute(grand.Reader)
rn := new(big.Int).SetBytes(grand.GetRandom(12))
rn.Exp(k.rn, rn, k.N2)
d := new(big.Int)
d.Mul(k.N, m) // d = n * m
d.Add(d, gmath.BigInt1) // d = nm + 1
d.Mul(d, rn) // c = (nm+1)*r^n mod n^2
d.Mod(d, k.N2)
return &Cipher{D: d}, nil
} else {
// r should select from (1, N)
var r *big.Int
var err error
for {
r, err = rand.Int(rnd, k.N)
if err != nil {
return nil, err
}
// should we check gcd(r,n) == 1?
if r.Sign() > 0 {
break
}
}
d := new(big.Int)
d.Mul(k.N, m) // d = n * m
d.Add(d, gmath.BigInt1) // d = nm + 1
r.Exp(r, k.N, k.N2) // r = r^n mod n^2
// r.SetUint64(1)
d.Mul(d, r) // c = (nm+1)*r^n mod n^2
d.Mod(d, k.N2)
return &Cipher{D: d}, nil
}
}
func Encrypt(m *big.Int, publicKey *PublicKey, rnd io.Reader) (*Cipher, error) {
return publicKey.Encrypt(m, rnd)
}
func Decrypt(c *Cipher, key *PrivateKey) (*big.Int, error) {
return key.Decrypt(c)
}
func GenerateKeyFromPassword(bits int, password []byte, salt []byte, count int) (*PrivateKey, error) {
b, err := pbkd.PbkdfWithHmacSm3(password, salt, count, int64((bits+15)/16))
pBits := bits / 2
if err != nil {
return nil, err
}
p := big.NewInt(0).SetBytes(b)
p.SetBit(p, 0, 1)
p.SetBit(p, pBits-1, 1)
for !p.ProbablyPrime(20) {
p.Add(p, big.NewInt(2))
}
b, err = pbkd.PbkdfWithHmacSm3(password, salt, count+1, int64(bits/16))
if err != nil {
return nil, err
}
q := big.NewInt(0).SetBytes(b)
q.SetBit(q, 0, 1)
q.SetBit(q, pBits-1, 1)
for !q.ProbablyPrime(20) || q.Cmp(p) == 0 {
q.Add(q, big.NewInt(2))
}
return newPrivateKey(p, q), nil
}
func (c *Cipher) Marshal() ([]byte, error) {
if c.D == nil {
return nil, errors.New("empty cipher")
}
var b cryptobyte.Builder
b.AddASN1BigInt(c.D)
return b.Bytes()
}
func (c *Cipher) Unmarshal(b []byte) error {
if c.D == nil {
c.D = new(big.Int)
}
input := cryptobyte.String(b)
if !input.ReadASN1Integer(c.D) {
return errors.New("parse ASN.1 cipher failed")
}
return nil
}
// round up n to the nearest power of 2.
func roundup(n uint64) uint64 {
n--
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n |= n >> 32
return n + 1
}
func (k *PublicKey) Size() uint {
return uint(roundup(uint64(k.N.BitLen())))
}
// Marshal 编码公钥, PublicKey ::= INTEGER
func (k *PublicKey) Marshal() ([]byte, error) {
if k.N == nil {
return nil, errors.New("empty public key")
}
var b cryptobyte.Builder
b.AddASN1BigInt(k.N)
return b.Bytes()
}
func (k *PublicKey) Unmarshal(b []byte) error {
if k.N == nil || k.N2 == nil {
k.N = new(big.Int)
k.N2 = new(big.Int)
}
input := cryptobyte.String(b)
if !input.ReadASN1Integer(k.N) {
return errors.New("parse ASN.1 public key failed")
}
k.N2.Mul(k.N, k.N)
return nil
}
// MarshalExt 编码公钥,包括预计算数据, PublicKey ::= INTEGER
func (k *PublicKey) MarshalExt() ([]byte, error) {
if k.N == nil {
return nil, errors.New("empty public key")
}
k.Precompute(grand.Reader)
var b cryptobyte.Builder
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1BigInt(k.N)
b.AddASN1BigInt(k.rn)
})
return b.Bytes()
}
func (k *PublicKey) UnmarshalExt(b []byte) error {
if k.N == nil || k.N2 == nil {
k.N = new(big.Int)
k.N2 = new(big.Int)
}
if k.rn == nil {
k.rn = new(big.Int)
}
input := cryptobyte.String(b)
var inner cryptobyte.String
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!inner.ReadASN1Integer(k.N) ||
!inner.ReadASN1Integer(k.rn) {
return errors.New("read ASN.1 private key failed")
}
k.N2.Mul(k.N, k.N)
return nil
}
// Marshal 编码私钥
func (k *PrivateKey) Marshal() ([]byte, error) {
if k.lambda == nil {
return nil, errors.New("empty private key")
}
var b cryptobyte.Builder
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1BigInt(k.lambda)
b.AddASN1BigInt(k.N)
})
return b.Bytes()
}
// Unmarshal 解码私钥
func (k *PrivateKey) Unmarshal(b []byte) error {
if k.lambda == nil || k.N == nil {
k.lambda = new(big.Int)
k.N = new(big.Int)
}
input := cryptobyte.String(b)
var inner cryptobyte.String
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!inner.ReadASN1Integer(k.lambda) ||
!inner.ReadASN1Integer(k.N) {
return errors.New("read ASN.1 private key failed")
}
if k.lambdaInv == nil {
k.lambdaInv = new(big.Int)
}
k.lambdaInv.ModInverse(k.lambda, k.N)
_ = k.Public()
return nil
}
+46
View File
@@ -0,0 +1,46 @@
package paillier
import (
"math/big"
"xdx.jelly/xgcl/gmath"
)
// HomomorphicAdd set c = Enc(m1+m2) where c1 = Enc(m1) and c2 = Enc(m2)
func (c *Cipher) HomomorphicAdd(c1 *Cipher, c2 *Cipher, pk *PublicKey) *Cipher {
if c.D == nil {
c.D = new(big.Int)
}
c.D.Mul(c1.D, c2.D)
c.D.Mod(c.D, pk.N2)
return c
}
// HomomorphicAddInt set c = Enc(m1 + m) where c1 = Enc(m1) and m < N.
//
// Becareful, if the adversary knows c1, c, and m(or m1), then he can computes m1(or m).
// So, using HomomorphicAddInt if you know what you're doing,
// otherwise, you should use like this:
// c2, err := pk.Encrypt(m, rnd)
// c.HomomorphicAdd(c1, c2, pk)
func (c *Cipher) HomomorphicAddInt(c1 *Cipher, m *big.Int, pk *PublicKey) *Cipher {
d := new(big.Int)
c.D = d.Mul(pk.N, m).Add(d, gmath.BigInt1).Mod(d, pk.N2).Mul(d, c1.D).Mod(d, pk.N2)
return c
}
// HomomorphicScalarMul if c1 = Enc(a), then HomomorphicScalarMul computes c = Enc(ka)
// if ka < n^2.
func (c *Cipher) HomomorphicScalarMul(a *Cipher, k *big.Int, pk *PublicKey) *Cipher {
if c.D == nil {
c.D = new(big.Int)
}
c.D.Exp(a.D, k, pk.N2)
return c
}
// Neg negates the plaintext mod n, i.e., if c = Enc(m), then c.Neg() = Enc(n-m).
func (c *Cipher) Neg(pk *PublicKey) *Cipher {
c.D.ModInverse(c.D, pk.N2)
return c
}
+26
View File
@@ -0,0 +1,26 @@
package paillier
import (
"crypto/rand"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/grand"
)
func TestNeg(t *testing.T) {
sk, err := GenerateKeyFromPassword(2048, grand.GetRandom(32), grand.GetRandom(32), 1024)
assert.Nil(t, err)
pk := sk.Public()
m, _ := rand.Int(grand.Reader, pk.N)
mNeg := new(big.Int).Sub(pk.N, m) // n - m
c, _ := Encrypt(m, pk, grand.Reader)
c.Neg(pk) // Enc(n-m) = Enc(m)^-1 mod n^2
mm, _ := Decrypt(c, sk)
assert.Zero(t, mm.Cmp(mNeg))
}
+250
View File
@@ -0,0 +1,250 @@
package paillier
import (
"crypto/rand"
"encoding/hex"
"math/big"
"testing"
"time"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/grand"
"xdx.jelly/xgcl/sm/sm2"
)
func bigFromBase16(s string) *big.Int {
b, err := hex.DecodeString(s)
if err != nil {
panic(err)
}
return new(big.Int).SetBytes(b)
}
var p = bigFromBase16("ff03b1a74827c746db83d2eaff00067622f545b62584321256e62b01509f1096" +
"2f9c5c8fd0b7f5184a9ce8e81f439df47dda14563dd55a221799d2aa57ed2713" +
"271678a5a0b8b40a84ad13d5b6e6599e6467c670109cf1f45ccfed8f75ea3b81" +
"4548ab294626fe4d14ff764dd8b091f11a0943a2dd2b983b0df02f4c4d00b413")
var q = bigFromBase16("dacaabc1dc57faa9fd6a4274c4d588765a1d3311c22e57d8101431b07eb3ddcb" +
"05d77d9a742ac2322fe6a063bd1e05acb13b0fe91c70115c2b1eee1155e07252" +
"7011a5f849de7072a1ce8e6b71db525fbcda7a89aaed46d27aca5eaeaf35a262" +
"70a4a833c5cda681ffd49baa0f610bad100cdf47cc86e5034e2a0b2179e04ec7")
var n = new(big.Int).Mul(p, q)
var lambda = new(big.Int)
// lcm(lambda, new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
func TestPaillier(t *testing.T) {
// pk, sk := GenerateKey(1024)
sk, err := GenerateKeyFromPassword(2048, grand.GetRandom(32), grand.GetRandom(32), 1024)
assert.Nil(t, err)
pk := sk.Public()
m1, _ := rand.Int(grand.Reader, pk.N)
m2, _ := rand.Int(grand.Reader, pk.N)
c1, _ := Encrypt(m1, pk, grand.Reader)
c2, _ := Encrypt(m2, pk, grand.Reader)
c := new(Cipher).HomomorphicAdd(c1, c2, pk)
m, _ := Decrypt(c, sk)
mm := new(big.Int).Add(m1, m2)
mm.Mod(mm, pk.N)
assert.Zero(t, m.Cmp(mm))
}
func TestKeyMarshal(t *testing.T) {
sk, pk, err := GenerateKey(2048, grand.Reader)
assert.Nil(t, err)
assert.Equal(t, pk.Size(), uint(2048))
skBytes, err := sk.Marshal()
assert.Nil(t, err)
sk2 := new(PrivateKey)
assert.Nil(t, sk2.Unmarshal(skBytes))
assert.Zero(t, sk.p.Cmp(sk2.p)|sk.q.Cmp(sk2.q)|sk.lambda.Cmp(sk2.lambda)|sk.lambdaInv.Cmp(sk2.lambdaInv))
pkBytes, err := pk.Marshal()
assert.Nil(t, err)
pk2 := new(PublicKey)
assert.Nil(t, pk2.Unmarshal(pkBytes))
assert.Zero(t, pk.N.Cmp(pk2.N)|pk.N2.Cmp(pk2.N2))
}
func TestPaillierScalarMul(t *testing.T) {
sk, err := GenerateKeyFromPassword(2048, grand.GetRandom(32), grand.GetRandom(32), 1024)
assert.Nil(t, err)
pk := sk.Public()
limit := big.NewInt(1)
limit.Lsh(limit, 256)
ch := time.After(3 * time.Second)
done := false
for !done {
select {
case <-ch:
done = true
default:
m, _ := rand.Int(grand.Reader, limit)
k, _ := rand.Int(grand.Reader, limit)
c, _ := Encrypt(m, pk, grand.Reader)
c.HomomorphicScalarMul(c, k, sk.Public())
m1, err := Decrypt(c, sk)
assert.Nil(t, err)
m2 := new(big.Int).Mul(m, k)
assert.Zero(t, m1.Cmp(m2))
}
}
}
func BenchmarkParallelPaillierEnc(b *testing.B) {
_, pk, _ := GenerateKey(2048, grand.Reader)
m, _ := rand.Int(grand.Reader, pk.N)
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
Encrypt(m, pk, grand.Reader)
}
})
}
func BenchmarkPaillierEnc(b *testing.B) {
_, pk, _ := GenerateKey(2048, grand.Reader)
m, _ := rand.Int(grand.Reader, pk.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Encrypt(m, pk, grand.Reader)
}
}
func BenchmarkPaillierDec(b *testing.B) {
sk, pk, _ := GenerateKey(2048, grand.Reader)
m, _ := rand.Int(grand.Reader, pk.N)
c, _ := Encrypt(m, pk, grand.Reader)
b.ResetTimer()
for i := 0; i < b.N; i++ {
Decrypt(c, sk)
}
}
func BenchmarkPaillierHomomorphicScalarMul(b *testing.B) {
sk, pk, _ := GenerateKey(2048, grand.Reader)
limit := big.NewInt(1)
limit.Lsh(limit, 256)
m, _ := rand.Int(grand.Reader, limit)
c, _ := Encrypt(m, pk, grand.Reader)
k, _ := rand.Int(grand.Reader, limit)
b.ResetTimer()
for i := 0; i < b.N; i++ {
c.HomomorphicScalarMul(c, k, sk.Public())
}
}
func TestPaillierHomomorphicEncSpeed(t *testing.T) {
_, pk, _ := GenerateKey(2048, grand.Reader)
m, _ := rand.Int(grand.Reader, pk.N)
times := 1000
start := time.Now()
for i := 0; i < times; i++ {
Encrypt(m, pk, grand.Reader)
}
end := time.Now()
elapsed := end.Sub(start)
t.Logf("HomomorphicScalarMul: %.2f per second\n", float64(times)/elapsed.Seconds())
}
func TestPaillierHomomorphicScalarMulSpeed(t *testing.T) {
_, pk, _ := GenerateKey(2048, grand.Reader)
limit := big.NewInt(1)
limit.Lsh(limit, 256)
m, _ := rand.Int(grand.Reader, limit)
c, _ := Encrypt(m, pk, grand.Reader)
k, _ := rand.Int(grand.Reader, limit)
times := 1000
start := time.Now()
for i := 0; i < times; i++ {
c.HomomorphicScalarMul(c, k, pk)
}
end := time.Now()
elapsed := end.Sub(start)
t.Logf("HomomorphicScalarMul: %.2f per second\n", float64(times)/elapsed.Seconds())
}
func BenchmarkBlind1(b *testing.B) {
_, pk, _ := GenerateKey(2048, grand.Reader)
limit := big.NewInt(1)
limit.Lsh(limit, 256)
k, _ := rand.Int(grand.Reader, limit)
nc, _ := pk.Encrypt(sm2.OrderN(), grand.Reader)
b.ResetTimer()
for i := 0; i < b.N; i++ {
(&Cipher{}).HomomorphicScalarMul(nc, k, pk)
}
}
func BenchmarkBlind2(b *testing.B) {
_, pk, _ := GenerateKey(2048, grand.Reader)
limit := big.NewInt(1)
limit.Lsh(limit, 256)
k, _ := rand.Int(grand.Reader, limit)
kn := new(big.Int).Mul(k, sm2.OrderN())
b.ResetTimer()
for i := 0; i < b.N; i++ {
kn.Mul(k, sm2.OrderN())
pk.Encrypt(kn, grand.Reader)
}
}
// func BenchmarkGMPIntExp(b *testing.B) {
// sk, _, _ := GenerateKey(2048, grand.Reader)
// n := gmp.NewInt(1).SetBytes(sk.N.Bytes())
// n2 := gmp.NewInt(1).Mul(n, n)
// r := gmp.NewInt(1).SetBytes(grand.GetRandom(128))
// b.ResetTimer()
// for i := 0; i < b.N; i++ {
// r.Exp(r, n, n2)
// }
// }
func BenchmarkIntExp(b *testing.B) {
sk, _, _ := GenerateKey(2048, grand.Reader)
n := sk.N
n2 := sk.N2
r := new(big.Int).SetBytes(grand.GetRandom(128))
b.ResetTimer()
for i := 0; i < b.N; i++ {
r.Exp(r, n, n2)
}
}
func TestGenerateKeyFromPassword(t *testing.T) {
b, _ := hex.DecodeString("12345678abcdef")
sk, _ := GenerateKeyFromPassword(2048, []byte("1234567812345678"), b, 1024)
assert.Equal(t, sk.N.Text(16), "86257d4f684edb672420a6e0d6a6e66b00a316080c0b025d96e9d22c57d6fc7166bcddc07dadc2f0dca7440c6f43a90fab494ea810304af2abc18d54bcdeb8803c8c245270d70b897f3bf2e43c3a5e9d777fb256f84cf5b4705cba19283952dd10aa2b15793a401195ee2a418b999bbf72e35bd94f48267597ab7cfb699b3bbab78a6201a9ee18a22d25e841a66c54d5ebf45c10491ea43cca5e9e6f487c7aedc24d15cda20e6f80a755477b6e2b1d1a9e669ba0773bb31e2fb76e550fdef1be4d02ec820aba5ebfbfd0fbb37bd1c748af1f4a0c17f5cfb41e4cb44a05587bcff2937415eb2e13398da514224def6c03f61a07319512362912caa08bded076dd")
assert.Equal(t, sk.Size(), uint(2048))
}
+22
View File
@@ -0,0 +1,22 @@
package x
import (
"crypto/rand"
"testing"
"github.com/stretchr/testify/assert"
"xdx.jelly/xgcl/grand"
)
func TestPaillier(t *testing.T) {
// pk, sk := GenerateKey(1024)
sk, pk, err := GenerateKey(2048)
assert.Nil(t, err)
m, _ := rand.Int(grand.Reader, pk.N)
c, _ := Encrypt(m, pk, grand.Reader)
m1, _ := Decrypt(c, sk)
assert.Zero(t, m.Cmp(m1))
}
+345
View File
@@ -0,0 +1,345 @@
package x
import (
"crypto/rand"
"crypto/rsa"
"sync"
"errors"
"io"
"math/big"
"golang.org/x/crypto/cryptobyte"
"golang.org/x/crypto/cryptobyte/asn1"
"xdx.jelly/xgcl/gmath"
"xdx.jelly/xgcl/grand"
)
//
// PublicKey ::= INTEGER
//
// PrivateKey ::= SEQUENCE{
// lambda INTEGER,
// N INTEGER
// }
//
// Cipher ::= INTEGER
type PublicKey struct {
N *big.Int
N2 *big.Int
mu sync.Mutex // guard rn
rn *big.Int
}
type PrivateKey struct {
PublicKey
lambda *big.Int
// option
lambdaInv *big.Int
p, q *big.Int
}
func (k *PrivateKey) Public() *PublicKey {
if k.PublicKey.N2 == nil {
k.PublicKey.N2 = new(big.Int).Mul(k.PublicKey.N, k.PublicKey.N)
}
if k.rn == nil {
k.Precompute(grand.Reader)
}
return &k.PublicKey
}
// Cipher the member variable D is for gcl's internal use.
// You should never use it except you know what you're doing.
type Cipher struct {
D *big.Int
}
func newPrivateKey(p *big.Int, q *big.Int, r *big.Int, s *big.Int) *PrivateKey {
sk := &PrivateKey{
PublicKey: PublicKey{
N: new(big.Int).Mul(p, q),
},
lambda: new(big.Int),
lambdaInv: new(big.Int),
}
N := sk.PublicKey.N
N.Mul(N, r).Mul(N, s)
pk := sk.Public()
// lambda = LCM(p-1, q-1) or just (p-1)*(q-1)
// lcm(sk.lambda, new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
sk.lambda.Mul(new(big.Int).Sub(p, gmath.BigInt1), new(big.Int).Sub(q, gmath.BigInt1))
sk.lambda.Mul(sk.lambda, new(big.Int).Sub(r, gmath.BigInt1))
sk.lambda.Mul(sk.lambda, new(big.Int).Sub(s, gmath.BigInt1))
sk.lambdaInv.ModInverse(sk.lambda, pk.N)
return sk
}
// return l = lcm(a,b)
func lcm(l, a, b *big.Int) {
d := new(big.Int).GCD(nil, nil, a, b)
l.Mul(a, b)
l.Div(l, d)
}
// GenerateKey 生成同态密钥. bits 应为2048.
// rnd_opt 可选, 忽略则使用grand.Reader.
func GenerateKey(bits int, rnd_opt ...io.Reader) (*PrivateKey, *PublicKey, error) {
var rnd io.Reader
if len(rnd_opt) > 0 {
rnd = rnd_opt[0]
} else {
rnd = grand.Reader
}
priKey := &PrivateKey{}
rsaKey1, err := rsa.GenerateKey(rnd, bits)
if err != nil {
return nil, nil, err
}
rsaKey2, err := rsa.GenerateKey(rnd, bits)
if err != nil {
return nil, nil, err
}
// check rsaKey1 and rsaKey2 has no gcd > 1.
priKey = newPrivateKey(rsaKey1.Primes[0], rsaKey1.Primes[1], rsaKey2.Primes[0], rsaKey2.Primes[1])
return priKey, &priKey.PublicKey, nil
}
func (k *PrivateKey) Decrypt(c *Cipher) (*big.Int, error) {
if c.D == nil || c.D.Cmp(k.N2) >= 0 {
return nil, errors.New("invalid cipher")
}
if k.lambdaInv == nil {
k.lambdaInv = new(big.Int).ModInverse(k.lambda, k.N)
}
pk := k.Public()
d := c.D
L := new(big.Int)
L.Exp(d, k.lambda, pk.N2) // L = c^lambda mod n^2
L.Sub(L, gmath.BigInt1)
L.Div(L, pk.N) // L = (c^lambda - 1)/n
L.Mul(L, k.lambdaInv)
L.Mod(L, pk.N)
return L, nil
}
func (k *PublicKey) Bits() int {
return k.N.BitLen()
}
// Precompute computes r^N mod N^2 for a random r.
func (k *PublicKey) Precompute(rnd io.Reader) error {
if k.rn != nil {
return nil
}
k.mu.Lock()
defer k.mu.Unlock()
if k.N2 == nil {
k.N2 = new(big.Int).Mul(k.N, k.N)
}
if k.rn != nil {
return nil
}
buf := make([]byte, k.N.BitLen()/2)
_, err := rnd.Read(buf)
if err != nil {
return err
}
buf[0] |= 1 // at least one
r := new(big.Int).SetBytes(buf)
r.Exp(r, k.N, k.N2) // r = r^n mod n^2
k.rn = r
return nil
}
func (k *PublicKey) Encrypt(m *big.Int, rnd io.Reader) (*Cipher, error) {
if true {
k.Precompute(grand.Reader)
rn := new(big.Int).SetBytes(grand.GetRandom(12))
rn.Exp(k.rn, rn, k.N2)
d := new(big.Int)
d.Mul(k.N, m) // d = n * m
d.Add(d, gmath.BigInt1) // d = nm + 1
d.Mul(d, rn) // c = (nm+1)*r^n mod n^2
d.Mod(d, k.N2)
return &Cipher{D: d}, nil
} else {
// r should select from (1, N)
var r *big.Int
var err error
for {
r, err = rand.Int(rnd, k.N)
if err != nil {
return nil, err
}
// should we check gcd(r,n) == 1?
if r.Sign() > 0 {
break
}
}
d := new(big.Int)
d.Mul(k.N, m) // d = n * m
d.Add(d, gmath.BigInt1) // d = nm + 1
r.Exp(r, k.N, k.N2) // r = r^n mod n^2
// r.SetUint64(1)
d.Mul(d, r) // c = (nm+1)*r^n mod n^2
d.Mod(d, k.N2)
return &Cipher{D: d}, nil
}
}
func Encrypt(m *big.Int, publicKey *PublicKey, rnd io.Reader) (*Cipher, error) {
return publicKey.Encrypt(m, rnd)
}
func Decrypt(c *Cipher, key *PrivateKey) (*big.Int, error) {
return key.Decrypt(c)
}
func (c *Cipher) Marshal() ([]byte, error) {
if c.D == nil {
return nil, errors.New("empty cipher")
}
var b cryptobyte.Builder
b.AddASN1BigInt(c.D)
return b.Bytes()
}
func (c *Cipher) Unmarshal(b []byte) error {
if c.D == nil {
c.D = new(big.Int)
}
input := cryptobyte.String(b)
if !input.ReadASN1Integer(c.D) {
return errors.New("parse ASN.1 cipher failed")
}
return nil
}
// round up n to the nearest power of 2.
func roundup(n uint64) uint64 {
n--
n |= n >> 1
n |= n >> 2
n |= n >> 4
n |= n >> 8
n |= n >> 16
n |= n >> 32
return n + 1
}
func (k *PublicKey) Size() uint {
return uint(roundup(uint64(k.N.BitLen())))
}
// Marshal 编码公钥, PublicKey ::= INTEGER
func (k *PublicKey) Marshal() ([]byte, error) {
if k.N == nil {
return nil, errors.New("empty public key")
}
var b cryptobyte.Builder
b.AddASN1BigInt(k.N)
return b.Bytes()
}
func (k *PublicKey) Unmarshal(b []byte) error {
if k.N == nil || k.N2 == nil {
k.N = new(big.Int)
k.N2 = new(big.Int)
}
input := cryptobyte.String(b)
if !input.ReadASN1Integer(k.N) {
return errors.New("parse ASN.1 public key failed")
}
k.N2.Mul(k.N, k.N)
return nil
}
// MarshalExt 编码公钥,包括预计算数据, PublicKey ::= INTEGER
func (k *PublicKey) MarshalExt() ([]byte, error) {
if k.N == nil {
return nil, errors.New("empty public key")
}
k.Precompute(grand.Reader)
var b cryptobyte.Builder
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1BigInt(k.N)
b.AddASN1BigInt(k.rn)
})
return b.Bytes()
}
func (k *PublicKey) UnmarshalExt(b []byte) error {
if k.N == nil || k.N2 == nil {
k.N = new(big.Int)
k.N2 = new(big.Int)
}
if k.rn == nil {
k.rn = new(big.Int)
}
input := cryptobyte.String(b)
var inner cryptobyte.String
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!inner.ReadASN1Integer(k.N) ||
!inner.ReadASN1Integer(k.rn) {
return errors.New("read ASN.1 private key failed")
}
k.N2.Mul(k.N, k.N)
return nil
}
// Marshal 编码私钥
func (k *PrivateKey) Marshal() ([]byte, error) {
if k.lambda == nil {
return nil, errors.New("empty private key")
}
var b cryptobyte.Builder
b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
b.AddASN1BigInt(k.lambda)
b.AddASN1BigInt(k.N)
})
return b.Bytes()
}
// Unmarshal 解码私钥
func (k *PrivateKey) Unmarshal(b []byte) error {
if k.lambda == nil || k.N == nil {
k.lambda = new(big.Int)
k.N = new(big.Int)
}
input := cryptobyte.String(b)
var inner cryptobyte.String
if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
!inner.ReadASN1Integer(k.lambda) ||
!inner.ReadASN1Integer(k.N) {
return errors.New("read ASN.1 private key failed")
}
if k.lambdaInv == nil {
k.lambdaInv = new(big.Int)
}
k.lambdaInv.ModInverse(k.lambda, k.N)
_ = k.Public()
return nil
}