mirror of
https://github.com/arnaucube/cryptofun.git
synced 2026-02-27 21:06:45 +01:00
shamir secret sharing: create secret sharing, and reconstruct secret from shares with Langrange Interpolation
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
fmt
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
25
rsa/rsa.go
25
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)
|
||||
|
||||
@@ -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
secrets/secrets_test.go
Normal file
45
secrets/secrets_test.go
Normal file
@@ -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
secrets/sercrets.go
Normal file
114
secrets/sercrets.go
Normal file
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user