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.

121 lines
3.4 KiB

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