Browse Source

shamir secret sharing: create secret sharing, and reconstruct secret from shares with Langrange Interpolation

master
arnaucode 5 years ago
parent
commit
9aa4a2d1a0
9 changed files with 206 additions and 17 deletions
  1. +1
    -0
      .gitignore
  2. +7
    -1
      README.md
  3. +14
    -5
      paillier/paillier.go
  4. +0
    -1
      paillier/paillier_test.go
  5. +7
    -1
      prime/prime.go
  6. +18
    -7
      rsa/rsa.go
  7. +0
    -2
      rsa/rsa_test.go
  8. +45
    -0
      secrets/secrets_test.go
  9. +114
    -0
      secrets/sercrets.go

+ 1
- 0
.gitignore

@ -0,0 +1 @@
fmt

+ 7
- 1
README.md

@ -4,6 +4,7 @@ Crypto algorithms from scratch. Academic purposes only.
## RSA
https://en.wikipedia.org/wiki/RSA_(cryptosystem)#
- [x] GenerateKeyPair
- [x] Encrypt
- [x] Decrypt
@ -14,10 +15,15 @@ Crypto algorithms from scratch. Academic purposes only.
- [x] Homomorphic Multiplication
## Paillier
https://en.wikipedia.org/wiki/Paillier_cryptosystem
- [x] GenerateKeyPair
- [x] Encrypt
- [x] Decrypt
- [x] Homomorphic Addition
## ECC
## Shamir Secret Sharing
https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing
- [x] create secret sharing from NumOfSecretsNeed, NumOfShares, RandPointP, SecretToShare
- [x] Lagrange Interpolation to restore the secret from the shares
## ECC

+ 14
- 5
paillier/paillier.go

@ -12,20 +12,25 @@ const (
bits = 16
)
// PublicKey stores the public key data
type PublicKey struct {
N *big.Int `json:"n"`
G *big.Int `json:"g"`
}
// PrivateKey stores the private key data
type PrivateKey struct {
Lambda *big.Int `json:"lambda"`
Mu *big.Int `json:"mu"`
}
// Key stores the public and private key data
type Key struct {
PubK PublicKey
PrivK PrivateKey
}
// GenerateKeyPair generates a random private and public key
func GenerateKeyPair() (key Key, err error) {
p, err := rand.Prime(rand.Reader, bits/2)
if err != nil {
@ -44,7 +49,7 @@ func GenerateKeyPair() (key Key, err error) {
}
n := new(big.Int).Mul(p, q)
lambda := big.NewInt(int64(Lcm(float64(p.Int64())-1, float64(q.Int64())-1)))
lambda := big.NewInt(int64(lcm(float64(p.Int64())-1, float64(q.Int64())-1)))
//g generation
alpha := big.NewInt(int64(prime.RandInt(0, int(n.Int64()))))
@ -64,7 +69,7 @@ func GenerateKeyPair() (key Key, err error) {
//mu generation
Glambda := new(big.Int).Exp(g, lambda, nil)
u := new(big.Int).Mod(Glambda, n2)
L := L(u, n)
L := l(u, n)
mu := new(big.Int).ModInverse(L, n)
key.PrivK.Lambda = lambda
@ -73,17 +78,18 @@ func GenerateKeyPair() (key Key, err error) {
return key, nil
}
func Lcm(a, b float64) float64 {
func lcm(a, b float64) float64 {
r := (a * b) / float64(prime.Gcd(int(a), int(b)))
return r
}
func L(u *big.Int, n *big.Int) *big.Int {
func l(u *big.Int, n *big.Int) *big.Int {
u1 := new(big.Int).Sub(u, big.NewInt(1))
L := new(big.Int).Div(u1, n)
return L
}
// Encrypt encrypts a message m with given PublicKey
func Encrypt(m *big.Int, pubK PublicKey) *big.Int {
gM := new(big.Int).Exp(pubK.G, m, nil)
r := big.NewInt(int64(prime.RandInt(0, int(pubK.N.Int64()))))
@ -93,16 +99,19 @@ func Encrypt(m *big.Int, pubK PublicKey) *big.Int {
c := new(big.Int).Mod(gMrN, n2)
return c
}
// Decrypt deencrypts a ciphertext c with given PublicKey and PrivateKey
func Decrypt(c *big.Int, pubK PublicKey, privK PrivateKey) *big.Int {
cLambda := new(big.Int).Exp(c, privK.Lambda, nil)
n2 := new(big.Int).Mul(pubK.N, pubK.N)
u := new(big.Int).Mod(cLambda, n2)
L := L(u, pubK.N)
L := l(u, pubK.N)
LMu := new(big.Int).Mul(L, privK.Mu)
m := new(big.Int).Mod(LMu, pubK.N)
return m
}
// HomomorphicAddition calculates the addition of tow encrypted values given a PublicKey
func HomomorphicAddition(c1 *big.Int, c2 *big.Int, pubK PublicKey) *big.Int {
c1c2 := new(big.Int).Mul(c1, c2)
n2 := new(big.Int).Mul(pubK.N, pubK.N)

+ 0
- 1
paillier/paillier_test.go

@ -12,7 +12,6 @@ func TestEncryptDecrypt(t *testing.T) {
if err != nil {
t.Errorf(err.Error())
}
fmt.Println(key)
mBytes := []byte("Hi")
m := new(big.Int).SetBytes(mBytes)
c := Encrypt(m, key.PubK)

+ 7
- 1
prime/prime.go

@ -3,21 +3,26 @@ package prime
import "math/rand"
const (
// MaxPrime is to get a prime value below this number
MaxPrime = 2000
// MinPrime is to get a prime value above this number
MinPrime = 500
)
// RandInt returns a random integer between two values
func RandInt(min int, max int) int {
r := rand.Intn(max-min) + min
return r
}
// RandPrime returns a random prime number between two values
func RandPrime(min int, max int) int {
primes := SieveOfEratosthenes(max)
randN := rand.Intn(len(primes)-0) + 0
return primes[randN]
}
// return list of primes less than N
// SieveOfEratosthenes returns a list of primes less than N
func SieveOfEratosthenes(N int) (primes []int) {
b := make([]bool, N)
for i := 2; i < N; i++ {
@ -32,6 +37,7 @@ func SieveOfEratosthenes(N int) (primes []int) {
return
}
// Gcd returns the greatest common divisor
func Gcd(a, b int) int {
var bgcd func(a, b, res int) int
bgcd = func(a, b, res int) int {

+ 18
- 7
rsa/rsa.go

@ -12,24 +12,25 @@ const (
var bigOne = big.NewInt(int64(1))
// PublicKey stores the public key data
type PublicKey struct {
E *big.Int `json:"e"`
N *big.Int `json:"n"`
}
type PublicKeyString struct {
E string `json:"e"`
N string `json:"n"`
}
// PrivateKey stores the private key data
type PrivateKey struct {
D *big.Int `json:"d"`
N *big.Int `json:"n"`
}
// Key stores the public and private key data
type Key struct {
PubK PublicKey
PrivK PrivateKey
}
// GenerateKeyPair generates a random private and public key
func GenerateKeyPair() (key Key, err error) {
p, err := rand.Prime(rand.Reader, bits/2)
if err != nil {
@ -41,9 +42,9 @@ func GenerateKeyPair() (key Key, err error) {
}
n := new(big.Int).Mul(p, q)
p_1 := new(big.Int).Sub(p, bigOne)
q_1 := new(big.Int).Sub(q, bigOne)
phi := new(big.Int).Mul(p_1, q_1)
p1 := new(big.Int).Sub(p, bigOne)
q1 := new(big.Int).Sub(q, bigOne)
phi := new(big.Int).Mul(p1, q1)
e := 65537
var pubK PublicKey
pubK.E = big.NewInt(int64(e))
@ -60,15 +61,19 @@ func GenerateKeyPair() (key Key, err error) {
return key, nil
}
// Encrypt encrypts a message m with given PublicKey
func Encrypt(m *big.Int, pubK PublicKey) *big.Int {
c := new(big.Int).Exp(m, pubK.E, pubK.N)
return c
}
// Decrypt deencrypts a ciphertext c with given PrivateKey
func Decrypt(c *big.Int, privK PrivateKey) *big.Int {
m := new(big.Int).Exp(c, privK.D, privK.N)
return m
}
// Blind blinds a message
func Blind(m *big.Int, r *big.Int, pubK PublicKey) *big.Int {
rE := new(big.Int).Exp(r, pubK.E, nil)
mrE := new(big.Int).Mul(m, rE)
@ -76,16 +81,21 @@ func Blind(m *big.Int, r *big.Int, pubK PublicKey) *big.Int {
return mBlinded
}
// BlindSign blind signs a message without knowing the content
func BlindSign(m *big.Int, privK PrivateKey) *big.Int {
sigma := new(big.Int).Exp(m, privK.D, privK.N)
return sigma
}
// Unblind unblinds the Blinded Signature
func Unblind(sigma *big.Int, r *big.Int, pubK PublicKey) *big.Int {
r1 := new(big.Int).ModInverse(r, pubK.N)
bsr := new(big.Int).Mul(sigma, r1)
sig := new(big.Int).Mod(bsr, pubK.N)
return sig
}
// Verify verifies the signature of a message given the PublicKey of the signer
func Verify(msg *big.Int, mSigned *big.Int, pubK PublicKey) bool {
//decrypt the mSigned with pubK
Cd := new(big.Int).Exp(mSigned, pubK.E, nil)
@ -93,6 +103,7 @@ func Verify(msg *big.Int, mSigned *big.Int, pubK PublicKey) bool {
return bytes.Equal(msg.Bytes(), m.Bytes())
}
// HomomorphicMul calculates the multiplication of tow encrypted values given a PublicKey
func HomomorphicMul(c1 *big.Int, c2 *big.Int, pubK PublicKey) *big.Int {
c1c2 := new(big.Int).Mul(c1, c2)
n2 := new(big.Int).Mul(pubK.N, pubK.N)

+ 0
- 2
rsa/rsa_test.go

@ -2,7 +2,6 @@ package rsa
import (
"bytes"
"fmt"
"math/big"
"testing"
)
@ -12,7 +11,6 @@ func TestEncryptDecrypt(t *testing.T) {
if err != nil {
t.Errorf(err.Error())
}
fmt.Println(key)
mBytes := []byte("Hi")
m := new(big.Int).SetBytes(mBytes)
c := Encrypt(m, key.PubK)

+ 45
- 0
secrets/secrets_test.go

@ -0,0 +1,45 @@
package secrets
import (
"crypto/rand"
"math/big"
"testing"
)
func TestCreate(t *testing.T) {
k := 123456789
p, err := rand.Prime(rand.Reader, bits/2)
if err != nil {
t.Errorf(err.Error())
}
nNeededSecrets := big.NewInt(int64(3))
nShares := big.NewInt(int64(6))
shares, err := Create(
nNeededSecrets,
nShares,
p,
big.NewInt(int64(k)))
if err != nil {
t.Errorf(err.Error())
}
//generate sharesToUse
var sharesToUse [][]*big.Int
sharesToUse = append(sharesToUse, shares[2])
sharesToUse = append(sharesToUse, shares[1])
sharesToUse = append(sharesToUse, shares[0])
secr := LagrangeInterpolation(sharesToUse, p)
// fmt.Print("original secret: ")
// fmt.Println(k)
// fmt.Print("p: ")
// fmt.Println(p)
// fmt.Print("shares: ")
// fmt.Println(shares)
// fmt.Print("secret result: ")
// fmt.Println(secr)
if int64(k) != secr.Int64() {
t.Errorf("reconstructed secret not correspond to original secret")
}
}

+ 114
- 0
secrets/sercrets.go

@ -0,0 +1,114 @@
package secrets
import (
"crypto/rand"
"errors"
"math/big"
)
const (
bits = 1024
)
// t: number of secrets needed
// n: number of shares
// p: random point
// k: secret to share
// Create calculates the secrets to share from given parameters
func Create(t, n, p, k *big.Int) (result [][]*big.Int, err error) {
if k.Cmp(p) > 0 {
return nil, errors.New("Error: need k<p. k: " + k.String() + ", p: " + p.String())
}
//generate the basePolynomial
var basePolynomial []*big.Int
basePolynomial = append(basePolynomial, k)
for i := 0; i < int(t.Int64())-1; i++ {
randPrime, err := rand.Prime(rand.Reader, bits/2)
if err != nil {
return result, err
}
basePolynomial = append(basePolynomial, randPrime)
}
//calculate shares, based on the basePolynomial
var shares []*big.Int
for i := 1; i < int(n.Int64())+1; i++ {
var pResultMod *big.Int
pResult := big.NewInt(int64(0))
for x, polElem := range basePolynomial {
if x == 0 {
pResult = pResult.Add(pResult, polElem)
} else {
iBigInt := big.NewInt(int64(i))
xBigInt := big.NewInt(int64(x))
iPowed := iBigInt.Exp(iBigInt, xBigInt, nil)
currElem := iPowed.Mul(iPowed, polElem)
pResult = pResult.Add(pResult, currElem)
pResultMod = pResult.Mod(pResult, p)
}
}
shares = append(shares, pResultMod)
}
//put the share together with his p value
result = packSharesAndI(shares)
return result, nil
}
func packSharesAndI(sharesString []*big.Int) (r [][]*big.Int) {
for i, share := range sharesString {
curr := []*big.Int{share, big.NewInt(int64(i + 1))}
r = append(r, curr)
}
return r
}
func unpackSharesAndI(sharesPacked [][]*big.Int) ([]*big.Int, []*big.Int) {
var shares []*big.Int
var i []*big.Int
for _, share := range sharesPacked {
shares = append(shares, share[0])
i = append(i, share[1])
}
return shares, i
}
// LagrangeInterpolation calculates the secret from given shares
func LagrangeInterpolation(sharesGiven [][]*big.Int, p *big.Int) *big.Int {
resultN := big.NewInt(int64(0))
resultD := big.NewInt(int64(0))
//unpack shares
sharesBigInt, sharesIBigInt := unpackSharesAndI(sharesGiven)
for i := 0; i < len(sharesBigInt); i++ {
lagrangeNumerator := big.NewInt(int64(1))
lagrangeDenominator := big.NewInt(int64(1))
for j := 0; j < len(sharesBigInt); j++ {
if sharesIBigInt[i] != sharesIBigInt[j] {
currLagrangeNumerator := sharesIBigInt[j]
currLagrangeDenominator := new(big.Int).Sub(sharesIBigInt[j], sharesIBigInt[i])
lagrangeNumerator = new(big.Int).Mul(lagrangeNumerator, currLagrangeNumerator)
lagrangeDenominator = new(big.Int).Mul(lagrangeDenominator, currLagrangeDenominator)
}
}
numerator := new(big.Int).Mul(sharesBigInt[i], lagrangeNumerator)
quo := new(big.Int).Quo(numerator, lagrangeDenominator)
if quo.Int64() != 0 {
resultN = resultN.Add(resultN, quo)
} else {
resultNMULlagrangeDenominator := new(big.Int).Mul(resultN, lagrangeDenominator)
resultN = new(big.Int).Add(resultNMULlagrangeDenominator, numerator)
resultD = resultD.Add(resultD, lagrangeDenominator)
}
}
var modinvMul *big.Int
if resultD.Int64() != 0 {
modinv := new(big.Int).ModInverse(resultD, p)
modinvMul = new(big.Int).Mul(resultN, modinv)
} else {
modinvMul = resultN
}
r := new(big.Int).Mod(modinvMul, p)
return r
}

Loading…
Cancel
Save