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 }