mirror of
https://github.com/cloudflare/redoctober.git
synced 2026-01-03 19:54:19 +00:00
150 lines
2.7 KiB
Go
150 lines
2.7 KiB
Go
// Package msp implements 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, fI := range f {
|
|
e[i].AddM(fI)
|
|
}
|
|
|
|
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, fJ := range f[row:] {
|
|
if !fJ[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()
|
|
}
|