in client/internal/secret_sharing/internal/shamirgeneric/shamir_generic.go [94:136]
func Reconstruct(splitSecret secrets.Split, gf field.GaloisField) ([]byte, error) {
if err := validateReconstructInput(splitSecret); err != nil {
return nil, err
}
// We only need `threshold` shares to reconstruct the secrets.
shares := splitSecret.Shares[:splitSecret.Metadata.Threshold]
xVals := []field.Element{}
for _, s := range shares {
xi, err := gf.CreateElement(s.X)
if err != nil {
return nil, err
}
xVals = append(xVals, xi)
}
// Precompute the Lagrange coefficients before performing polynomial interpolation.
// The output to this step could be kept in memory, but it would require making
// this implementation thread safe.
coefficients, err := lagrangeCoefficients(xVals, gf)
if err != nil {
return nil, err
}
// Calculate the number of field elements per secret share based on the share size.
var numSubSecrets = len(shares[0].Value) / gf.ElementSize()
subsecrets := make([]field.Element, numSubSecrets, numSubSecrets)
for i := 0; i < numSubSecrets; i++ {
yVals := make([]field.Element, len(xVals))
for j, s := range shares {
yVals[j], err = gf.ReadElement(s.Value, i)
if err != nil {
return nil, err
}
}
// interpolatePolynomial recovers the C[0] coefficient, the geometric interpretation
// of the intersection with the Y axis.
subsecrets[i], err = interpolatePolynomial(coefficients, yVals, gf)
if err != nil {
return nil, err
}
}
// combine the subsecret field elements into the original secrets.
return gf.EncodeElements(subsecrets, splitSecret.SecretLen)
}