arnaucube
arnaucube/shamirsecretsharingPublic Self-hosted repository
shamirsecretsharing/go-shamirsecretsharing/shamirsecretsharing.go
go-shamirsecretsharing/shamirsecretsharing.goRaw
  1package shamirsecretsharing
  2
  3import (
  4	"crypto/rand"
  5	"errors"
  6	"math/big"
  7)
  8
  9func randBigInt(p *big.Int) (*big.Int, error) {
 10	b := make([]byte, 32)
 11	_, err := rand.Read(b)
 12	if err != nil {
 13		return nil, err
 14	}
 15	r := new(big.Int).SetBytes(b)
 16	rp := new(big.Int).Mod(r, p)
 17	return rp, nil
 18}
 19
 20// Create calculates the secrets to share from given parameters
 21// t: number of secrets needed
 22// n: number of shares
 23// p: size of finite field
 24// k: secret to share
 25func Create(t, n, p, k *big.Int) (result [][]*big.Int, err error) {
 26	if k.Cmp(p) > 0 {
 27		return nil, errors.New("Error: need k<p. k: " + k.String() + ", p: " + p.String())
 28	}
 29	//generate the basePolynomial
 30	var basePolynomial []*big.Int
 31	basePolynomial = append(basePolynomial, k)
 32	for i := 0; i < int(t.Int64())-1; i++ {
 33		x, err := randBigInt(p)
 34		if err != nil {
 35			return result, err
 36		}
 37		basePolynomial = append(basePolynomial, x)
 38	}
 39
 40	//calculate shares, based on the basePolynomial
 41	var shares []*big.Int
 42	for i := 1; i < int(n.Int64())+1; i++ {
 43		var pResultMod *big.Int
 44		pResult := big.NewInt(int64(0))
 45		for x, polElem := range basePolynomial {
 46			if x == 0 {
 47				pResult = pResult.Add(pResult, polElem)
 48			} else {
 49				iBigInt := big.NewInt(int64(i))
 50				xBigInt := big.NewInt(int64(x))
 51				iPowed := iBigInt.Exp(iBigInt, xBigInt, nil)
 52				currElem := iPowed.Mul(iPowed, polElem)
 53				pResult = pResult.Add(pResult, currElem)
 54				pResultMod = pResult.Mod(pResult, p)
 55			}
 56		}
 57		shares = append(shares, pResultMod)
 58	}
 59	//put the share together with his p value
 60	result = packSharesAndI(shares)
 61	return result, nil
 62}
 63
 64func packSharesAndI(sharesString []*big.Int) (r [][]*big.Int) {
 65	for i, share := range sharesString {
 66		curr := []*big.Int{share, big.NewInt(int64(i + 1))}
 67		r = append(r, curr)
 68	}
 69	return r
 70}
 71func unpackSharesAndI(sharesPacked [][]*big.Int) ([]*big.Int, []*big.Int) {
 72	var shares []*big.Int
 73	var i []*big.Int
 74	for _, share := range sharesPacked {
 75		shares = append(shares, share[0])
 76		i = append(i, share[1])
 77	}
 78	return shares, i
 79}
 80
 81// LagrangeInterpolation calculates the secret from given shares
 82func LagrangeInterpolation(p *big.Int, sharesGiven [][]*big.Int) *big.Int {
 83	resultN := big.NewInt(int64(0))
 84	resultD := big.NewInt(int64(0))
 85
 86	//unpack shares
 87	sharesBigInt, sharesIBigInt := unpackSharesAndI(sharesGiven)
 88
 89	for i := 0; i < len(sharesBigInt); i++ {
 90		lagrangeNumerator := big.NewInt(int64(1))
 91		lagrangeDenominator := big.NewInt(int64(1))
 92		for j := 0; j < len(sharesBigInt); j++ {
 93			if sharesIBigInt[i] != sharesIBigInt[j] {
 94				currLagrangeNumerator := sharesIBigInt[j]
 95				currLagrangeDenominator := new(big.Int).Sub(sharesIBigInt[j], sharesIBigInt[i])
 96				lagrangeNumerator = new(big.Int).Mul(lagrangeNumerator, currLagrangeNumerator)
 97				lagrangeDenominator = new(big.Int).Mul(lagrangeDenominator, currLagrangeDenominator)
 98			}
 99		}
100		numerator := new(big.Int).Mul(sharesBigInt[i], lagrangeNumerator)
101		quo := new(big.Int).Quo(numerator, lagrangeDenominator)
102		if quo.Int64() != 0 {
103			resultN = resultN.Add(resultN, quo)
104		} else {
105			resultNMULlagrangeDenominator := new(big.Int).Mul(resultN, lagrangeDenominator)
106			resultN = new(big.Int).Add(resultNMULlagrangeDenominator, numerator)
107
108			resultD = resultD.Add(resultD, lagrangeDenominator)
109		}
110	}
111
112	var modinvMul *big.Int
113	if resultD.Int64() != 0 {
114		modinv := new(big.Int).ModInverse(resultD, p)
115		modinvMul = new(big.Int).Mul(resultN, modinv)
116	} else {
117		modinvMul = resultN
118	}
119	r := new(big.Int).Mod(modinvMul, p)
120	return r
121}