github.com/cloudflare/circl@v1.5.0/abe/cpabe/tkn20/internal/tkn/matrixG1.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  )
    10  
    11  // matrixG1 represents a matrix of G1 elements. They are stored in row-major order.
    12  type matrixG1 struct {
    13  	rows    int
    14  	cols    int
    15  	entries []pairing.G1
    16  }
    17  
    18  func (m *matrixG1) marshalBinary() ([]byte, error) {
    19  	ret := make([]byte, 4+pairing.G1Size*m.rows*m.cols)
    20  	binary.LittleEndian.PutUint16(ret[0:], uint16(m.rows))
    21  	binary.LittleEndian.PutUint16(ret[2:], uint16(m.cols))
    22  	for i := 0; i < m.rows*m.cols; i++ {
    23  		pt := m.entries[i].Bytes()
    24  		if !m.entries[i].IsOnG1() {
    25  			return nil, fmt.Errorf("matrixG1: illegal serialization attempt")
    26  		}
    27  		if len(pt) != pairing.G1Size {
    28  			panic("matrixG1: incorrect assumption of size")
    29  		}
    30  		copy(ret[pairing.G1Size*i+4:], pt)
    31  	}
    32  	return ret, nil
    33  }
    34  
    35  func (m *matrixG1) unmarshalBinary(data []byte) error {
    36  	if len(data) < 4 {
    37  		return fmt.Errorf("matrixG1 deserialization failure: input too short")
    38  	}
    39  	m.rows = int(binary.LittleEndian.Uint16(data[0:]))
    40  	m.cols = int(binary.LittleEndian.Uint16(data[2:]))
    41  	data = data[4:]
    42  	if len(data) != pairing.G1Size*m.rows*m.cols {
    43  		return fmt.Errorf("matrixG1 deserialization failure: invalid entries length: expected %d, actual %d",
    44  			pairing.G1Size*m.cols*m.rows,
    45  			len(data))
    46  	}
    47  	m.entries = make([]pairing.G1, m.rows*m.cols)
    48  	var err error
    49  	for i := 0; i < m.rows*m.cols; i++ {
    50  		err = m.entries[i].SetBytes(data[pairing.G1Size*i : pairing.G1Size*(i+1)])
    51  		if err != nil {
    52  			return fmt.Errorf("matrixG1 deserialization failure: error from bytes %v: %w",
    53  				data[pairing.G1Size*i:pairing.G1Size*(i+1)],
    54  				err)
    55  		}
    56  	}
    57  	return nil
    58  }
    59  
    60  // We write addition for each of these, multiplication by scalars, and action on both
    61  // sides?
    62  
    63  // exp computes the naive matrix exponential of a with respect to the basepoint.
    64  func (m *matrixG1) exp(a *matrixZp) {
    65  	basepoint := pairing.G1Generator()
    66  	m.resize(a.rows, a.cols)
    67  	for i := 0; i < m.rows*m.cols; i++ {
    68  		m.entries[i].ScalarMult(&a.entries[i], basepoint)
    69  	}
    70  }
    71  
    72  // resize only changes the matrix if we have to
    73  func (m *matrixG1) resize(r int, c int) {
    74  	if m.rows != r || m.cols != c {
    75  		m.rows = r
    76  		m.cols = c
    77  		m.entries = make([]pairing.G1, m.rows*m.cols)
    78  	}
    79  }
    80  
    81  // clear sets a matrix to the all zero matrix
    82  func (m *matrixG1) clear() {
    83  	for i := 0; i < len(m.entries); i++ {
    84  		m.entries[i].SetIdentity()
    85  	}
    86  }
    87  
    88  // conformal returns true iff m and a have the same dimensions.
    89  func (m *matrixG1) conformal(a *matrixG1) bool {
    90  	return a.rows == m.rows && a.cols == m.cols
    91  }
    92  
    93  // Equal returns true if m == b.
    94  func (m *matrixG1) Equal(b *matrixG1) bool {
    95  	if !m.conformal(b) {
    96  		return false
    97  	}
    98  	for i := 0; i < m.rows; i++ {
    99  		for j := 0; j < m.cols; j++ {
   100  			if !m.entries[i*m.cols+j].IsEqual(&b.entries[i*b.cols+j]) {
   101  				return false
   102  			}
   103  		}
   104  	}
   105  	return true
   106  }
   107  
   108  // set sets m to a.
   109  func (m *matrixG1) set(a *matrixG1) {
   110  	m.resize(a.rows, a.cols)
   111  	for i := 0; i < m.rows*m.cols; i++ {
   112  		m.entries[i] = a.entries[i]
   113  	}
   114  }
   115  
   116  // add sets m to a+b.
   117  func (m *matrixG1) add(a *matrixG1, b *matrixG1) {
   118  	if !a.conformal(b) {
   119  		panic(errBadMatrixSize)
   120  	}
   121  	m.resize(a.rows, a.cols)
   122  	for i := 0; i < m.rows*m.cols; i++ {
   123  		m.entries[i].Add(&a.entries[i], &b.entries[i])
   124  	}
   125  }
   126  
   127  // sub sets m to a-b.
   128  func (m *matrixG1) sub(a *matrixG1, b *matrixG1) {
   129  	if !a.conformal(b) {
   130  		panic(errBadMatrixSize)
   131  	}
   132  	m.resize(a.rows, a.cols)
   133  	for i := 0; i < m.rows*m.cols; i++ {
   134  		t := b.entries[i]
   135  		t.Neg()
   136  		m.entries[i].Add(&a.entries[i], &t)
   137  	}
   138  }
   139  
   140  // leftMult multiples a*b with a matrixZp, b matrixG1.
   141  func (m *matrixG1) leftMult(a *matrixZp, b *matrixG1) {
   142  	if a.cols != b.rows {
   143  		panic(errBadMatrixSize)
   144  	}
   145  	if b == m {
   146  		c := newMatrixG1(0, 0)
   147  		c.set(b)
   148  		b = c
   149  	}
   150  	m.resize(a.rows, b.cols)
   151  	m.clear()
   152  	var t pairing.G1
   153  	t.SetIdentity()
   154  	for i := 0; i < m.rows; i++ {
   155  		for j := 0; j < m.cols; j++ {
   156  			for k := 0; k < a.cols; k++ {
   157  				t.ScalarMult(&a.entries[i*a.cols+k], &b.entries[k*b.cols+j])
   158  				m.entries[i*m.cols+j].Add(&m.entries[i*m.cols+j], &t)
   159  			}
   160  		}
   161  	}
   162  }
   163  
   164  // rightMult multiplies a*b with a matrixG1, b matrixZp.
   165  func (m *matrixG1) rightMult(a *matrixG1, b *matrixZp) {
   166  	if a.cols != b.rows {
   167  		panic(errBadMatrixSize)
   168  	}
   169  	if a == m {
   170  		c := newMatrixG1(0, 0)
   171  		c.set(a)
   172  		a = c
   173  	}
   174  	m.resize(a.rows, b.cols)
   175  	m.clear()
   176  	var t pairing.G1
   177  	t.SetIdentity()
   178  	for i := 0; i < m.rows; i++ {
   179  		for j := 0; j < m.cols; j++ {
   180  			for k := 0; k < a.cols; k++ {
   181  				t.ScalarMult(&b.entries[k*b.cols+j], &a.entries[i*a.cols+k])
   182  				m.entries[i*m.cols+j].Add(&m.entries[i*m.cols+j], &t)
   183  			}
   184  		}
   185  	}
   186  }
   187  
   188  // scalarMult sets m to c*a where c is a Scalar,
   189  func (m *matrixG1) scalarMult(c *pairing.Scalar, a *matrixG1) {
   190  	m.resize(a.rows, a.cols)
   191  	for i := 0; i < len(a.entries); i++ {
   192  		m.entries[i].ScalarMult(c, &a.entries[i])
   193  	}
   194  }
   195  
   196  // copy creates and returns a new matrix that shares no storage with m
   197  func (m *matrixG1) copy() *matrixG1 {
   198  	ret := new(matrixG1)
   199  	ret.resize(m.rows, m.cols)
   200  	for i := 0; i < m.rows*m.cols; i++ {
   201  		ret.entries[i] = m.entries[i]
   202  	}
   203  	return ret
   204  }
   205  
   206  func newMatrixG1(r int, c int) *matrixG1 {
   207  	ret := new(matrixG1)
   208  	ret.resize(r, c)
   209  	ret.clear()
   210  	return ret
   211  }
   212  
   213  func randomMatrixG1(rand io.Reader, r int, c int) (*matrixG1, error) {
   214  	a, err := randomMatrixZp(rand, r, c)
   215  	if err != nil {
   216  		return nil, err
   217  	}
   218  	ret := newMatrixG1(r, c)
   219  	ret.exp(a)
   220  	return ret, nil
   221  }
   222  
   223  // oracle generates 3x2 matrices via the random oracle
   224  func oracle(input []byte) (*matrixG1, *matrixG1) {
   225  	a := newMatrixG1(3, 2)
   226  	b := newMatrixG1(3, 2)
   227  	for i := 0; i < 3; i++ {
   228  		for j := 0; j < 2; j++ {
   229  			a.entries[i*a.cols+j].Hash(input, []byte(fmt.Sprintf("a matrix entry [%d, %d]", i, j)))
   230  			b.entries[i*b.cols+j].Hash(input, []byte(fmt.Sprintf("b matrix entry [%d, %d]", i, j)))
   231  		}
   232  	}
   233  	return a, b
   234  }
   235  
   236  // transpose sets m to the transpose of a.
   237  // Not aliasing safe
   238  func (m *matrixG1) transpose(a *matrixG1) {
   239  	if m == a {
   240  		c := newMatrixG1(0, 0)
   241  		c.set(a)
   242  		a = c
   243  	}
   244  	m.resize(a.cols, a.rows)
   245  
   246  	for i := 0; i < m.rows; i++ {
   247  		for j := 0; j < m.cols; j++ {
   248  			m.entries[i*m.cols+j] = a.entries[j*a.cols+i]
   249  		}
   250  	}
   251  }