mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-01-05 13:07:10 +00:00
Move field and matrix logic into their own files and abstractions.
- Instead of using GF(2^127-1) as one of many options, move to GF(2^128) exclusively. - Don't clear the first two bits of every secret key.
This commit is contained in:
@@ -116,9 +116,8 @@ fmt.Printf("%v\n", r2.Formatted()) // (3, Alice, Bob, Carl)
|
||||
```go
|
||||
type MSP Formatted
|
||||
|
||||
func Modulus(n int) *big.Int {}
|
||||
func (m MSP) DistributeShares(sec []byte, modulus *big.Int, db *UserDatabase) (map[string][][]byte, error) {}
|
||||
func (m MSP) RecoverSecret(modulus *big.Int, db *UserDatabase) ([]byte, error) {}
|
||||
func (m MSP) DistributeShares(sec []byte, db *UserDatabase) (map[string][][]byte, error) {}
|
||||
func (m MSP) RecoverSecret(db *UserDatabase) ([]byte, error) {}
|
||||
```
|
||||
|
||||
To switch from predicate-mode to secret-sharing-mode, just cast your formatted
|
||||
@@ -133,21 +132,3 @@ of shares which should be given to that party and integrated into the
|
||||
`UserDatabase` somehow. When you're ready to reconstruct the secret, you call
|
||||
`RecoverSecret`, which does some prodding about and hopefully gives you back
|
||||
what you put in.
|
||||
|
||||
The modulus determines the size of the secret shares. It must be prime, larger
|
||||
than the secret, and larger than n<sup>k</sup> where `n` is the number of
|
||||
parties and `k` is the depth of the circuit. (For each path from the root to a
|
||||
gate with only leaf nodes, sum the thresholds of all the gates along that path.
|
||||
`k` is the maximum of these values--a safe overestimation is to sum the
|
||||
thresholds of all gates in the circuit) Because this form of secret sharing
|
||||
is *information-theoretically secure*, as long as the modulus satisfies those
|
||||
requirements, it can be as small or as large as you'd like (there's no
|
||||
bonus/reduction in security). An excessively small modulus is restrictive, but
|
||||
saves a *lot* of bandwidth. However, there's no sensible reason for a modulus
|
||||
over about 256 bits--by that point, it's easier to generate a random AES key,
|
||||
encrypt your secret with *that*, and distribute shares of the decryption key
|
||||
instead.
|
||||
|
||||
For convenience, the `Modulus` function has some hard coded moduli that are
|
||||
useful. The choices are currently: `127`, `224`, and `256` for a 127-bit,
|
||||
224-bit, or 256-bit modulus, respectively.
|
||||
|
||||
149
msp/matrix.go
Normal file
149
msp/matrix.go
Normal file
@@ -0,0 +1,149 @@
|
||||
// Matrix operations for elements in GF(2^128).
|
||||
package msp
|
||||
|
||||
type Row []FieldElem
|
||||
|
||||
// NewRow returns a row of length s with all zero entries.
|
||||
func NewRow(s int) Row {
|
||||
out := Row(make([]FieldElem, s))
|
||||
|
||||
for i := 0; i < s; i++ {
|
||||
out[i] = NewFieldElem()
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// AddM adds two vectors.
|
||||
func (e Row) AddM(f Row) {
|
||||
le, lf := e.Size(), f.Size()
|
||||
if le != lf {
|
||||
panic("Can't add rows that are different sizes!")
|
||||
}
|
||||
|
||||
for i, f_i := range f {
|
||||
e[i].AddM(f_i)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// MulM multiplies the row by a scalar.
|
||||
func (e Row) MulM(f FieldElem) {
|
||||
for i, _ := range e {
|
||||
e[i] = e[i].Mul(f)
|
||||
}
|
||||
}
|
||||
|
||||
func (e Row) Mul(f FieldElem) Row {
|
||||
out := NewRow(e.Size())
|
||||
|
||||
for i := 0; i < e.Size(); i++ {
|
||||
out[i] = e[i].Mul(f)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// DotProduct computes the dot product of two vectors.
|
||||
func (e Row) DotProduct(f Row) FieldElem {
|
||||
if e.Size() != f.Size() {
|
||||
panic("Can't get dot product of rows of different length!")
|
||||
}
|
||||
|
||||
out := NewFieldElem()
|
||||
|
||||
for i := 0; i < e.Size(); i++ {
|
||||
out.AddM(e[i].Mul(f[i]))
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func (e Row) Size() int {
|
||||
return len(e)
|
||||
}
|
||||
|
||||
type Matrix []Row
|
||||
|
||||
// Mul right-multiplies a matrix by a row.
|
||||
func (e Matrix) Mul(f Row) Row {
|
||||
out, in := e.Size()
|
||||
if in != f.Size() {
|
||||
panic("Can't multiply by row that is wrong size!")
|
||||
}
|
||||
|
||||
res := NewRow(out)
|
||||
|
||||
for i := 0; i < out; i++ {
|
||||
res[i] = e[i].DotProduct(f)
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// Recovery returns the row vector that takes this matrix to the target vector [1 0 0 ... 0].
|
||||
func (e Matrix) Recovery() (Row, bool) {
|
||||
a, b := e.Size()
|
||||
|
||||
// aug is the target vector.
|
||||
aug := NewRow(a)
|
||||
aug[0] = One.Dup()
|
||||
|
||||
// Duplicate e away so we don't mutate it; transpose it at the same time.
|
||||
f := make([]Row, b)
|
||||
for i, _ := range f {
|
||||
f[i] = NewRow(a)
|
||||
}
|
||||
|
||||
for i := 0; i < a; i++ {
|
||||
for j := 0; j < b; j++ {
|
||||
f[j][i] = e[i][j].Dup()
|
||||
}
|
||||
}
|
||||
|
||||
for row, _ := range f {
|
||||
if row >= b { // The matrix is tall and thin--we've finished before exhausting all the rows.
|
||||
break
|
||||
}
|
||||
|
||||
// Find a row with a non-zero entry in the (row)th position
|
||||
candId := -1
|
||||
for j, f_j := range f[row:] {
|
||||
if !f_j[row].IsZero() {
|
||||
candId = j + row
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if candId == -1 { // If we can't find one, fail and return our partial work.
|
||||
return aug, false
|
||||
}
|
||||
|
||||
// Move it to the top
|
||||
f[row], f[candId] = f[candId], f[row]
|
||||
aug[row], aug[candId] = aug[candId], aug[row]
|
||||
|
||||
// Make the pivot 1.
|
||||
fInv := f[row][row].Invert()
|
||||
|
||||
f[row].MulM(fInv)
|
||||
aug[row] = aug[row].Mul(fInv)
|
||||
|
||||
// Cancel out the (row)th position for every row above and below it.
|
||||
for i, _ := range f {
|
||||
if i != row && !f[i][row].IsZero() {
|
||||
c := f[i][row].Dup()
|
||||
|
||||
f[i].AddM(f[row].Mul(c))
|
||||
aug[i].AddM(aug[row].Mul(c))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return aug, true
|
||||
}
|
||||
|
||||
func (e Matrix) Size() (int, int) {
|
||||
return len(e), e[0].Size()
|
||||
}
|
||||
44
msp/matrix_test.go
Normal file
44
msp/matrix_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package msp
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestRecovery(t *testing.T) {
|
||||
// Generate the matrix.
|
||||
height, width := 10, 10
|
||||
M := Matrix(make([]Row, height))
|
||||
|
||||
for i := 0; i < height; i++ {
|
||||
M[i] = NewRow(width)
|
||||
|
||||
for j := 0; j < width; j++ {
|
||||
M[i][j][0] = byte(i + 1)
|
||||
M[i][j] = M[i][j].Exp(j)
|
||||
}
|
||||
}
|
||||
|
||||
// Find the recovery vector.
|
||||
r, ok := M.Recovery()
|
||||
if !ok {
|
||||
t.Fatalf("Failed to find the recovery vector!")
|
||||
}
|
||||
|
||||
// Find the output vector.
|
||||
out := NewRow(width)
|
||||
|
||||
for i := 0; i < height; i++ {
|
||||
out.AddM(M[i].Mul(r[i]))
|
||||
}
|
||||
|
||||
// Check that it is the target vector.
|
||||
if !out[0].IsOne() {
|
||||
t.Fatalf("Output is not the target vector!")
|
||||
}
|
||||
|
||||
for i := 1; i < width; i++ {
|
||||
if !out[i].IsZero() {
|
||||
t.Fatalf("Output is not the target vector!")
|
||||
}
|
||||
}
|
||||
}
|
||||
214
msp/msp.go
214
msp/msp.go
@@ -4,7 +4,6 @@ import (
|
||||
"container/heap"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -82,34 +81,6 @@ TopLoop:
|
||||
|
||||
type MSP Formatted
|
||||
|
||||
func Modulus(n int) (modulus *big.Int) {
|
||||
switch n {
|
||||
case 256:
|
||||
modulus = big.NewInt(1) // 2^256 - 2^224 + 2^192 + 2^96 - 1
|
||||
modulus.Lsh(modulus, 256)
|
||||
modulus.Sub(modulus, big.NewInt(0).Lsh(big.NewInt(1), 224))
|
||||
modulus.Add(modulus, big.NewInt(0).Lsh(big.NewInt(1), 192))
|
||||
modulus.Add(modulus, big.NewInt(0).Lsh(big.NewInt(1), 96))
|
||||
modulus.Sub(modulus, big.NewInt(1))
|
||||
|
||||
case 224:
|
||||
modulus = big.NewInt(1) // 2^224 - 2^96 + 1
|
||||
modulus.Lsh(modulus, 224)
|
||||
modulus.Sub(modulus, big.NewInt(0).Lsh(big.NewInt(1), 96))
|
||||
modulus.Add(modulus, big.NewInt(1))
|
||||
|
||||
case 127:
|
||||
modulus = big.NewInt(1) // 2^127 - 1
|
||||
modulus.Lsh(modulus, 127)
|
||||
modulus.Sub(modulus, big.NewInt(1))
|
||||
|
||||
default:
|
||||
panic("Invalid modulus size chosen!")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func StringToMSP(pred string) (m MSP, err error) {
|
||||
var f Formatted
|
||||
|
||||
@@ -164,53 +135,56 @@ func (m MSP) DerivePath(db *UserDatabase) (ok bool, names []string, locs []int,
|
||||
return
|
||||
}
|
||||
|
||||
func (m MSP) DistributeShares(sec []byte, modulus *big.Int, db *UserDatabase) (map[string][][]byte, error) {
|
||||
// DistributeShares takes as input a secret and a user database and returns secret shares according to access structure
|
||||
// described by the MSP.
|
||||
func (m MSP) DistributeShares(sec []byte, db *UserDatabase) (map[string][][]byte, error) {
|
||||
out := make(map[string][][]byte)
|
||||
|
||||
// Math to distribute shares.
|
||||
secInt := big.NewInt(0).SetBytes(sec) // Convert secret to number.
|
||||
secInt.Mod(secInt, modulus)
|
||||
// Generate a Vandermonde matrix.
|
||||
height, width := len(m.Conds), m.Min
|
||||
M := Matrix(make([]Row, height))
|
||||
|
||||
var junk []*big.Int // Generate junk numbers.
|
||||
for i := 1; i < m.Min; i++ {
|
||||
r := make([]byte, (modulus.BitLen()/8)+1)
|
||||
_, err := rand.Read(r)
|
||||
if err != nil {
|
||||
return out, err
|
||||
for i := 0; i < height; i++ {
|
||||
M[i] = NewRow(width)
|
||||
|
||||
for j := 0; j < width; j++ {
|
||||
M[i][j][0] = byte(i + 1)
|
||||
M[i][j] = M[i][j].Exp(j)
|
||||
}
|
||||
|
||||
s := big.NewInt(0).SetBytes(r)
|
||||
s.Mod(s, modulus)
|
||||
|
||||
junk = append(junk, s)
|
||||
}
|
||||
|
||||
for i, cond := range m.Conds { // Calculate shares.
|
||||
share := big.NewInt(1)
|
||||
share.Mul(share, secInt)
|
||||
// Convert secret vector.
|
||||
s := NewRow(width)
|
||||
s[0] = FieldElem(sec)
|
||||
|
||||
for j := 2; j <= m.Min; j++ {
|
||||
cell := big.NewInt(int64(i + 1))
|
||||
cell.Exp(cell, big.NewInt(int64(j-1)), modulus)
|
||||
// CELL SHOULD ALWAYS BE LESS THAN MODULUS
|
||||
for i := 1; i < width; i++ {
|
||||
r := NewFieldElem()
|
||||
rand.Read(r)
|
||||
|
||||
share.Add(share, cell.Mul(cell, junk[j-2])).Mod(share, modulus)
|
||||
}
|
||||
s[i] = FieldElem(r)
|
||||
}
|
||||
|
||||
// Calculate shares.
|
||||
shares := M.Mul(s)
|
||||
|
||||
// Distribute the shares.
|
||||
for i, cond := range m.Conds {
|
||||
share := shares[i]
|
||||
|
||||
switch cond.(type) {
|
||||
case Name:
|
||||
name := cond.(Name).string
|
||||
if _, ok := out[name]; ok {
|
||||
out[name] = append(out[name], m.encode(share, modulus))
|
||||
out[name] = append(out[name], share)
|
||||
} else if (*db).ValidUser(name) {
|
||||
out[name] = [][]byte{m.encode(share, modulus)}
|
||||
out[name] = [][]byte{share}
|
||||
} else {
|
||||
return out, errors.New("Unknown user in predicate.")
|
||||
}
|
||||
|
||||
default:
|
||||
below := MSP(cond.(Formatted))
|
||||
subOut, err := below.DistributeShares(m.encode(share, modulus), modulus, db)
|
||||
subOut, err := below.DistributeShares(share, db)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
@@ -229,15 +203,16 @@ func (m MSP) DistributeShares(sec []byte, modulus *big.Int, db *UserDatabase) (m
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (m MSP) RecoverSecret(modulus *big.Int, db *UserDatabase) ([]byte, error) {
|
||||
// RecoverSecret takes a user database storing secret shares as input and returns the original secret.
|
||||
func (m MSP) RecoverSecret(db *UserDatabase) ([]byte, error) {
|
||||
cache := make(map[string][][]byte, 0) // Caches un-used shares for a user.
|
||||
return m.recoverSecret(modulus, db, cache)
|
||||
return m.recoverSecret(db, cache)
|
||||
}
|
||||
|
||||
func (m MSP) recoverSecret(modulus *big.Int, db *UserDatabase, cache map[string][][]byte) ([]byte, error) {
|
||||
func (m MSP) recoverSecret(db *UserDatabase, cache map[string][][]byte) ([]byte, error) {
|
||||
var (
|
||||
index = []int{} // Indexes where given shares were in the matrix.
|
||||
shares = [][]byte{} // Contains shares that will be used in reconstruction.
|
||||
index = []int{} // Indexes where given shares were in the matrix.
|
||||
shares = []FieldElem{} // Contains shares that will be used in reconstruction.
|
||||
)
|
||||
|
||||
ok, names, locs, _ := m.DerivePath(db)
|
||||
@@ -266,118 +241,39 @@ func (m MSP) recoverSecret(modulus *big.Int, db *UserDatabase, cache map[string]
|
||||
return nil, errors.New("Predicate / database mismatch!")
|
||||
}
|
||||
|
||||
shares = append(shares, cache[gate.(Name).string][gate.(Name).index])
|
||||
shares = append(shares, FieldElem(cache[gate.(Name).string][gate.(Name).index]))
|
||||
|
||||
case Formatted:
|
||||
share, err := MSP(gate.(Formatted)).recoverSecret(modulus, db, cache)
|
||||
share, err := MSP(gate.(Formatted)).recoverSecret(db, cache)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shares = append(shares, share)
|
||||
shares = append(shares, FieldElem(share))
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the reconstruction vector. We only need the top row of the
|
||||
// matrix's inverse, so we augment M transposed with u1 transposed and
|
||||
// eliminate Gauss-Jordan style.
|
||||
matrix := [][][2]int{} // 2d grid of (numerator, denominator)
|
||||
matrix = append(matrix, [][2]int{}) // Create first row of all 1s
|
||||
// Generate the Vandermonde matrix specific to whichever users' shares we're using.
|
||||
MSub := Matrix(make([]Row, m.Min))
|
||||
|
||||
for j := 0; j < m.Min; j++ {
|
||||
matrix[0] = append(matrix[0], [2]int{1, 1})
|
||||
for i := 0; i < m.Min; i++ {
|
||||
MSub[i] = NewRow(m.Min)
|
||||
|
||||
for j := 0; j < m.Min; j++ {
|
||||
MSub[i][j][0] = byte(index[i])
|
||||
MSub[i][j] = MSub[i][j].Exp(j)
|
||||
}
|
||||
}
|
||||
|
||||
for j := 1; j < m.Min; j++ { // Fill in rest of matrix.
|
||||
row := [][2]int{}
|
||||
|
||||
for k, idx := range index {
|
||||
row = append(row, [2]int{int(idx) * matrix[j-1][k][0], matrix[j-1][k][1]})
|
||||
}
|
||||
|
||||
matrix = append(matrix, row)
|
||||
}
|
||||
|
||||
matrix[0] = append(matrix[0], [2]int{1, 1}) // Stick on last column.
|
||||
for j := 1; j < m.Min; j++ {
|
||||
matrix[j] = append(matrix[j], [2]int{0, 1})
|
||||
}
|
||||
|
||||
// Reduce matrix.
|
||||
for i := 0; i < len(matrix); i++ {
|
||||
for j := 0; j < len(matrix[i]); j++ { // Make row unary.
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
|
||||
matrix[i][j][0] *= matrix[i][i][1]
|
||||
matrix[i][j][1] *= matrix[i][i][0]
|
||||
}
|
||||
matrix[i][i] = [2]int{1, 1}
|
||||
|
||||
for j := 0; j < len(matrix); j++ { // Remove this row from the others.
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
|
||||
top := matrix[j][i][0]
|
||||
bot := matrix[j][i][1]
|
||||
|
||||
for k := 0; k < len(matrix[j]); k++ {
|
||||
// matrix[j][k] = matrix[j][k] - matrix[j][i] * matrix[i][k]
|
||||
temp := [2]int{0, 0}
|
||||
temp[0] = top * matrix[i][k][0]
|
||||
temp[1] = bot * matrix[i][k][1]
|
||||
|
||||
if matrix[j][k][0] == 0 {
|
||||
matrix[j][k][0] = -temp[0]
|
||||
matrix[j][k][1] = temp[1]
|
||||
} else {
|
||||
matrix[j][k][0] = (matrix[j][k][0] * temp[1]) - (temp[0] * matrix[j][k][1])
|
||||
matrix[j][k][1] *= temp[1]
|
||||
}
|
||||
|
||||
if matrix[j][k][0] == 0 {
|
||||
matrix[j][k][1] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
// Calculate the reconstruction vector and use it to recover the secret.
|
||||
r, ok := MSub.Recovery()
|
||||
if !ok {
|
||||
return nil, errors.New("Unable to find a reconstruction vector!")
|
||||
}
|
||||
|
||||
// Compute dot product of the shares vector and the reconstruction vector to
|
||||
// reconstruct the secret.
|
||||
secInt := big.NewInt(0)
|
||||
// recover the secret.
|
||||
s := Row(shares).DotProduct(r)
|
||||
|
||||
for i, share := range shares {
|
||||
lst := len(matrix[i]) - 1
|
||||
|
||||
num := big.NewInt(int64(matrix[i][lst][0]))
|
||||
den := big.NewInt(int64(matrix[i][lst][1]))
|
||||
num.Mod(num, modulus)
|
||||
den.Mod(den, modulus)
|
||||
|
||||
coeff := big.NewInt(0).ModInverse(den, modulus)
|
||||
coeff.Mul(coeff, num).Mod(coeff, modulus)
|
||||
|
||||
shareInt := big.NewInt(0).SetBytes(share)
|
||||
shareInt.Mul(shareInt, coeff).Mod(shareInt, modulus)
|
||||
|
||||
secInt.Add(secInt, shareInt).Mod(secInt, modulus)
|
||||
}
|
||||
|
||||
return m.encode(secInt, modulus), nil
|
||||
}
|
||||
|
||||
func (m MSP) encode(x *big.Int, modulus *big.Int) (out []byte) {
|
||||
tmp := x.Bytes()
|
||||
tmpSize := len(tmp)
|
||||
|
||||
modSize := len(modulus.Bytes())
|
||||
out = make([]byte, modSize)
|
||||
|
||||
for pos := 0; pos < tmpSize; pos++ {
|
||||
out[modSize-pos-1] = tmp[tmpSize-pos-1]
|
||||
}
|
||||
|
||||
return out
|
||||
return []byte(s), nil
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ func TestMSP(t *testing.T) {
|
||||
|
||||
predicate, _ := StringToMSP("(2, (1, Alice, Bob), Carl)")
|
||||
|
||||
shares1, _ := predicate.DistributeShares(sec, Modulus(127), &db)
|
||||
shares2, _ := predicate.DistributeShares(sec, Modulus(127), &db)
|
||||
shares1, _ := predicate.DistributeShares(sec, &db)
|
||||
shares2, _ := predicate.DistributeShares(sec, &db)
|
||||
|
||||
alice := bytes.Compare(shares1["Alice"][0], shares2["Alice"][0])
|
||||
bob := bytes.Compare(shares1["Bob"][0], shares2["Bob"][0])
|
||||
@@ -56,12 +56,12 @@ func TestMSP(t *testing.T) {
|
||||
db1 := UserDatabase(Database(shares1))
|
||||
db2 := UserDatabase(Database(shares2))
|
||||
|
||||
sec1, err := predicate.RecoverSecret(Modulus(127), &db1)
|
||||
sec1, err := predicate.RecoverSecret(&db1)
|
||||
if err != nil {
|
||||
t.Fatalf("#1: %v", err)
|
||||
}
|
||||
|
||||
sec2, err := predicate.RecoverSecret(Modulus(127), &db2)
|
||||
sec2, err := predicate.RecoverSecret(&db2)
|
||||
if err != nil {
|
||||
t.Fatalf("#2: %v", err)
|
||||
}
|
||||
|
||||
116
msp/number.go
Normal file
116
msp/number.go
Normal file
@@ -0,0 +1,116 @@
|
||||
// Polynomial fields with coefficients in GF(2)
|
||||
package msp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type FieldElem []byte
|
||||
|
||||
var (
|
||||
Modulus FieldElem = []byte{135, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} // x^128 + x^7 + x^2 + x + 1
|
||||
ModulusSize int = 16
|
||||
ModulusBitSize int = 128
|
||||
|
||||
Zero FieldElem = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
One FieldElem = []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
)
|
||||
|
||||
// NewFieldElem returns a new zero element.
|
||||
func NewFieldElem() FieldElem {
|
||||
return FieldElem(make([]byte, ModulusSize))
|
||||
}
|
||||
|
||||
// AddM mutates e into e+f.
|
||||
func (e FieldElem) AddM(f FieldElem) {
|
||||
for i := 0; i < ModulusSize; i++ {
|
||||
e[i] ^= f[i]
|
||||
}
|
||||
}
|
||||
|
||||
// Add returns e+f.
|
||||
func (e FieldElem) Add(f FieldElem) FieldElem {
|
||||
out := e.Dup()
|
||||
out.AddM(f)
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Mul returns e*f.
|
||||
func (e FieldElem) Mul(f FieldElem) FieldElem {
|
||||
out := NewFieldElem()
|
||||
|
||||
for i := 0; i < ModulusBitSize; i++ { // Foreach bit e_i in e:
|
||||
if e.getCoeff(i) == 1 { // where e_i equals 1:
|
||||
temp := f.Dup() // Multiply f * x^i mod M(x):
|
||||
|
||||
for j := 0; j < i; j++ { // Multiply f by x mod M(x), i times.
|
||||
carry := temp.shift()
|
||||
|
||||
if carry {
|
||||
temp[0] ^= Modulus[0]
|
||||
}
|
||||
}
|
||||
|
||||
out.AddM(temp) // Add f * x^i to the output
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Exp returns e^i.
|
||||
func (e FieldElem) Exp(i int) FieldElem {
|
||||
out := One.Dup()
|
||||
|
||||
for j := 0; j < i; j++ {
|
||||
out = out.Mul(e)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
// Invert returns the multiplicative inverse of e.
|
||||
func (e FieldElem) Invert() FieldElem {
|
||||
out, temp := e.Dup(), e.Dup()
|
||||
|
||||
for i := 0; i < 126; i++ {
|
||||
temp = temp.Mul(temp)
|
||||
out = out.Mul(temp)
|
||||
}
|
||||
|
||||
return out.Mul(out)
|
||||
}
|
||||
|
||||
// getCoeff returns the ith coefficient of the field element: either 0 or 1.
|
||||
func (e FieldElem) getCoeff(i int) byte {
|
||||
return (e[i/8] >> (uint(i) % 8)) & 1
|
||||
}
|
||||
|
||||
// shift multiplies e by 2 and returns true if there was overflow and false if there wasn't.
|
||||
func (e FieldElem) shift() bool {
|
||||
carry := false
|
||||
|
||||
for i := 0; i < ModulusSize; i++ {
|
||||
nextCarry := e[i] >= 128
|
||||
|
||||
e[i] = e[i] << 1
|
||||
if carry {
|
||||
e[i]++
|
||||
}
|
||||
carry = nextCarry
|
||||
}
|
||||
|
||||
return carry
|
||||
}
|
||||
|
||||
func (e FieldElem) IsZero() bool { return bytes.Compare(e, Zero) == 0 }
|
||||
func (e FieldElem) IsOne() bool { return bytes.Compare(e, One) == 0 }
|
||||
|
||||
// Dup returns a duplicate of e.
|
||||
func (e FieldElem) Dup() FieldElem {
|
||||
out := FieldElem(make([]byte, ModulusSize))
|
||||
copy(out, e)
|
||||
|
||||
return out
|
||||
}
|
||||
50
msp/number_test.go
Normal file
50
msp/number_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package msp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFieldElemMultiplicationOne(t *testing.T) {
|
||||
x := FieldElem(make([]byte, ModulusSize))
|
||||
rand.Read(x)
|
||||
|
||||
xy, yx := x.Mul(One), One.Mul(x)
|
||||
|
||||
if !One.IsOne() {
|
||||
t.Fatalf("One is not one?")
|
||||
}
|
||||
|
||||
if bytes.Compare(xy, x) != 0 || bytes.Compare(yx, x) != 0 {
|
||||
t.Fatalf("Multiplication by 1 failed!\nx = %x\n1*x = %x\nx*1 = %x", x, yx, xy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldElemMultiplicationZero(t *testing.T) {
|
||||
x := FieldElem(make([]byte, ModulusSize))
|
||||
rand.Read(x)
|
||||
|
||||
xy, yx := x.Mul(Zero), Zero.Mul(x)
|
||||
|
||||
if !Zero.IsZero() {
|
||||
t.Fatalf("Zero is not zero?")
|
||||
}
|
||||
|
||||
if !xy.IsZero() || !yx.IsZero() {
|
||||
t.Fatalf("Multiplication by 0 failed!\nx = %x\n0*x = %x\nx*0 = %x", x, yx, xy)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldElemInvert(t *testing.T) {
|
||||
x := FieldElem(make([]byte, ModulusSize))
|
||||
rand.Read(x)
|
||||
|
||||
xInv := x.Invert()
|
||||
|
||||
xy, yx := x.Mul(xInv), xInv.Mul(x)
|
||||
|
||||
if !xy.IsOne() || !yx.IsOne() {
|
||||
t.Fatalf("Multiplication by inverse failed!\nx = %x\nxInv = %x\nxInv*x = %x\nx*xInv = %x", x, yx, xy)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user