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.

115 lines
3.3 KiB

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