mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-14 12:15:18 +00:00
469 lines
11 KiB
Go
469 lines
11 KiB
Go
package shuffle
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"math/big"
|
|
|
|
"filippo.io/edwards25519"
|
|
)
|
|
|
|
var lBE = []byte{
|
|
16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 222, 249, 222, 162, 247,
|
|
156, 214, 88, 18, 99, 26, 92, 245, 211, 236,
|
|
}
|
|
var lBigInt = big.NewInt(0).SetBytes(lBE)
|
|
|
|
func genPolyFrags(
|
|
secret *edwards25519.Scalar,
|
|
total, threshold int,
|
|
) []*edwards25519.Scalar {
|
|
coeffs := []*edwards25519.Scalar{}
|
|
coeffs = append(coeffs, secret)
|
|
|
|
for i := 1; i < threshold; i++ {
|
|
coeffBI, _ := rand.Int(rand.Reader, lBigInt)
|
|
coeff := BigIntToLEBytes(coeffBI)
|
|
scalar, err := edwards25519.NewScalar().SetCanonicalBytes(coeff[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
coeffs = append(coeffs, scalar)
|
|
}
|
|
|
|
frags := []*edwards25519.Scalar{}
|
|
|
|
for i := 1; i <= total; i++ {
|
|
result, _ := edwards25519.NewScalar().SetCanonicalBytes(coeffs[0].Bytes())
|
|
iBytes := BigIntToLEBytes(big.NewInt(int64(i)))
|
|
x, err := edwards25519.NewScalar().SetCanonicalBytes(iBytes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
for j := 1; j <= threshold-1; j++ {
|
|
xi := edwards25519.NewScalar().Multiply(coeffs[j], x)
|
|
result.Add(result, xi)
|
|
xmul, _ := edwards25519.NewScalar().SetCanonicalBytes(iBytes)
|
|
x.Multiply(x, xmul)
|
|
}
|
|
|
|
frags = append(frags, result)
|
|
}
|
|
|
|
return frags
|
|
}
|
|
|
|
func ShamirSplitMatrix(
|
|
matrix [][]*edwards25519.Scalar,
|
|
total, threshold int,
|
|
) [][][]*edwards25519.Scalar {
|
|
shamirMatrix := make([][][]*edwards25519.Scalar, len(matrix))
|
|
|
|
for x := 0; x < len(matrix); x++ {
|
|
shamirMatrix[x] = make([][]*edwards25519.Scalar, len(matrix[0]))
|
|
for y := 0; y < len(matrix[0]); y++ {
|
|
shamirMatrix[x][y] = genPolyFrags(matrix[x][y], total, threshold)
|
|
}
|
|
}
|
|
|
|
return shamirMatrix
|
|
}
|
|
|
|
func AddMatrices(matrices ...[][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|
result := make([][]*edwards25519.Scalar, len(matrices[0]))
|
|
|
|
for x := 0; x < len(matrices[0]); x++ {
|
|
result[x] = make([]*edwards25519.Scalar, len(matrices[0][0]))
|
|
|
|
for y := 0; y < len(matrices[0][0]); y++ {
|
|
result[x][y] = edwards25519.NewScalar()
|
|
|
|
for i := 0; i < len(matrices); i++ {
|
|
result[x][y].Add(result[x][y], matrices[i][x][y])
|
|
}
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func GenerateRandomVectorShares(
|
|
length, total, threshold int,
|
|
) [][]*edwards25519.Scalar {
|
|
result := make([][]*edwards25519.Scalar, length)
|
|
|
|
for i := 0; i < length; i++ {
|
|
bi, _ := rand.Int(rand.Reader, lBigInt)
|
|
biBytes := BigIntToLEBytes(bi)
|
|
scalar, _ := edwards25519.NewScalar().SetCanonicalBytes(biBytes[:])
|
|
|
|
result[i] = genPolyFrags(scalar, total, threshold)
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func InterpolatePolynomialShares(
|
|
shares []*edwards25519.Scalar,
|
|
ids []int,
|
|
) *edwards25519.Scalar {
|
|
var reconstructedSum *edwards25519.Scalar
|
|
|
|
for j := 0; j < len(ids); j++ {
|
|
oneLENumBytes := BigIntToLEBytes(big.NewInt(1))
|
|
coeffNum, _ := edwards25519.NewScalar().SetCanonicalBytes(oneLENumBytes)
|
|
coeffDenom, _ := edwards25519.NewScalar().SetCanonicalBytes(oneLENumBytes)
|
|
|
|
for k := 0; k < len(ids); k++ {
|
|
if j != k {
|
|
ikBytes := BigIntToLEBytes(big.NewInt(int64(ids[k])))
|
|
ijBytes := BigIntToLEBytes(big.NewInt(int64(ids[j])))
|
|
ikScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ikBytes)
|
|
ijScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ijBytes)
|
|
|
|
coeffNum.Multiply(coeffNum, ikScalar)
|
|
ikScalar.Subtract(ikScalar, ijScalar)
|
|
coeffDenom.Multiply(coeffDenom, ikScalar)
|
|
}
|
|
}
|
|
|
|
coeffDenom.Invert(coeffDenom)
|
|
coeffNum.Multiply(coeffNum, coeffDenom)
|
|
reconstructedFrag := edwards25519.NewScalar().Multiply(
|
|
coeffNum,
|
|
shares[ids[j]-1],
|
|
)
|
|
|
|
if reconstructedSum == nil {
|
|
reconstructedSum = reconstructedFrag
|
|
} else {
|
|
reconstructedSum.Add(reconstructedSum, reconstructedFrag)
|
|
}
|
|
}
|
|
|
|
return reconstructedSum
|
|
}
|
|
|
|
func LUDecompose(
|
|
matrix [][]*edwards25519.Scalar,
|
|
) ([][]*edwards25519.Scalar, [][]*edwards25519.Scalar) {
|
|
imax := 0
|
|
maxA := edwards25519.NewScalar()
|
|
N := len(matrix)
|
|
p := make([]int, N)
|
|
pm := make([][]*edwards25519.Scalar, N)
|
|
newA := make([][]*edwards25519.Scalar, N)
|
|
|
|
for i := 0; i < N; i++ {
|
|
newA[i] = make([]*edwards25519.Scalar, N)
|
|
pm[i] = make([]*edwards25519.Scalar, N)
|
|
p[i] = i
|
|
for j := 0; j < N; j++ {
|
|
newA[i][j], _ = edwards25519.NewScalar().SetCanonicalBytes(
|
|
matrix[i][j].Bytes(),
|
|
)
|
|
}
|
|
}
|
|
|
|
scalarOne, _ := edwards25519.NewScalar().SetCanonicalBytes(
|
|
BigIntToLEBytes(big.NewInt(int64(1))),
|
|
)
|
|
|
|
for i := 0; i < N; i++ {
|
|
maxA = edwards25519.NewScalar()
|
|
imax = i
|
|
|
|
for k := i; k < N; k++ {
|
|
if LEBytesToBigInt(newA[k][i].Bytes()).Cmp(
|
|
LEBytesToBigInt(maxA.Bytes()),
|
|
) > 0 {
|
|
maxA = newA[k][i]
|
|
imax = k
|
|
}
|
|
}
|
|
|
|
if imax != i {
|
|
//pivoting P
|
|
j := p[i]
|
|
p[i] = p[imax]
|
|
p[imax] = j
|
|
|
|
//pivoting rows of A
|
|
ptr := newA[i]
|
|
newA[i] = newA[imax]
|
|
newA[imax] = ptr
|
|
}
|
|
|
|
for j := i + 1; j < N; j++ {
|
|
newA[j][i].Multiply(
|
|
newA[j][i],
|
|
edwards25519.NewScalar().Invert(newA[i][i]),
|
|
)
|
|
|
|
for k := i + 1; k < N; k++ {
|
|
newA[j][k].Subtract(newA[j][k], edwards25519.NewScalar().Multiply(
|
|
newA[j][i],
|
|
newA[i][k],
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
for i := 0; i < N; i++ {
|
|
for j := 0; j < N; j++ {
|
|
if p[i] == j {
|
|
pm[i][j] = scalarOne
|
|
} else {
|
|
pm[i][j] = edwards25519.NewScalar()
|
|
}
|
|
}
|
|
}
|
|
|
|
return newA, pm
|
|
}
|
|
|
|
func Invert(matrix [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|
a, p := LUDecompose(matrix)
|
|
ia := make([][]*edwards25519.Scalar, len(matrix))
|
|
|
|
for i := 0; i < len(matrix); i++ {
|
|
ia[i] = make([]*edwards25519.Scalar, len(matrix))
|
|
}
|
|
|
|
for j := 0; j < len(matrix); j++ {
|
|
for i := 0; i < len(matrix); i++ {
|
|
ia[i][j] = edwards25519.NewScalar().Set(p[i][j])
|
|
|
|
for k := 0; k < i; k++ {
|
|
ia[i][j].Subtract(ia[i][j], edwards25519.NewScalar().Multiply(
|
|
a[i][k],
|
|
ia[k][j],
|
|
))
|
|
}
|
|
}
|
|
|
|
for i := len(matrix) - 1; i >= 0; i-- {
|
|
for k := i + 1; k < len(matrix); k++ {
|
|
ia[i][j].Subtract(ia[i][j], edwards25519.NewScalar().Multiply(
|
|
a[i][k],
|
|
ia[k][j],
|
|
))
|
|
}
|
|
|
|
ia[i][j].Multiply(ia[i][j], edwards25519.NewScalar().Invert(a[i][i]))
|
|
}
|
|
}
|
|
|
|
return ia
|
|
}
|
|
|
|
func InterpolateMatrixShares(
|
|
matrixShares [][][]*edwards25519.Scalar,
|
|
ids []int,
|
|
) [][]*edwards25519.Scalar {
|
|
matrix := make([][]*edwards25519.Scalar, len(matrixShares))
|
|
|
|
for x := 0; x < len(matrix); x++ {
|
|
matrix[x] = make([]*edwards25519.Scalar, len(matrixShares[0]))
|
|
for y := 0; y < len(matrix[0]); y++ {
|
|
matrix[x][y] = InterpolatePolynomialShares(matrixShares[x][y], ids)
|
|
}
|
|
}
|
|
|
|
return matrix
|
|
}
|
|
|
|
func ScalarMult(a int, b [][]*edwards25519.Scalar) [][]*edwards25519.Scalar {
|
|
prod := make([][]*edwards25519.Scalar, len(b))
|
|
for x := 0; x < len(b); x++ {
|
|
prod[x] = make([]*edwards25519.Scalar, len(b[0]))
|
|
|
|
for y := 0; y < len(b[0]); y++ {
|
|
if a >= 0 {
|
|
prod[x][y], _ = edwards25519.NewScalar().SetCanonicalBytes(
|
|
BigIntToLEBytes(big.NewInt(int64(a))),
|
|
)
|
|
} else {
|
|
negA, _ := edwards25519.NewScalar().SetCanonicalBytes(
|
|
BigIntToLEBytes(big.NewInt(int64(-a))),
|
|
)
|
|
prod[x][y] = edwards25519.NewScalar().Subtract(
|
|
edwards25519.NewScalar(),
|
|
negA,
|
|
)
|
|
}
|
|
|
|
prod[x][y] = prod[x][y].Multiply(prod[x][y], b[x][y])
|
|
}
|
|
}
|
|
|
|
return prod
|
|
}
|
|
|
|
func GenerateDotProduct(
|
|
a, b [][]*edwards25519.Scalar,
|
|
) [][]*edwards25519.Scalar {
|
|
if len(a[0]) != len(b) {
|
|
panic("cannot generate dot product of a and b - mismatched length")
|
|
}
|
|
|
|
abMatrix := make([][]*edwards25519.Scalar, len(a))
|
|
|
|
for x := 0; x < len(a); x++ {
|
|
abMatrix[x] = make([]*edwards25519.Scalar, len(b[0]))
|
|
|
|
for y := 0; y < len(b[0]); y++ {
|
|
abMatrix[x][y] = edwards25519.NewScalar()
|
|
|
|
for ay := 0; ay < len(a[0]); ay++ {
|
|
abMatrix[x][y].MultiplyAdd(a[x][ay], b[ay][y], abMatrix[x][y])
|
|
}
|
|
}
|
|
}
|
|
|
|
return abMatrix
|
|
}
|
|
|
|
func GenerateRandomMatrixAndInverseShares(
|
|
size, total, threshold int,
|
|
) [2][][][]*edwards25519.Scalar {
|
|
output := make([][]*edwards25519.Scalar, size)
|
|
for x := 0; x < size; x++ {
|
|
output[x] = make([]*edwards25519.Scalar, size)
|
|
for y := 0; y < size; y++ {
|
|
i, _ := rand.Int(rand.Reader, lBigInt)
|
|
iBytes := BigIntToLEBytes(i)
|
|
iScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(iBytes[:])
|
|
output[x][y] = iScalar
|
|
}
|
|
}
|
|
|
|
splitOutput := ShamirSplitMatrix(output, total, threshold)
|
|
splitInverse := ShamirSplitMatrix(Invert(output), total, threshold)
|
|
|
|
return [2][][][]*edwards25519.Scalar{splitOutput, splitInverse}
|
|
}
|
|
|
|
func GenerateRandomBeaverTripleMatrixShares(
|
|
size, total, threshold int,
|
|
) [3][][][]*edwards25519.Scalar {
|
|
uMatrix := make([][]*edwards25519.Scalar, size)
|
|
vMatrix := make([][]*edwards25519.Scalar, size)
|
|
|
|
for i := 0; i < size; i++ {
|
|
uMatrix[i] = make([]*edwards25519.Scalar, size)
|
|
vMatrix[i] = make([]*edwards25519.Scalar, size)
|
|
|
|
for j := 0; j < size; j++ {
|
|
uj, _ := rand.Int(rand.Reader, lBigInt)
|
|
ujBytes := BigIntToLEBytes(uj)
|
|
ujScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(ujBytes[:])
|
|
vj, _ := rand.Int(rand.Reader, lBigInt)
|
|
vjBytes := BigIntToLEBytes(vj)
|
|
vjScalar, _ := edwards25519.NewScalar().SetCanonicalBytes(vjBytes[:])
|
|
|
|
uMatrix[i][j] = ujScalar
|
|
vMatrix[i][j] = vjScalar
|
|
}
|
|
}
|
|
|
|
uvMatrix := GenerateDotProduct(uMatrix, vMatrix)
|
|
|
|
uMatrixShares := ShamirSplitMatrix(uMatrix, total, threshold)
|
|
vMatrixShares := ShamirSplitMatrix(vMatrix, total, threshold)
|
|
uvMatrixShares := ShamirSplitMatrix(uvMatrix, total, threshold)
|
|
|
|
return [3][][][]*edwards25519.Scalar{
|
|
uMatrixShares, vMatrixShares, uvMatrixShares,
|
|
}
|
|
}
|
|
|
|
func GeneratePermutationMatrix(size int) [][]*edwards25519.Scalar {
|
|
matrix := [][]*edwards25519.Scalar{}
|
|
elements := []int{}
|
|
|
|
for i := 0; i < size; i++ {
|
|
elements = append(elements, i)
|
|
}
|
|
|
|
for i := 0; i < size; i++ {
|
|
pos, _ := rand.Int(rand.Reader, big.NewInt(int64(len(elements))))
|
|
var vecPos int
|
|
|
|
elements, vecPos = remove(elements, int(pos.Int64()))
|
|
|
|
scalarOne, err := edwards25519.NewScalar().SetCanonicalBytes(
|
|
BigIntToLEBytes(big.NewInt(1)),
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
vector := []*edwards25519.Scalar{}
|
|
|
|
for j := 0; j < vecPos; j++ {
|
|
scalarZero, err := edwards25519.NewScalar().SetCanonicalBytes(
|
|
BigIntToLEBytes(big.NewInt(0)),
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
vector = append(vector, scalarZero)
|
|
}
|
|
|
|
vector = append(vector, scalarOne)
|
|
|
|
for j := vecPos + 1; j < size; j++ {
|
|
scalarZero, err := edwards25519.NewScalar().SetCanonicalBytes(
|
|
BigIntToLEBytes(big.NewInt(0)),
|
|
)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
vector = append(vector, scalarZero)
|
|
}
|
|
|
|
matrix = append(matrix, vector)
|
|
}
|
|
|
|
return matrix
|
|
}
|
|
|
|
func BigIntToLEBytes(bi *big.Int) []byte {
|
|
b := bi.Bytes()
|
|
last := len(b) - 1
|
|
|
|
for i := 0; i < len(b)/2; i++ {
|
|
b[i], b[last-i] = b[last-i], b[i]
|
|
}
|
|
|
|
for i := len(b); i < 32; i++ {
|
|
b = append(b, 0x00)
|
|
}
|
|
|
|
return b
|
|
}
|
|
|
|
func LEBytesToBigInt(bytes []byte) *big.Int {
|
|
b := make([]byte, len(bytes))
|
|
last := len(b) - 1
|
|
|
|
for i := 0; i < len(b)/2; i++ {
|
|
b[i], b[last-i] = b[last-i], b[i]
|
|
}
|
|
|
|
res := big.NewInt(0)
|
|
return res.SetBytes(b)
|
|
}
|
|
|
|
func remove(elements []int, i int) ([]int, int) {
|
|
ret := elements[i]
|
|
elements[i] = elements[len(elements)-1]
|
|
newElements := []int{}
|
|
newElements = append(newElements, elements[:len(elements)-1]...)
|
|
return newElements, ret
|
|
}
|