mirror of
https://github.com/luxfi/threshold.git
synced 2026-10-30 15:15:53 +00:00
78 lines
2.7 KiB
Go
78 lines
2.7 KiB
Go
package polynomial
|
|
|
|
import (
|
|
"github.com/cronokirby/saferith"
|
|
"github.com/luxfi/threshold/pkg/math/curve"
|
|
"github.com/luxfi/threshold/pkg/party"
|
|
)
|
|
|
|
// Lagrange returns the Lagrange coefficients at 0 for all parties in the interpolation domain.
|
|
func Lagrange(group curve.Curve, interpolationDomain []party.ID) map[party.ID]curve.Scalar {
|
|
return LagrangeFor(group, interpolationDomain, interpolationDomain...)
|
|
}
|
|
|
|
// LagrangeFor returns the Lagrange coefficients at 0 for all parties in the given subset.
|
|
func LagrangeFor(group curve.Curve, interpolationDomain []party.ID, subset ...party.ID) map[party.ID]curve.Scalar {
|
|
// numerator = x₀ * … * xₖ
|
|
scalars, numerator := getScalarsAndNumerator(group, interpolationDomain)
|
|
|
|
coefficients := make(map[party.ID]curve.Scalar, len(subset))
|
|
for _, j := range subset {
|
|
coefficients[j] = lagrange(group, scalars, numerator, j)
|
|
}
|
|
return coefficients
|
|
}
|
|
|
|
// LagrangeSingle returns the lagrange coefficient at 0 of the party with index j.
|
|
func LagrangeSingle(group curve.Curve, interpolationDomain []party.ID, j party.ID) curve.Scalar {
|
|
return LagrangeFor(group, interpolationDomain, j)[j]
|
|
}
|
|
|
|
// getScalarsAndNumerator returns the Scalars associated to the list of party.IDs.
|
|
func getScalarsAndNumerator(group curve.Curve, interpolationDomain []party.ID) (map[party.ID]curve.Scalar, curve.Scalar) {
|
|
// numerator = x₀ * … * xₖ
|
|
numerator := group.NewScalar().SetNat(new(saferith.Nat).SetUint64(1))
|
|
scalars := make(map[party.ID]curve.Scalar, len(interpolationDomain))
|
|
for _, id := range interpolationDomain {
|
|
xi := id.Scalar(group)
|
|
scalars[id] = xi
|
|
numerator.Mul(xi)
|
|
}
|
|
return scalars, numerator
|
|
}
|
|
|
|
// lagrange returns the Lagrange coefficient lⱼ(0), for j in the interpolation domain.
|
|
// The numerator is provided beforehand for efficiency reasons.
|
|
//
|
|
// The following formulas are taken from
|
|
// https://en.wikipedia.org/wiki/Lagrange_polynomial
|
|
//
|
|
// x₀ ⋅⋅⋅ xₖ
|
|
//
|
|
// lⱼ(0) = --------------------------------------------------
|
|
//
|
|
// xⱼ⋅(x₀ - xⱼ)⋅⋅⋅(xⱼ₋₁ - xⱼ)⋅(xⱼ₊₁ - xⱼ)⋅⋅⋅(xₖ - xⱼ).
|
|
func lagrange(group curve.Curve, interpolationDomain map[party.ID]curve.Scalar, numerator curve.Scalar, j party.ID) curve.Scalar {
|
|
xJ := interpolationDomain[j]
|
|
tmp := group.NewScalar()
|
|
|
|
// denominator = xⱼ⋅(xⱼ - x₀)⋅⋅⋅(xⱼ₋₁ - xⱼ)⋅(xⱼ₊₁ - xⱼ)⋅⋅⋅(xₖ - xⱼ)
|
|
denominator := group.NewScalar().SetNat(new(saferith.Nat).SetUint64(1))
|
|
for i, xI := range interpolationDomain {
|
|
if i == j {
|
|
// lⱼ *= xⱼ
|
|
denominator.Mul(xJ)
|
|
continue
|
|
}
|
|
// tmp = xᵢ - xⱼ
|
|
tmp.Set(xJ).Negate().Add(xI)
|
|
// lⱼ *= xᵢ - xⱼ
|
|
denominator.Mul(tmp)
|
|
}
|
|
|
|
// lⱼ = numerator/denominator
|
|
lJ := denominator.Invert()
|
|
lJ.Mul(numerator)
|
|
return lJ
|
|
}
|