github.com/cloudflare/circl@v1.5.0/abe/cpabe/tkn20/internal/tkn/matrixZp.go (about)

     1  package tkn
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  
     8  	pairing "github.com/cloudflare/circl/ecc/bls12381"
     9  	"golang.org/x/crypto/blake2b"
    10  )
    11  
    12  // matrixZp represents a matrix of mod grouporder  elements. They are stored in row-major order.
    13  // The name is a gesture toward the paper.
    14  type matrixZp struct {
    15  	rows    int
    16  	cols    int
    17  	entries []pairing.Scalar
    18  }
    19  
    20  func (m *matrixZp) marshalBinary() ([]byte, error) {
    21  	ret := make([]byte, 4+pairing.ScalarSize*m.rows*m.cols)
    22  	binary.LittleEndian.PutUint16(ret[0:], uint16(m.rows))
    23  	binary.LittleEndian.PutUint16(ret[2:], uint16(m.cols))
    24  	for i := 0; i < m.rows*m.cols; i++ {
    25  		pt, err := m.entries[i].MarshalBinary()
    26  		if err != nil {
    27  			return nil, err
    28  		}
    29  		if len(pt) != pairing.ScalarSize {
    30  			panic("matrixZp: incorrect assumption of size")
    31  		}
    32  		copy(ret[pairing.ScalarSize*i+4:], pt)
    33  	}
    34  	return ret, nil
    35  }
    36  
    37  func (m *matrixZp) unmarshalBinary(data []byte) error {
    38  	if len(data) < 4 {
    39  		return fmt.Errorf("matrixZp deserialization failure: input too short")
    40  	}
    41  	m.rows = int(binary.LittleEndian.Uint16(data[0:]))
    42  	m.cols = int(binary.LittleEndian.Uint16(data[2:]))
    43  	data = data[4:]
    44  	if len(data) != pairing.ScalarSize*m.rows*m.cols {
    45  		return fmt.Errorf("matrixZp deserialization failure: invalid entries length: expected %d, actual %d",
    46  			pairing.ScalarSize*m.cols*m.rows,
    47  			len(data))
    48  	}
    49  	m.entries = make([]pairing.Scalar, m.rows*m.cols)
    50  	var err error
    51  	for i := 0; i < m.rows*m.cols; i++ {
    52  		err = m.entries[i].UnmarshalBinary(data[pairing.ScalarSize*i : pairing.ScalarSize*(i+1)])
    53  		if err != nil {
    54  			return fmt.Errorf("matrixZp deserialization failure: error from bytes %v: %w",
    55  				data[pairing.ScalarSize*i:pairing.ScalarSize*(i+1)],
    56  				err)
    57  		}
    58  	}
    59  	return nil
    60  }
    61  
    62  // sampleDlin samples from the distribution Dk.
    63  // See section 3.2 of the paper for details.
    64  func sampleDlin(rand io.Reader) (*matrixZp, error) {
    65  	var ret matrixZp
    66  	ret.rows = 3
    67  	ret.cols = 2
    68  	ret.entries = make([]pairing.Scalar, 6)
    69  	err := ret.entries[0].Random(rand)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  	ret.entries[1].SetUint64(0)
    74  	ret.entries[2].SetUint64(0)
    75  	err = ret.entries[3].Random(rand)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	ret.entries[4].SetOne()
    80  	ret.entries[5].SetOne()
    81  
    82  	return &ret, nil
    83  }
    84  
    85  func randomMatrixZp(rand io.Reader, r int, c int) (*matrixZp, error) {
    86  	ret := newMatrixZp(r, c)
    87  	for i := 0; i < r*c; i++ {
    88  		err := ret.entries[i].Random(rand)
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  	}
    93  	return ret, nil
    94  }
    95  
    96  // We adopt the interface that math.Big uses
    97  // Receivers get set to the results of operations, and return themselves.
    98  // All aliases are allowed.
    99  
   100  // Now recall that G1, G2, GT are acted on by Zp.
   101  // So we don't have all products, just left and right with Zp.
   102  // Zp doesn't need this distinction.
   103  
   104  // Errors are signalled by returning nil, which propagates.
   105  
   106  // initialize sets up m to be r x c
   107  func (m *matrixZp) resize(r int, c int) {
   108  	if m.rows != r || m.cols != c {
   109  		m.rows = r
   110  		m.cols = c
   111  		m.entries = make([]pairing.Scalar, m.rows*m.cols)
   112  	}
   113  }
   114  
   115  // clear makes m an all 0
   116  func (m *matrixZp) clear() {
   117  	for i := 0; i < len(m.entries); i++ {
   118  		m.entries[i] = pairing.Scalar{}
   119  	}
   120  }
   121  
   122  func newMatrixZp(r int, c int) *matrixZp {
   123  	ret := new(matrixZp)
   124  	ret.resize(r, c)
   125  	ret.clear()
   126  	return ret
   127  }
   128  
   129  // eye returns the k by k identity matrix.
   130  func eye(k int) *matrixZp {
   131  	ret := newMatrixZp(k, k)
   132  	for i := 0; i < k; i++ {
   133  		ret.entries[i*k+i].SetUint64(1)
   134  	}
   135  	return ret
   136  }
   137  
   138  // conformal returns true iff m and a have the same dimensions.
   139  func (m *matrixZp) conformal(a *matrixZp) bool {
   140  	return a.rows == m.rows && a.cols == m.cols
   141  }
   142  
   143  // Equal returns true iff m == a.
   144  func (m *matrixZp) Equal(a *matrixZp) bool {
   145  	if !m.conformal(a) {
   146  		return false
   147  	}
   148  	for i := 0; i < m.rows*m.cols; i++ {
   149  		if m.entries[i].IsEqual(&a.entries[i]) == 0 {
   150  			return false
   151  		}
   152  	}
   153  	return true
   154  }
   155  
   156  // set sets m to a.
   157  func (m *matrixZp) set(a *matrixZp) {
   158  	m.resize(a.rows, a.cols)
   159  	for i := 0; i < m.rows*m.cols; i++ {
   160  		m.entries[i].Set(&a.entries[i])
   161  	}
   162  }
   163  
   164  // add sets m to a+b.
   165  func (m *matrixZp) add(a *matrixZp, b *matrixZp) {
   166  	if !a.conformal(b) {
   167  		panic(errBadMatrixSize)
   168  	}
   169  	m.resize(a.rows, a.cols)
   170  	for i := 0; i < m.rows*m.cols; i++ {
   171  		m.entries[i].Add(&a.entries[i], &b.entries[i])
   172  	}
   173  }
   174  
   175  // sub sets m to a-b.
   176  func (m *matrixZp) sub(a *matrixZp, b *matrixZp) {
   177  	if !a.conformal(b) {
   178  		panic(errBadMatrixSize)
   179  	}
   180  	m.resize(a.rows, a.cols)
   181  	for i := 0; i < m.rows*m.cols; i++ {
   182  		m.entries[i].Sub(&a.entries[i], &b.entries[i])
   183  	}
   184  }
   185  
   186  // mul sets m to a*b.
   187  func (m *matrixZp) mul(a *matrixZp, b *matrixZp) {
   188  	if a.cols != b.rows {
   189  		panic(errBadMatrixSize)
   190  	}
   191  	if m == a {
   192  		c := newMatrixZp(a.rows, a.cols)
   193  		c.set(a)
   194  		a = c
   195  	}
   196  	if m == b {
   197  		c := newMatrixZp(b.rows, b.cols)
   198  		c.set(b)
   199  		b = c
   200  	}
   201  	m.resize(a.rows, b.cols)
   202  	m.clear()
   203  	t := &pairing.Scalar{}
   204  	for i := 0; i < m.rows; i++ {
   205  		for j := 0; j < m.cols; j++ {
   206  			for k := 0; k < a.cols; k++ {
   207  				t.Mul(&a.entries[i*a.cols+k], &b.entries[k*b.cols+j])
   208  				m.entries[i*m.cols+j].Add(&m.entries[i*m.cols+j], t)
   209  			}
   210  		}
   211  	}
   212  }
   213  
   214  // transpose sets m to the transpose of a.
   215  func (m *matrixZp) transpose(a *matrixZp) {
   216  	if m == a {
   217  		c := newMatrixZp(a.rows, a.cols)
   218  		c.set(a)
   219  		a = c
   220  	}
   221  	m.resize(a.cols, a.rows)
   222  
   223  	for i := 0; i < m.rows; i++ {
   224  		for j := 0; j < m.cols; j++ {
   225  			m.entries[i*m.cols+j].Set(&a.entries[j*a.cols+i])
   226  		}
   227  	}
   228  }
   229  
   230  // swaprows swaps two rows.
   231  func (m *matrixZp) swapRows(i int, j int) {
   232  	t := &pairing.Scalar{}
   233  	for k := 0; k < m.cols; k++ {
   234  		t.Set(&m.entries[i*m.cols+k])
   235  		m.entries[i*m.cols+k].Set(&m.entries[j*m.cols+k])
   236  		m.entries[j*m.cols+k].Set(t)
   237  	}
   238  }
   239  
   240  // scalerow scales a row.
   241  func (m *matrixZp) scaleRow(alpha *pairing.Scalar, i int) {
   242  	for k := 0; k < m.cols; k++ {
   243  		m.entries[i*m.cols+k].Mul(&m.entries[i*m.cols+k], alpha)
   244  	}
   245  }
   246  
   247  // addscaledrow takes alpha * row i and adds it to row j.
   248  func (m *matrixZp) addScaledRow(alpha *pairing.Scalar, i int, j int) {
   249  	tmp := &pairing.Scalar{}
   250  	for k := 0; k < m.cols; k++ {
   251  		tmp.Mul(alpha, &m.entries[i*m.cols+k])
   252  		m.entries[j*m.cols+k].Add(tmp, &m.entries[j*m.cols+k])
   253  	}
   254  }
   255  
   256  // inverse sets m to the inverse of a. If a is not invertible,
   257  // the result is undefined and an error is returned.
   258  // Aliasing safe
   259  func (m *matrixZp) inverse(a *matrixZp) error {
   260  	if a.rows != a.cols {
   261  		panic(errBadMatrixSize)
   262  	}
   263  	// Any way we slice it we need additional storage.
   264  	y := newMatrixZp(a.rows, 2*a.cols)
   265  	for i := 0; i < a.rows; i++ {
   266  		for j := 0; j < a.cols; j++ {
   267  			y.entries[i*y.cols+j].Set(&a.entries[i*a.cols+j])
   268  		}
   269  		y.entries[i*y.cols+y.rows+i].SetUint64(1)
   270  	}
   271  
   272  	tmp := &pairing.Scalar{}
   273  	// Gaussian elimination with pivoting begins here.
   274  	for i := 0; i < y.rows; i++ {
   275  		pivoted := false
   276  	pivot:
   277  		for j := i; j < y.rows; j++ {
   278  			if y.entries[i*y.cols+j].IsZero() == 0 {
   279  				y.swapRows(i, j)
   280  				pivoted = true
   281  				break pivot
   282  			}
   283  		}
   284  		if !pivoted {
   285  			return errMatrixNonInvertible
   286  		}
   287  		tmp.Inv(&y.entries[i*y.cols+i])
   288  		y.scaleRow(tmp, i)
   289  
   290  		for j := i + 1; j < y.rows; j++ {
   291  			tmp.Set(&y.entries[j*y.cols+i])
   292  			tmp.Neg()
   293  			y.addScaledRow(tmp, i, j)
   294  		}
   295  	}
   296  	// At this point the matrix is in reduced row echelon form.
   297  	// The next step is to substitute back.
   298  
   299  	for i := y.rows - 1; i >= 0; i-- {
   300  		for j := i - 1; j >= 0; j-- {
   301  			tmp.Set(&y.entries[j*y.cols+i])
   302  			tmp.Neg()
   303  			y.addScaledRow(tmp, i, j)
   304  		}
   305  	}
   306  	m.resize(a.rows, a.cols)
   307  	for i := 0; i < m.rows; i++ {
   308  		for j := 0; j < m.cols; j++ {
   309  			m.entries[i*m.cols+j].Set(&y.entries[i*y.cols+m.cols+j])
   310  		}
   311  	}
   312  	return nil
   313  }
   314  
   315  // prf computes a prf with output in pairs of 3x2 matrices
   316  func prf(key []byte, input []byte) (*matrixZp, *matrixZp, error) {
   317  	xof, err := blake2b.NewXOF(blake2b.OutputLengthUnknown, key)
   318  	if err != nil {
   319  		return nil, nil, err
   320  	}
   321  	if _, err = xof.Write(input); err != nil {
   322  		return nil, nil, err
   323  	}
   324  	m1 := newMatrixZp(3, 2)
   325  	m2 := newMatrixZp(3, 2)
   326  	for i := 0; i < m1.rows; i++ {
   327  		for j := 0; j < m1.cols; j++ {
   328  			local := xof.Clone()
   329  			if _, err = local.Write([]byte(fmt.Sprintf("m1 matrix entry (%d, %d)", i, j))); err != nil {
   330  				return nil, nil, err
   331  			}
   332  			err = m1.entries[i*m1.cols+j].Random(local)
   333  			if err != nil {
   334  				return nil, nil, err
   335  			}
   336  			local = xof.Clone()
   337  			if _, err = local.Write([]byte(fmt.Sprintf("m2 matrix entry (%d, %d)", i, j))); err != nil {
   338  				return nil, nil, err
   339  			}
   340  			err = m2.entries[i*m2.cols+j].Random(local)
   341  			if err != nil {
   342  				return nil, nil, err
   343  			}
   344  		}
   345  	}
   346  	return m1, m2, nil
   347  }
   348  
   349  // scalarmul sets m to a matrix a*B
   350  func (m *matrixZp) scalarmul(a *pairing.Scalar, b *matrixZp) {
   351  	m.resize(b.rows, b.cols)
   352  	for i := 0; i < b.rows*b.cols; i++ {
   353  		m.entries[i].Mul(a, &b.entries[i])
   354  	}
   355  }
   356  
   357  // colsel sets m to a matrix with the selected columns.
   358  func (m *matrixZp) colsel(a *matrixZp, cols []int) {
   359  	if m == a {
   360  		c := newMatrixZp(a.rows, a.cols)
   361  		c.set(a)
   362  		a = c
   363  	}
   364  	m.resize(a.rows, len(cols))
   365  	for i := 0; i < m.rows; i++ {
   366  		for j := 0; j < m.cols; j++ {
   367  			m.entries[i*m.cols+j].Set(&a.entries[i*a.cols+cols[j]])
   368  		}
   369  	}
   370  }
   371  
   372  func (m *matrixZp) String() string {
   373  	var s string
   374  	for i := 0; i < m.rows; i++ {
   375  		for j := 0; j < m.cols; j++ {
   376  			s += fmt.Sprintf("%v ", m.entries[i*m.cols+j].String())
   377  		}
   378  		s += "\n"
   379  	}
   380  	return s
   381  }