github.com/cloudflare/circl@v1.5.0/sign/dilithium/mode5/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  }