x86_64 assembly pack: make Windows build more robust.
[openssl.git] / crypto / whrlpool / wp_dgst.c
1 /**
2  * The Whirlpool hashing function.
3  *
4  * <P>
5  * <b>References</b>
6  *
7  * <P>
8  * The Whirlpool algorithm was developed by
9  * <a href="mailto:pbarreto@scopus.com.br">Paulo S. L. M. Barreto</a> and
10  * <a href="mailto:vincent.rijmen@cryptomathic.com">Vincent Rijmen</a>.
11  *
12  * See
13  *      P.S.L.M. Barreto, V. Rijmen,
14  *      ``The Whirlpool hashing function,''
15  *      NESSIE submission, 2000 (tweaked version, 2001),
16  *      <https://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/whirlpool.zip>
17  *
18  * Based on "@version 3.0 (2003.03.12)" by Paulo S.L.M. Barreto and
19  * Vincent Rijmen. Lookup "reference implementations" on
20  * <http://planeta.terra.com.br/informatica/paulobarreto/>
21  *
22  * =============================================================================
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
25  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
34  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37
38 /*
39  * OpenSSL-specific implementation notes.
40  *
41  * WHIRLPOOL_Update as well as one-stroke WHIRLPOOL both expect
42  * number of *bytes* as input length argument. Bit-oriented routine
43  * as specified by authors is called WHIRLPOOL_BitUpdate[!] and
44  * does not have one-stroke counterpart.
45  *
46  * WHIRLPOOL_BitUpdate implements byte-oriented loop, essentially
47  * to serve WHIRLPOOL_Update. This is done for performance.
48  *
49  * Unlike authors' reference implementation, block processing
50  * routine whirlpool_block is designed to operate on multi-block
51  * input. This is done for perfomance.
52  */
53
54 #include "wp_locl.h"
55 #include <string.h>
56
57 int WHIRLPOOL_Init      (WHIRLPOOL_CTX *c)
58         {
59         memset (c,0,sizeof(*c));
60         return(1);
61         }
62
63 int WHIRLPOOL_Update    (WHIRLPOOL_CTX *c,const void *_inp,size_t bytes)
64         {
65         /* Well, largest suitable chunk size actually is
66          * (1<<(sizeof(size_t)*8-3))-64, but below number
67          * is large enough for not to care about excessive
68          * calls to WHIRLPOOL_BitUpdate... */
69         size_t chunk = ((size_t)1)<<(sizeof(size_t)*8-4);
70         const unsigned char *inp = _inp;
71
72         while (bytes>=chunk)
73                 {
74                 WHIRLPOOL_BitUpdate(c,inp,chunk*8);
75                 bytes -= chunk;
76                 inp   += chunk;
77                 }
78         if (bytes)
79                 WHIRLPOOL_BitUpdate(c,inp,bytes*8);
80
81         return(1);
82         }
83
84 void WHIRLPOOL_BitUpdate(WHIRLPOOL_CTX *c,const void *_inp,size_t bits)
85         {
86         size_t          n;
87         unsigned int    bitoff = c->bitoff,
88                         bitrem = bitoff%8,
89                         inpgap = (8-(unsigned int)bits%8)&7;
90         const unsigned char *inp=_inp;
91
92         /* This 256-bit increment procedure relies on the size_t
93          * being natural size of CPU register, so that we don't
94          * have to mask the value in order to detect overflows. */
95         c->bitlen[0] += bits;
96         if (c->bitlen[0] < bits)        /* overflow */
97                 {
98                 n = 1;
99                 do  {   c->bitlen[n]++;
100                     } while(c->bitlen[n]==0
101                             && ++n<(WHIRLPOOL_COUNTER/sizeof(size_t)));
102                 }
103
104 #ifndef OPENSSL_SMALL_FOOTPRINT
105         reconsider:
106         if (inpgap==0 && bitrem==0)     /* byte-oriented loop */
107                 {
108                 while (bits)
109                         {
110                         if (bitoff==0 && (n=bits/WHIRLPOOL_BBLOCK))
111                                 {
112                                 whirlpool_block(c,inp,n);
113                                 inp  += n*WHIRLPOOL_BBLOCK/8;
114                                 bits %= WHIRLPOOL_BBLOCK;
115                                 }
116                         else
117                                 {
118                                 unsigned int byteoff = bitoff/8;
119
120                                 bitrem = WHIRLPOOL_BBLOCK - bitoff;/* re-use bitrem */
121                                 if (bits >= bitrem)
122                                         {
123                                         bits -= bitrem;
124                                         bitrem /= 8;
125                                         memcpy(c->data+byteoff,inp,bitrem);
126                                         inp  += bitrem;
127                                         whirlpool_block(c,c->data,1);
128                                         bitoff = 0;
129                                         }
130                                 else
131                                         {
132                                         memcpy(c->data+byteoff,inp,bits/8);
133                                         bitoff += (unsigned int)bits;
134                                         bits = 0;
135                                         }
136                                 c->bitoff = bitoff;
137                                 }
138                         }
139                 }
140         else                            /* bit-oriented loop */
141 #endif
142                 {
143                 /*
144                            inp
145                            |
146                            +-------+-------+-------
147                               |||||||||||||||||||||
148                            +-------+-------+-------
149                 +-------+-------+-------+-------+-------
150                 ||||||||||||||                          c->data
151                 +-------+-------+-------+-------+-------
152                         |
153                         c->bitoff/8
154                 */
155                 while (bits)
156                         {
157                         unsigned int    byteoff = bitoff/8;
158                         unsigned char   b;
159
160 #ifndef OPENSSL_SMALL_FOOTPRINT
161                         if (bitrem==inpgap)
162                                 {
163                                 c->data[byteoff++] |= inp[0] & (0xff>>inpgap);
164                                 inpgap = 8-inpgap;
165                                 bitoff += inpgap;  bitrem = 0;  /* bitoff%8 */
166                                 bits   -= inpgap;  inpgap = 0;  /* bits%8   */
167                                 inp++;
168                                 if (bitoff==WHIRLPOOL_BBLOCK)
169                                         {
170                                         whirlpool_block(c,c->data,1);
171                                         bitoff = 0;
172                                         }
173                                 c->bitoff = bitoff;
174                                 goto reconsider;
175                                 }
176                         else
177 #endif
178                         if (bits>=8)
179                                 {
180                                 b  = ((inp[0]<<inpgap) | (inp[1]>>(8-inpgap)));
181                                 b &= 0xff;
182                                 if (bitrem)     c->data[byteoff++] |= b>>bitrem;
183                                 else            c->data[byteoff++]  = b;
184                                 bitoff += 8;
185                                 bits   -= 8;
186                                 inp++;
187                                 if (bitoff>=WHIRLPOOL_BBLOCK)
188                                         {
189                                         whirlpool_block(c,c->data,1);
190                                         byteoff  = 0;
191                                         bitoff  %= WHIRLPOOL_BBLOCK;
192                                         }
193                                 if (bitrem)     c->data[byteoff] = b<<(8-bitrem);
194                                 }
195                         else    /* remaining less than 8 bits */
196                                 {
197                                 b = (inp[0]<<inpgap)&0xff;
198                                 if (bitrem)     c->data[byteoff++] |= b>>bitrem;
199                                 else            c->data[byteoff++]  = b;
200                                 bitoff += (unsigned int)bits;
201                                 if (bitoff==WHIRLPOOL_BBLOCK)
202                                         {
203                                         whirlpool_block(c,c->data,1);
204                                         byteoff  = 0;
205                                         bitoff  %= WHIRLPOOL_BBLOCK;
206                                         }
207                                 if (bitrem)     c->data[byteoff] = b<<(8-bitrem);
208                                 bits = 0;
209                                 }
210                         c->bitoff = bitoff;
211                         }
212                 }
213         }
214
215 int WHIRLPOOL_Final     (unsigned char *md,WHIRLPOOL_CTX *c)
216         {
217         unsigned int    bitoff  = c->bitoff,
218                         byteoff = bitoff/8;
219         size_t          i,j,v;
220         unsigned char  *p;
221
222         bitoff %= 8;
223         if (bitoff)     c->data[byteoff] |= 0x80>>bitoff;
224         else            c->data[byteoff]  = 0x80;
225         byteoff++;
226
227         /* pad with zeros */
228         if (byteoff > (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER))
229                 {
230                 if (byteoff<WHIRLPOOL_BBLOCK/8)
231                         memset(&c->data[byteoff],0,WHIRLPOOL_BBLOCK/8-byteoff);
232                 whirlpool_block(c,c->data,1);
233                 byteoff = 0;
234                 }
235         if (byteoff < (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER))
236                 memset(&c->data[byteoff],0,
237                         (WHIRLPOOL_BBLOCK/8-WHIRLPOOL_COUNTER)-byteoff);
238         /* smash 256-bit c->bitlen in big-endian order */
239         p = &c->data[WHIRLPOOL_BBLOCK/8-1];     /* last byte in c->data */
240         for(i=0;i<WHIRLPOOL_COUNTER/sizeof(size_t);i++)
241                 for(v=c->bitlen[i],j=0;j<sizeof(size_t);j++,v>>=8)
242                         *p-- = (unsigned char)(v&0xff);
243
244         whirlpool_block(c,c->data,1);
245
246         if (md) {
247                 memcpy(md,c->H.c,WHIRLPOOL_DIGEST_LENGTH);
248                 memset(c,0,sizeof(*c));
249                 return(1);
250                 }
251         return(0);
252         }
253
254 unsigned char *WHIRLPOOL(const void *inp, size_t bytes,unsigned char *md)
255         {
256         WHIRLPOOL_CTX ctx;
257         static unsigned char m[WHIRLPOOL_DIGEST_LENGTH];
258
259         if (md == NULL) md=m;
260         WHIRLPOOL_Init(&ctx);
261         WHIRLPOOL_Update(&ctx,inp,bytes);
262         WHIRLPOOL_Final(md,&ctx);
263         return(md);
264         }