package gnarl // Exponentiation routines for torus matrices (tmat) and full matrices (mat4). // // Fixed-base exponentiation uses a precomputed table for the Schnorr generator. // 54 windows of 4 bits each (ceil(213/4) = 54 for the ~213-bit scalar Q). // // Variable-base uses square-and-multiply. // Shamir's trick computes G^a * PK^b in one pass for verification. // genTable holds precomputed multiples of the Schnorr generator. // genTable[i][j] = SchnorrGen^(j * 2^(4*i)) for j = 0..15, i = 0..53. var genTable [54][16]tmat var genTableReady bool // initGenTable precomputes the fixed-base table for SchnorrGen. func initGenTable(g *tmat) { if genTableReady { return } genTable[0][0] = tmEye() genTable[0][1] = *g for j := 2; j < 16; j++ { tmMul(&genTable[0][j], &genTable[0][j-1], g) } for i := 1; i < 54; i++ { var base tmat tmSquare(&base, &genTable[i-1][1]) tmSquare(&base, &base) tmSquare(&base, &base) tmSquare(&base, &base) genTable[i][0] = tmEye() genTable[i][1] = base for j := 2; j < 16; j++ { tmMul(&genTable[i][j], &genTable[i][j-1], &base) } } genTableReady = true } // tmFixedExp computes r = SchnorrGen^s using the precomputed table. // Processes 54 4-bit windows covering the ~213-bit scalar. func tmFixedExp(r *tmat, s *scalar) { *r = tmEye() for i := 0; i < 54; i++ { limb := i / 16 bit := uint((i % 16) * 4) nib := int((s[limb] >> bit) & 0xF) if nib != 0 { tmMul(r, r, &genTable[i][nib]) } } } // tmVarExp computes r = base^s for a variable torus matrix. func tmVarExp(r *tmat, base *tmat, s *scalar) { *r = tmEye() var b tmat b = *base for i := 0; i < 4; i++ { word := s[i] for bit := 0; bit < 64; bit++ { if word&1 == 1 { tmMul(r, r, &b) } tmSquare(&b, &b) word >>= 1 } } } // tmShamirExp computes r = G^a * PK^b where G is the fixed SchnorrGen // and PK is a variable torus matrix. // // Uses separate 4-bit windows with Horner's method (top-down). func tmShamirExp(r *tmat, a *scalar, pk *tmat, b *scalar) { var pkTab [16]tmat pkTab[0] = tmEye() pkTab[1] = *pk for j := 2; j < 16; j++ { tmMul(&pkTab[j], &pkTab[j-1], pk) } *r = tmEye() for i := 53; i >= 0; i-- { tmSquare(r, r) tmSquare(r, r) tmSquare(r, r) tmSquare(r, r) limb := i / 16 bit := uint((i % 16) * 4) nibA := int((a[limb] >> bit) & 0xF) nibB := int((b[limb] >> bit) & 0xF) if nibA != 0 { tmMul(r, r, &genTable[0][nibA]) } if nibB != 0 { tmMul(r, r, &pkTab[nibB]) } } }