You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.2 KiB

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