mirror of
https://github.com/arnaucube/cryptofun.git
synced 2026-02-28 05:16:46 +01:00
shamirsecretsharing moved to it's own repository plus wasm compiled lib
This commit is contained in:
@@ -1,48 +1,4 @@
|
|||||||
## Shamir Secret Sharing
|
## Shamir Secret Sharing
|
||||||
- https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing
|
Implementation of the Shamir Secret Sharing in Go + WASM compiled lib
|
||||||
|
|
||||||
- [x] create secret sharing from number of secrets needed, number of shares, random point p, secret to share
|
Code moved to https://github.com/arnaucube/shamirsecretsharing
|
||||||
- [x] Lagrange Interpolation to restore the secret from the shares
|
|
||||||
|
|
||||||
#### Usage
|
|
||||||
```go
|
|
||||||
// define secret to share
|
|
||||||
k := 123456789
|
|
||||||
|
|
||||||
// define random prime
|
|
||||||
p, err := rand.Prime(rand.Reader, bits/2)
|
|
||||||
if err!=nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// define how many shares want to generate
|
|
||||||
nShares := big.NewInt(int64(6))
|
|
||||||
|
|
||||||
// define how many shares are needed to recover the secret
|
|
||||||
nNeededShares := big.NewInt(int64(3))
|
|
||||||
|
|
||||||
// create the shares
|
|
||||||
shares, err := Create(
|
|
||||||
nNeededShares,
|
|
||||||
nShares,
|
|
||||||
p,
|
|
||||||
big.NewInt(int64(k)))
|
|
||||||
assert.Nil(t, err)
|
|
||||||
if err!=nil {
|
|
||||||
fmt.Println(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// select shares to use
|
|
||||||
var sharesToUse [][]*big.Int
|
|
||||||
sharesToUse = append(sharesToUse, shares[2])
|
|
||||||
sharesToUse = append(sharesToUse, shares[1])
|
|
||||||
sharesToUse = append(sharesToUse, shares[0])
|
|
||||||
|
|
||||||
// recover the secret using Lagrange Interpolation
|
|
||||||
secr := LagrangeInterpolation(sharesToUse, p)
|
|
||||||
|
|
||||||
// check that the restored secret matches the original secret
|
|
||||||
if !bytes.Equal(k.Bytes(), secr.Bytes()) {
|
|
||||||
fmt.Println("reconstructed secret not correspond to original secret")
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
package shamirsecretsharing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// bits = 1024
|
|
||||||
bits = 2048
|
|
||||||
)
|
|
||||||
|
|
||||||
// Create calculates the secrets to share from given parameters
|
|
||||||
// t: number of secrets needed
|
|
||||||
// n: number of shares
|
|
||||||
// p: random point
|
|
||||||
// k: secret to share
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
package shamirsecretsharing
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/rand"
|
|
||||||
"math/big"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
|
||||||
k := big.NewInt(int64(123456789))
|
|
||||||
p, err := rand.Prime(rand.Reader, bits/2)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
nShares := big.NewInt(int64(6))
|
|
||||||
nNeededShares := big.NewInt(int64(3))
|
|
||||||
shares, err := Create(
|
|
||||||
nNeededShares,
|
|
||||||
nShares,
|
|
||||||
p,
|
|
||||||
k)
|
|
||||||
assert.Nil(t, err)
|
|
||||||
|
|
||||||
//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 !bytes.Equal(k.Bytes(), secr.Bytes()) {
|
|
||||||
t.Errorf("reconstructed secret not correspond to original secret")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user