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 }