github.com/cloudflare/circl@v1.5.0/sign/mldsa/mldsa44/internal/pack.go (about) 1 // Code generated from mode3/internal/pack.go by gen.go 2 3 package internal 4 5 import ( 6 common "github.com/cloudflare/circl/sign/internal/dilithium" 7 ) 8 9 // Writes p with norm less than or equal η into buf, which must be of 10 // size PolyLeqEtaSize. 11 // 12 // Assumes coefficients of p are not normalized, but in [q-η,q+η]. 13 func PolyPackLeqEta(p *common.Poly, buf []byte) { 14 if DoubleEtaBits == 4 { // compiler eliminates branch 15 j := 0 16 for i := 0; i < PolyLeqEtaSize; i++ { 17 buf[i] = (byte(common.Q+Eta-p[j]) | 18 byte(common.Q+Eta-p[j+1])<<4) 19 j += 2 20 } 21 } else if DoubleEtaBits == 3 { 22 j := 0 23 for i := 0; i < PolyLeqEtaSize; i += 3 { 24 buf[i] = (byte(common.Q+Eta-p[j]) | 25 (byte(common.Q+Eta-p[j+1]) << 3) | 26 (byte(common.Q+Eta-p[j+2]) << 6)) 27 buf[i+1] = ((byte(common.Q+Eta-p[j+2]) >> 2) | 28 (byte(common.Q+Eta-p[j+3]) << 1) | 29 (byte(common.Q+Eta-p[j+4]) << 4) | 30 (byte(common.Q+Eta-p[j+5]) << 7)) 31 buf[i+2] = ((byte(common.Q+Eta-p[j+5]) >> 1) | 32 (byte(common.Q+Eta-p[j+6]) << 2) | 33 (byte(common.Q+Eta-p[j+7]) << 5)) 34 j += 8 35 } 36 } else { 37 panic("eta not supported") 38 } 39 } 40 41 // Sets p to the polynomial of norm less than or equal η encoded in the 42 // given buffer of size PolyLeqEtaSize. 43 // 44 // Output coefficients of p are not normalized, but in [q-η,q+η] provided 45 // buf was created using PackLeqEta. 46 // 47 // Beware, for arbitrary buf the coefficients of p might end up in 48 // the interval [q-2^b,q+2^b] where b is the least b with η≤2^b. 49 func PolyUnpackLeqEta(p *common.Poly, buf []byte) { 50 if DoubleEtaBits == 4 { // compiler eliminates branch 51 j := 0 52 for i := 0; i < PolyLeqEtaSize; i++ { 53 p[j] = common.Q + Eta - uint32(buf[i]&15) 54 p[j+1] = common.Q + Eta - uint32(buf[i]>>4) 55 j += 2 56 } 57 } else if DoubleEtaBits == 3 { 58 j := 0 59 for i := 0; i < PolyLeqEtaSize; i += 3 { 60 p[j] = common.Q + Eta - uint32(buf[i]&7) 61 p[j+1] = common.Q + Eta - uint32((buf[i]>>3)&7) 62 p[j+2] = common.Q + Eta - uint32((buf[i]>>6)|((buf[i+1]<<2)&7)) 63 p[j+3] = common.Q + Eta - uint32((buf[i+1]>>1)&7) 64 p[j+4] = common.Q + Eta - uint32((buf[i+1]>>4)&7) 65 p[j+5] = common.Q + Eta - uint32((buf[i+1]>>7)|((buf[i+2]<<1)&7)) 66 p[j+6] = common.Q + Eta - uint32((buf[i+2]>>2)&7) 67 p[j+7] = common.Q + Eta - uint32((buf[i+2]>>5)&7) 68 j += 8 69 } 70 } else { 71 panic("eta not supported") 72 } 73 } 74 75 // Writes v with coefficients in {0, 1} of which at most ω non-zero 76 // to buf, which must have length ω+k. 77 func (v *VecK) PackHint(buf []byte) { 78 // The packed hint starts with the indices of the non-zero coefficients 79 // For instance: 80 // 81 // (x⁵⁶ + x¹⁰⁰, x²⁵⁵, 0, x² + x²³, x¹) 82 // 83 // Yields 84 // 85 // 56, 100, 255, 2, 23, 1 86 // 87 // Then we pad with zeroes until we have a list of ω items: 88 // // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0 89 // 90 // Then we finish with a list of the switch-over-indices in this 91 // list between polynomials, so: 92 // 93 // 56, 100, 255, 2, 23, 1, 0, 0, ..., 0, 2, 3, 3, 5, 6 94 95 off := uint8(0) 96 for i := 0; i < K; i++ { 97 for j := uint16(0); j < common.N; j++ { 98 if v[i][j] != 0 { 99 buf[off] = uint8(j) 100 off++ 101 } 102 } 103 buf[Omega+i] = off 104 } 105 for ; off < Omega; off++ { 106 buf[off] = 0 107 } 108 } 109 110 // Sets v to the vector encoded using VecK.PackHint() 111 // 112 // Returns whether unpacking was successful. 113 func (v *VecK) UnpackHint(buf []byte) bool { 114 // A priori, there would be several reasonable ways to encode the same 115 // hint vector. We take care to only allow only one encoding, to ensure 116 // "strong unforgeability". 117 // 118 // See PackHint() source for description of the encoding. 119 *v = VecK{} // zero v 120 prevSOP := uint8(0) // previous switch-over-point 121 for i := 0; i < K; i++ { 122 SOP := buf[Omega+i] 123 if SOP < prevSOP || SOP > Omega { 124 return false // ensures switch-over-points are increasing 125 } 126 for j := prevSOP; j < SOP; j++ { 127 if j > prevSOP && buf[j] <= buf[j-1] { 128 return false // ensures indices are increasing (within a poly) 129 } 130 v[i][buf[j]] = 1 131 } 132 prevSOP = SOP 133 } 134 for j := prevSOP; j < Omega; j++ { 135 if buf[j] != 0 { 136 return false // ensures padding indices are zero 137 } 138 } 139 140 return true 141 } 142 143 // Sets p to the polynomial packed into buf by PolyPackLeGamma1. 144 // 145 // p will be normalized. 146 func PolyUnpackLeGamma1(p *common.Poly, buf []byte) { 147 if Gamma1Bits == 17 { 148 j := 0 149 for i := 0; i < PolyLeGamma1Size; i += 9 { 150 p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | 151 (uint32(buf[i+2]&0x3) << 16) 152 p1 := uint32(buf[i+2]>>2) | (uint32(buf[i+3]) << 6) | 153 (uint32(buf[i+4]&0xf) << 14) 154 p2 := uint32(buf[i+4]>>4) | (uint32(buf[i+5]) << 4) | 155 (uint32(buf[i+6]&0x3f) << 12) 156 p3 := uint32(buf[i+6]>>6) | (uint32(buf[i+7]) << 2) | 157 (uint32(buf[i+8]) << 10) 158 159 // coefficients in [0,…,2γ₁) 160 p0 = Gamma1 - p0 // (-γ₁,…,γ₁] 161 p1 = Gamma1 - p1 162 p2 = Gamma1 - p2 163 p3 = Gamma1 - p3 164 165 p0 += uint32(int32(p0)>>31) & common.Q // normalize 166 p1 += uint32(int32(p1)>>31) & common.Q 167 p2 += uint32(int32(p2)>>31) & common.Q 168 p3 += uint32(int32(p3)>>31) & common.Q 169 170 p[j] = p0 171 p[j+1] = p1 172 p[j+2] = p2 173 p[j+3] = p3 174 175 j += 4 176 } 177 } else if Gamma1Bits == 19 { 178 j := 0 179 for i := 0; i < PolyLeGamma1Size; i += 5 { 180 p0 := uint32(buf[i]) | (uint32(buf[i+1]) << 8) | 181 (uint32(buf[i+2]&0xf) << 16) 182 p1 := uint32(buf[i+2]>>4) | (uint32(buf[i+3]) << 4) | 183 (uint32(buf[i+4]) << 12) 184 185 p0 = Gamma1 - p0 186 p1 = Gamma1 - p1 187 188 p0 += uint32(int32(p0)>>31) & common.Q 189 p1 += uint32(int32(p1)>>31) & common.Q 190 191 p[j] = p0 192 p[j+1] = p1 193 194 j += 2 195 } 196 } else { 197 panic("γ₁ not supported") 198 } 199 } 200 201 // Writes p whose coefficients are in (-γ₁,γ₁] into buf 202 // which has to be of length PolyLeGamma1Size. 203 // 204 // Assumes p is normalized. 205 func PolyPackLeGamma1(p *common.Poly, buf []byte) { 206 if Gamma1Bits == 17 { 207 j := 0 208 // coefficients in [0,…,γ₁] ∪ (q-γ₁,…,q) 209 for i := 0; i < PolyLeGamma1Size; i += 9 { 210 p0 := Gamma1 - p[j] // [0,…,γ₁] ∪ (γ₁-q,…,2γ₁-q) 211 p0 += uint32(int32(p0)>>31) & common.Q // [0,…,2γ₁) 212 p1 := Gamma1 - p[j+1] 213 p1 += uint32(int32(p1)>>31) & common.Q 214 p2 := Gamma1 - p[j+2] 215 p2 += uint32(int32(p2)>>31) & common.Q 216 p3 := Gamma1 - p[j+3] 217 p3 += uint32(int32(p3)>>31) & common.Q 218 219 buf[i+0] = byte(p0) 220 buf[i+1] = byte(p0 >> 8) 221 buf[i+2] = byte(p0>>16) | byte(p1<<2) 222 buf[i+3] = byte(p1 >> 6) 223 buf[i+4] = byte(p1>>14) | byte(p2<<4) 224 buf[i+5] = byte(p2 >> 4) 225 buf[i+6] = byte(p2>>12) | byte(p3<<6) 226 buf[i+7] = byte(p3 >> 2) 227 buf[i+8] = byte(p3 >> 10) 228 229 j += 4 230 } 231 } else if Gamma1Bits == 19 { 232 j := 0 233 for i := 0; i < PolyLeGamma1Size; i += 5 { 234 // Coefficients are in [0, γ₁] ∪ (Q-γ₁, Q) 235 p0 := Gamma1 - p[j] 236 p0 += uint32(int32(p0)>>31) & common.Q 237 p1 := Gamma1 - p[j+1] 238 p1 += uint32(int32(p1)>>31) & common.Q 239 240 buf[i+0] = byte(p0) 241 buf[i+1] = byte(p0 >> 8) 242 buf[i+2] = byte(p0>>16) | byte(p1<<4) 243 buf[i+3] = byte(p1 >> 4) 244 buf[i+4] = byte(p1 >> 12) 245 246 j += 2 247 } 248 } else { 249 panic("γ₁ not supported") 250 } 251 } 252 253 // Pack w₁ into buf, which must be of length PolyW1Size. 254 // 255 // Assumes w₁ is normalized. 256 func PolyPackW1(p *common.Poly, buf []byte) { 257 if Gamma1Bits == 19 { 258 p.PackLe16(buf) 259 } else if Gamma1Bits == 17 { 260 j := 0 261 for i := 0; i < PolyW1Size; i += 3 { 262 buf[i] = byte(p[j]) | byte(p[j+1]<<6) 263 buf[i+1] = byte(p[j+1]>>2) | byte(p[j+2]<<4) 264 buf[i+2] = byte(p[j+2]>>4) | byte(p[j+3]<<2) 265 j += 4 266 } 267 } else { 268 panic("unsupported γ₁") 269 } 270 }