github.com/cloudflare/circl@v1.5.0/sign/internal/dilithium/pack.go (about) 1 package dilithium 2 3 // Sets p to the polynomial whose coefficients are less than 1024 encoded 4 // into buf (which must be of size PolyT1Size). 5 // 6 // p will be normalized. 7 func (p *Poly) UnpackT1(buf []byte) { 8 j := 0 9 for i := 0; i < PolyT1Size; i += 5 { 10 p[j] = (uint32(buf[i]) | (uint32(buf[i+1]) << 8)) & 0x3ff 11 p[j+1] = (uint32(buf[i+1]>>2) | (uint32(buf[i+2]) << 6)) & 0x3ff 12 p[j+2] = (uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4)) & 0x3ff 13 p[j+3] = (uint32(buf[i+3]>>6) | (uint32(buf[i+4]) << 2)) & 0x3ff 14 j += 4 15 } 16 } 17 18 // Writes p whose coefficients are in (-2ᵈ⁻¹, 2ᵈ⁻¹] into buf which 19 // has to be of length at least PolyT0Size. 20 // 21 // Assumes that the coefficients are not normalized, but lie in the 22 // range (q-2ᵈ⁻¹, q+2ᵈ⁻¹]. 23 func (p *Poly) PackT0(buf []byte) { 24 j := 0 25 for i := 0; i < PolyT0Size; i += 13 { 26 p0 := Q + (1 << (D - 1)) - p[j] 27 p1 := Q + (1 << (D - 1)) - p[j+1] 28 p2 := Q + (1 << (D - 1)) - p[j+2] 29 p3 := Q + (1 << (D - 1)) - p[j+3] 30 p4 := Q + (1 << (D - 1)) - p[j+4] 31 p5 := Q + (1 << (D - 1)) - p[j+5] 32 p6 := Q + (1 << (D - 1)) - p[j+6] 33 p7 := Q + (1 << (D - 1)) - p[j+7] 34 35 buf[i] = byte(p0 >> 0) 36 buf[i+1] = byte(p0>>8) | byte(p1<<5) 37 buf[i+2] = byte(p1 >> 3) 38 buf[i+3] = byte(p1>>11) | byte(p2<<2) 39 buf[i+4] = byte(p2>>6) | byte(p3<<7) 40 buf[i+5] = byte(p3 >> 1) 41 buf[i+6] = byte(p3>>9) | byte(p4<<4) 42 buf[i+7] = byte(p4 >> 4) 43 buf[i+8] = byte(p4>>12) | byte(p5<<1) 44 buf[i+9] = byte(p5>>7) | byte(p6<<6) 45 buf[i+10] = byte(p6 >> 2) 46 buf[i+11] = byte(p6>>10) | byte(p7<<3) 47 buf[i+12] = byte(p7 >> 5) 48 j += 8 49 } 50 } 51 52 // Sets p to the polynomial packed into buf by PackT0. 53 // 54 // The coefficients of p will not be normalized, but will lie 55 // in (-2ᵈ⁻¹, 2ᵈ⁻¹]. 56 func (p *Poly) UnpackT0(buf []byte) { 57 j := 0 58 for i := 0; i < PolyT0Size; i += 13 { 59 p[j] = Q + (1 << (D - 1)) - ((uint32(buf[i]) | 60 (uint32(buf[i+1]) << 8)) & 0x1fff) 61 p[j+1] = Q + (1 << (D - 1)) - (((uint32(buf[i+1]) >> 5) | 62 (uint32(buf[i+2]) << 3) | 63 (uint32(buf[i+3]) << 11)) & 0x1fff) 64 p[j+2] = Q + (1 << (D - 1)) - (((uint32(buf[i+3]) >> 2) | 65 (uint32(buf[i+4]) << 6)) & 0x1fff) 66 p[j+3] = Q + (1 << (D - 1)) - (((uint32(buf[i+4]) >> 7) | 67 (uint32(buf[i+5]) << 1) | 68 (uint32(buf[i+6]) << 9)) & 0x1fff) 69 p[j+4] = Q + (1 << (D - 1)) - (((uint32(buf[i+6]) >> 4) | 70 (uint32(buf[i+7]) << 4) | 71 (uint32(buf[i+8]) << 12)) & 0x1fff) 72 p[j+5] = Q + (1 << (D - 1)) - (((uint32(buf[i+8]) >> 1) | 73 (uint32(buf[i+9]) << 7)) & 0x1fff) 74 p[j+6] = Q + (1 << (D - 1)) - (((uint32(buf[i+9]) >> 6) | 75 (uint32(buf[i+10]) << 2) | 76 (uint32(buf[i+11]) << 10)) & 0x1fff) 77 p[j+7] = Q + (1 << (D - 1)) - ((uint32(buf[i+11]) >> 3) | 78 (uint32(buf[i+12]) << 5)) 79 80 j += 8 81 } 82 } 83 84 // Writes p whose coefficients are less than 1024 into buf, which must be 85 // of size at least PolyT1Size . 86 // 87 // Assumes coefficients of p are normalized. 88 func (p *Poly) PackT1(buf []byte) { 89 j := 0 90 for i := 0; i < PolyT1Size; i += 5 { 91 buf[i] = byte(p[j]) 92 buf[i+1] = byte(p[j]>>8) | byte(p[j+1]<<2) 93 buf[i+2] = byte(p[j+1]>>6) | byte(p[j+2]<<4) 94 buf[i+3] = byte(p[j+2]>>4) | byte(p[j+3]<<6) 95 buf[i+4] = byte(p[j+3] >> 2) 96 j += 4 97 } 98 } 99 100 // Writes p whose coefficients are in [0, 16) to buf, which must be of 101 // length N/2. 102 func (p *Poly) packLe16Generic(buf []byte) { 103 j := 0 104 for i := 0; i < PolyLe16Size; i++ { 105 buf[i] = byte(p[j]) | byte(p[j+1]<<4) 106 j += 2 107 } 108 } 109 110 // Writes p with 60 non-zero coefficients {-1,1} to buf, which must have 111 // length 40. 112 func (p *Poly) PackB60(buf []byte) { 113 // We start with a mask of the non-zero positions of p (which is 32 bytes) 114 // and then append 60 packed bits, where a one indicates a negative 115 // coefficients. 116 var signs uint64 117 mask := uint64(1) 118 for i := 0; i < 32; i++ { 119 buf[i] = 0 120 for j := 0; j < 8; j++ { 121 if p[8*i+j] != 0 { 122 buf[i] |= 1 << uint(j) 123 if p[8*i+j] == Q-1 { 124 signs |= mask 125 } 126 mask <<= 1 127 } 128 } 129 } 130 for i := uint64(0); i < 8; i++ { 131 buf[i+32] = uint8(signs >> (8 * i)) 132 } 133 } 134 135 // UnpackB60 sets p to the polynomial packed into buf with Poly.PackB60(). 136 // 137 // Returns whether unpacking was successful. 138 func (p *Poly) UnpackB60(buf []byte) bool { 139 *p = Poly{} // zero p 140 signs := (uint64(buf[32]) | (uint64(buf[33]) << 8) | 141 (uint64(buf[34]) << 16) | (uint64(buf[35]) << 24) | 142 (uint64(buf[36]) << 32) | (uint64(buf[37]) << 40) | 143 (uint64(buf[38]) << 48) | (uint64(buf[39]) << 56)) 144 if signs>>60 != 0 { 145 return false // ensure unused bits are zero for strong unforgeability 146 } 147 148 for i := 0; i < 32; i++ { 149 for j := 0; j < 8; j++ { 150 if (buf[i]>>uint(j))&1 == 1 { 151 p[8*i+j] = 1 152 // Note 1 ^ (1 | (Q-1)) = Q-1 and (-1)&x = x 153 p[8*i+j] ^= uint32(-(signs & 1)) & (1 | (Q - 1)) 154 signs >>= 1 155 } 156 } 157 } 158 159 return true 160 }