arnaucube
arnaucube/cryptofunPublic Self-hosted repository
shamir secret sharing: create secret sharing, and reconstruct secret from shares with Langrange Interpolation
arnaucode arnaucode@gmail.com
Sun, 22 Jul 2018 14:46:43 +0200
commit

9aa4a2d1a09335ea844d8b5d6323da2ac85605cf

parent

6ce09111f96cd03286e0397b6bd8df2816922f9f

A .gitignore

@@ -0,0 +1,1 @@

+fmt
M README.md → 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 @@ - [x] Verify Signature

- [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
M paillier/paillier.go → 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 @@ return key, errors.New("gcd comprovation failed")

} 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 @@

//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 @@

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 @@ n2 := new(big.Int).Mul(pubK.N, pubK.N)

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)
M paillier/paillier_test.go → paillier/paillier_test.go

@@ -12,7 +12,6 @@ key, err := GenerateKeyPair()

if err != nil { t.Errorf(err.Error()) } - fmt.Println(key) mBytes := []byte("Hi") m := new(big.Int).SetBytes(mBytes) c := Encrypt(m, key.PubK)
M prime/prime.go → prime/prime.go

@@ -3,21 +3,26 @@

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 @@ }

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 {
M rsa/rsa.go → rsa/rsa.go

@@ -12,24 +12,25 @@ )

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 @@ return key, err

} 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 @@ key.PrivK = privK

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 @@ mBlinded := new(big.Int).Mod(mrE, pubK.N)

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 @@ m := new(big.Int).Mod(Cd, pubK.N)

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)
M rsa/rsa_test.go → rsa/rsa_test.go

@@ -2,7 +2,6 @@ package rsa

import ( "bytes" - "fmt" "math/big" "testing" )

@@ -12,7 +11,6 @@ key, err := GenerateKeyPair()

if err != nil { t.Errorf(err.Error()) } - fmt.Println(key) mBytes := []byte("Hi") m := new(big.Int).SetBytes(mBytes) c := Encrypt(m, key.PubK)
A 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") + } +}
A 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 +}