1085658deSDaniel Fojt /*
2085658deSDaniel Fojt    BLAKE2 reference source code package - reference C implementations
3085658deSDaniel Fojt 
4085658deSDaniel Fojt    Copyright 2012, Samuel Neves <sneves@dei.uc.pt>.  You may use this under the
5085658deSDaniel Fojt    terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
6085658deSDaniel Fojt    your option.  The terms of these licenses can be found at:
7085658deSDaniel Fojt 
8085658deSDaniel Fojt    - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
9085658deSDaniel Fojt    - OpenSSL license   : https://www.openssl.org/source/license.html
10085658deSDaniel Fojt    - Apache 2.0        : http://www.apache.org/licenses/LICENSE-2.0
11085658deSDaniel Fojt 
12085658deSDaniel Fojt    More information about the BLAKE2 hash function can be found at
13085658deSDaniel Fojt    https://blake2.net.
14085658deSDaniel Fojt */
15085658deSDaniel Fojt 
16*50f8aa9cSAntonio Huete Jimenez #include "archive_platform.h"
17*50f8aa9cSAntonio Huete Jimenez 
18085658deSDaniel Fojt #include <stdlib.h>
19085658deSDaniel Fojt #include <string.h>
20085658deSDaniel Fojt #include <stdio.h>
21085658deSDaniel Fojt 
22085658deSDaniel Fojt #if defined(_OPENMP)
23085658deSDaniel Fojt #include <omp.h>
24085658deSDaniel Fojt #endif
25085658deSDaniel Fojt 
26085658deSDaniel Fojt #include "archive_blake2.h"
27085658deSDaniel Fojt #include "archive_blake2_impl.h"
28085658deSDaniel Fojt 
29085658deSDaniel Fojt #define PARALLELISM_DEGREE 8
30085658deSDaniel Fojt 
31085658deSDaniel Fojt /*
32085658deSDaniel Fojt   blake2sp_init_param defaults to setting the expecting output length
33085658deSDaniel Fojt   from the digest_length parameter block field.
34085658deSDaniel Fojt 
35085658deSDaniel Fojt   In some cases, however, we do not want this, as the output length
36085658deSDaniel Fojt   of these instances is given by inner_length instead.
37085658deSDaniel Fojt */
blake2sp_init_leaf_param(blake2s_state * S,const blake2s_param * P)38085658deSDaniel Fojt static int blake2sp_init_leaf_param( blake2s_state *S, const blake2s_param *P )
39085658deSDaniel Fojt {
40085658deSDaniel Fojt   int err = blake2s_init_param(S, P);
41085658deSDaniel Fojt   S->outlen = P->inner_length;
42085658deSDaniel Fojt   return err;
43085658deSDaniel Fojt }
44085658deSDaniel Fojt 
blake2sp_init_leaf(blake2s_state * S,size_t outlen,size_t keylen,uint32_t offset)45085658deSDaniel Fojt static int blake2sp_init_leaf( blake2s_state *S, size_t outlen, size_t keylen, uint32_t offset )
46085658deSDaniel Fojt {
47085658deSDaniel Fojt   blake2s_param P[1];
48085658deSDaniel Fojt   P->digest_length = (uint8_t)outlen;
49085658deSDaniel Fojt   P->key_length = (uint8_t)keylen;
50085658deSDaniel Fojt   P->fanout = PARALLELISM_DEGREE;
51085658deSDaniel Fojt   P->depth = 2;
52085658deSDaniel Fojt   store32( &P->leaf_length, 0 );
53085658deSDaniel Fojt   store32( &P->node_offset, offset );
54085658deSDaniel Fojt   store16( &P->xof_length, 0 );
55085658deSDaniel Fojt   P->node_depth = 0;
56085658deSDaniel Fojt   P->inner_length = BLAKE2S_OUTBYTES;
57085658deSDaniel Fojt   memset( P->salt, 0, sizeof( P->salt ) );
58085658deSDaniel Fojt   memset( P->personal, 0, sizeof( P->personal ) );
59085658deSDaniel Fojt   return blake2sp_init_leaf_param( S, P );
60085658deSDaniel Fojt }
61085658deSDaniel Fojt 
blake2sp_init_root(blake2s_state * S,size_t outlen,size_t keylen)62085658deSDaniel Fojt static int blake2sp_init_root( blake2s_state *S, size_t outlen, size_t keylen )
63085658deSDaniel Fojt {
64085658deSDaniel Fojt   blake2s_param P[1];
65085658deSDaniel Fojt   P->digest_length = (uint8_t)outlen;
66085658deSDaniel Fojt   P->key_length = (uint8_t)keylen;
67085658deSDaniel Fojt   P->fanout = PARALLELISM_DEGREE;
68085658deSDaniel Fojt   P->depth = 2;
69085658deSDaniel Fojt   store32( &P->leaf_length, 0 );
70085658deSDaniel Fojt   store32( &P->node_offset, 0 );
71085658deSDaniel Fojt   store16( &P->xof_length, 0 );
72085658deSDaniel Fojt   P->node_depth = 1;
73085658deSDaniel Fojt   P->inner_length = BLAKE2S_OUTBYTES;
74085658deSDaniel Fojt   memset( P->salt, 0, sizeof( P->salt ) );
75085658deSDaniel Fojt   memset( P->personal, 0, sizeof( P->personal ) );
76085658deSDaniel Fojt   return blake2s_init_param( S, P );
77085658deSDaniel Fojt }
78085658deSDaniel Fojt 
79085658deSDaniel Fojt 
blake2sp_init(blake2sp_state * S,size_t outlen)80085658deSDaniel Fojt int blake2sp_init( blake2sp_state *S, size_t outlen )
81085658deSDaniel Fojt {
82085658deSDaniel Fojt   size_t i;
83085658deSDaniel Fojt 
84085658deSDaniel Fojt   if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
85085658deSDaniel Fojt 
86085658deSDaniel Fojt   memset( S->buf, 0, sizeof( S->buf ) );
87085658deSDaniel Fojt   S->buflen = 0;
88085658deSDaniel Fojt   S->outlen = outlen;
89085658deSDaniel Fojt 
90085658deSDaniel Fojt   if( blake2sp_init_root( S->R, outlen, 0 ) < 0 )
91085658deSDaniel Fojt     return -1;
92085658deSDaniel Fojt 
93085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
94085658deSDaniel Fojt     if( blake2sp_init_leaf( S->S[i], outlen, 0, (uint32_t)i ) < 0 ) return -1;
95085658deSDaniel Fojt 
96085658deSDaniel Fojt   S->R->last_node = 1;
97085658deSDaniel Fojt   S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
98085658deSDaniel Fojt   return 0;
99085658deSDaniel Fojt }
100085658deSDaniel Fojt 
blake2sp_init_key(blake2sp_state * S,size_t outlen,const void * key,size_t keylen)101085658deSDaniel Fojt int blake2sp_init_key( blake2sp_state *S, size_t outlen, const void *key, size_t keylen )
102085658deSDaniel Fojt {
103085658deSDaniel Fojt   size_t i;
104085658deSDaniel Fojt 
105085658deSDaniel Fojt   if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
106085658deSDaniel Fojt 
107085658deSDaniel Fojt   if( !key || !keylen || keylen > BLAKE2S_KEYBYTES ) return -1;
108085658deSDaniel Fojt 
109085658deSDaniel Fojt   memset( S->buf, 0, sizeof( S->buf ) );
110085658deSDaniel Fojt   S->buflen = 0;
111085658deSDaniel Fojt   S->outlen = outlen;
112085658deSDaniel Fojt 
113085658deSDaniel Fojt   if( blake2sp_init_root( S->R, outlen, keylen ) < 0 )
114085658deSDaniel Fojt     return -1;
115085658deSDaniel Fojt 
116085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
117085658deSDaniel Fojt     if( blake2sp_init_leaf( S->S[i], outlen, keylen, (uint32_t)i ) < 0 ) return -1;
118085658deSDaniel Fojt 
119085658deSDaniel Fojt   S->R->last_node = 1;
120085658deSDaniel Fojt   S->S[PARALLELISM_DEGREE - 1]->last_node = 1;
121085658deSDaniel Fojt   {
122085658deSDaniel Fojt     uint8_t block[BLAKE2S_BLOCKBYTES];
123085658deSDaniel Fojt     memset( block, 0, BLAKE2S_BLOCKBYTES );
124085658deSDaniel Fojt     memcpy( block, key, keylen );
125085658deSDaniel Fojt 
126085658deSDaniel Fojt     for( i = 0; i < PARALLELISM_DEGREE; ++i )
127085658deSDaniel Fojt       blake2s_update( S->S[i], block, BLAKE2S_BLOCKBYTES );
128085658deSDaniel Fojt 
129085658deSDaniel Fojt     secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
130085658deSDaniel Fojt   }
131085658deSDaniel Fojt   return 0;
132085658deSDaniel Fojt }
133085658deSDaniel Fojt 
134085658deSDaniel Fojt 
blake2sp_update(blake2sp_state * S,const void * pin,size_t inlen)135085658deSDaniel Fojt int blake2sp_update( blake2sp_state *S, const void *pin, size_t inlen )
136085658deSDaniel Fojt {
137085658deSDaniel Fojt   const unsigned char * in = (const unsigned char *)pin;
138085658deSDaniel Fojt   size_t left = S->buflen;
139085658deSDaniel Fojt   size_t fill = sizeof( S->buf ) - left;
140085658deSDaniel Fojt   size_t i;
141085658deSDaniel Fojt 
142085658deSDaniel Fojt   if( left && inlen >= fill )
143085658deSDaniel Fojt   {
144085658deSDaniel Fojt     memcpy( S->buf + left, in, fill );
145085658deSDaniel Fojt 
146085658deSDaniel Fojt     for( i = 0; i < PARALLELISM_DEGREE; ++i )
147085658deSDaniel Fojt       blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES );
148085658deSDaniel Fojt 
149085658deSDaniel Fojt     in += fill;
150085658deSDaniel Fojt     inlen -= fill;
151085658deSDaniel Fojt     left = 0;
152085658deSDaniel Fojt   }
153085658deSDaniel Fojt 
154085658deSDaniel Fojt #if defined(_OPENMP)
155085658deSDaniel Fojt   #pragma omp parallel shared(S), num_threads(PARALLELISM_DEGREE)
156085658deSDaniel Fojt #else
157085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
158085658deSDaniel Fojt #endif
159085658deSDaniel Fojt   {
160085658deSDaniel Fojt #if defined(_OPENMP)
161085658deSDaniel Fojt     size_t      i = omp_get_thread_num();
162085658deSDaniel Fojt #endif
163085658deSDaniel Fojt     size_t inlen__ = inlen;
164085658deSDaniel Fojt     const unsigned char *in__ = ( const unsigned char * )in;
165085658deSDaniel Fojt     in__ += i * BLAKE2S_BLOCKBYTES;
166085658deSDaniel Fojt 
167085658deSDaniel Fojt     while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
168085658deSDaniel Fojt     {
169085658deSDaniel Fojt       blake2s_update( S->S[i], in__, BLAKE2S_BLOCKBYTES );
170085658deSDaniel Fojt       in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
171085658deSDaniel Fojt       inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
172085658deSDaniel Fojt     }
173085658deSDaniel Fojt   }
174085658deSDaniel Fojt 
175085658deSDaniel Fojt   in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES );
176085658deSDaniel Fojt   inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
177085658deSDaniel Fojt 
178085658deSDaniel Fojt   if( inlen > 0 )
179085658deSDaniel Fojt     memcpy( S->buf + left, in, inlen );
180085658deSDaniel Fojt 
181085658deSDaniel Fojt   S->buflen = left + inlen;
182085658deSDaniel Fojt   return 0;
183085658deSDaniel Fojt }
184085658deSDaniel Fojt 
185085658deSDaniel Fojt 
blake2sp_final(blake2sp_state * S,void * out,size_t outlen)186085658deSDaniel Fojt int blake2sp_final( blake2sp_state *S, void *out, size_t outlen )
187085658deSDaniel Fojt {
188085658deSDaniel Fojt   uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
189085658deSDaniel Fojt   size_t i;
190085658deSDaniel Fojt 
191085658deSDaniel Fojt   if(out == NULL || outlen < S->outlen) {
192085658deSDaniel Fojt     return -1;
193085658deSDaniel Fojt   }
194085658deSDaniel Fojt 
195085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
196085658deSDaniel Fojt   {
197085658deSDaniel Fojt     if( S->buflen > i * BLAKE2S_BLOCKBYTES )
198085658deSDaniel Fojt     {
199085658deSDaniel Fojt       size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES;
200085658deSDaniel Fojt 
201085658deSDaniel Fojt       if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES;
202085658deSDaniel Fojt 
203085658deSDaniel Fojt       blake2s_update( S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left );
204085658deSDaniel Fojt     }
205085658deSDaniel Fojt 
206085658deSDaniel Fojt     blake2s_final( S->S[i], hash[i], BLAKE2S_OUTBYTES );
207085658deSDaniel Fojt   }
208085658deSDaniel Fojt 
209085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
210085658deSDaniel Fojt     blake2s_update( S->R, hash[i], BLAKE2S_OUTBYTES );
211085658deSDaniel Fojt 
212085658deSDaniel Fojt   return blake2s_final( S->R, out, S->outlen );
213085658deSDaniel Fojt }
214085658deSDaniel Fojt 
215085658deSDaniel Fojt 
blake2sp(void * out,size_t outlen,const void * in,size_t inlen,const void * key,size_t keylen)216085658deSDaniel Fojt int blake2sp( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen )
217085658deSDaniel Fojt {
218085658deSDaniel Fojt   uint8_t hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES];
219085658deSDaniel Fojt   blake2s_state S[PARALLELISM_DEGREE][1];
220085658deSDaniel Fojt   blake2s_state FS[1];
221085658deSDaniel Fojt   size_t i;
222085658deSDaniel Fojt 
223085658deSDaniel Fojt   /* Verify parameters */
224085658deSDaniel Fojt   if ( NULL == in && inlen > 0 ) return -1;
225085658deSDaniel Fojt 
226085658deSDaniel Fojt   if ( NULL == out ) return -1;
227085658deSDaniel Fojt 
228085658deSDaniel Fojt   if ( NULL == key && keylen > 0) return -1;
229085658deSDaniel Fojt 
230085658deSDaniel Fojt   if( !outlen || outlen > BLAKE2S_OUTBYTES ) return -1;
231085658deSDaniel Fojt 
232085658deSDaniel Fojt   if( keylen > BLAKE2S_KEYBYTES ) return -1;
233085658deSDaniel Fojt 
234085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
235085658deSDaniel Fojt     if( blake2sp_init_leaf( S[i], outlen, keylen, (uint32_t)i ) < 0 ) return -1;
236085658deSDaniel Fojt 
237085658deSDaniel Fojt   S[PARALLELISM_DEGREE - 1]->last_node = 1; /* mark last node */
238085658deSDaniel Fojt 
239085658deSDaniel Fojt   if( keylen > 0 )
240085658deSDaniel Fojt   {
241085658deSDaniel Fojt     uint8_t block[BLAKE2S_BLOCKBYTES];
242085658deSDaniel Fojt     memset( block, 0, BLAKE2S_BLOCKBYTES );
243085658deSDaniel Fojt     memcpy( block, key, keylen );
244085658deSDaniel Fojt 
245085658deSDaniel Fojt     for( i = 0; i < PARALLELISM_DEGREE; ++i )
246085658deSDaniel Fojt       blake2s_update( S[i], block, BLAKE2S_BLOCKBYTES );
247085658deSDaniel Fojt 
248085658deSDaniel Fojt     secure_zero_memory( block, BLAKE2S_BLOCKBYTES ); /* Burn the key from stack */
249085658deSDaniel Fojt   }
250085658deSDaniel Fojt 
251085658deSDaniel Fojt #if defined(_OPENMP)
252085658deSDaniel Fojt   #pragma omp parallel shared(S,hash), num_threads(PARALLELISM_DEGREE)
253085658deSDaniel Fojt #else
254085658deSDaniel Fojt 
255085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
256085658deSDaniel Fojt #endif
257085658deSDaniel Fojt   {
258085658deSDaniel Fojt #if defined(_OPENMP)
259085658deSDaniel Fojt     size_t      i = omp_get_thread_num();
260085658deSDaniel Fojt #endif
261085658deSDaniel Fojt     size_t inlen__ = inlen;
262085658deSDaniel Fojt     const unsigned char *in__ = ( const unsigned char * )in;
263085658deSDaniel Fojt     in__ += i * BLAKE2S_BLOCKBYTES;
264085658deSDaniel Fojt 
265085658deSDaniel Fojt     while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES )
266085658deSDaniel Fojt     {
267085658deSDaniel Fojt       blake2s_update( S[i], in__, BLAKE2S_BLOCKBYTES );
268085658deSDaniel Fojt       in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
269085658deSDaniel Fojt       inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES;
270085658deSDaniel Fojt     }
271085658deSDaniel Fojt 
272085658deSDaniel Fojt     if( inlen__ > i * BLAKE2S_BLOCKBYTES )
273085658deSDaniel Fojt     {
274085658deSDaniel Fojt       const size_t left = inlen__ - i * BLAKE2S_BLOCKBYTES;
275085658deSDaniel Fojt       const size_t len = left <= BLAKE2S_BLOCKBYTES ? left : BLAKE2S_BLOCKBYTES;
276085658deSDaniel Fojt       blake2s_update( S[i], in__, len );
277085658deSDaniel Fojt     }
278085658deSDaniel Fojt 
279085658deSDaniel Fojt     blake2s_final( S[i], hash[i], BLAKE2S_OUTBYTES );
280085658deSDaniel Fojt   }
281085658deSDaniel Fojt 
282085658deSDaniel Fojt   if( blake2sp_init_root( FS, outlen, keylen ) < 0 )
283085658deSDaniel Fojt     return -1;
284085658deSDaniel Fojt 
285085658deSDaniel Fojt   FS->last_node = 1;
286085658deSDaniel Fojt 
287085658deSDaniel Fojt   for( i = 0; i < PARALLELISM_DEGREE; ++i )
288085658deSDaniel Fojt     blake2s_update( FS, hash[i], BLAKE2S_OUTBYTES );
289085658deSDaniel Fojt 
290085658deSDaniel Fojt   return blake2s_final( FS, out, outlen );
291085658deSDaniel Fojt }
292085658deSDaniel Fojt 
293085658deSDaniel Fojt 
294085658deSDaniel Fojt 
295085658deSDaniel Fojt #if defined(BLAKE2SP_SELFTEST)
296085658deSDaniel Fojt #include <string.h>
297085658deSDaniel Fojt #include "blake2-kat.h"
main(void)298085658deSDaniel Fojt int main( void )
299085658deSDaniel Fojt {
300085658deSDaniel Fojt   uint8_t key[BLAKE2S_KEYBYTES];
301085658deSDaniel Fojt   uint8_t buf[BLAKE2_KAT_LENGTH];
302085658deSDaniel Fojt   size_t i, step;
303085658deSDaniel Fojt 
304085658deSDaniel Fojt   for( i = 0; i < BLAKE2S_KEYBYTES; ++i )
305085658deSDaniel Fojt     key[i] = ( uint8_t )i;
306085658deSDaniel Fojt 
307085658deSDaniel Fojt   for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
308085658deSDaniel Fojt     buf[i] = ( uint8_t )i;
309085658deSDaniel Fojt 
310085658deSDaniel Fojt   /* Test simple API */
311085658deSDaniel Fojt   for( i = 0; i < BLAKE2_KAT_LENGTH; ++i )
312085658deSDaniel Fojt   {
313085658deSDaniel Fojt     uint8_t hash[BLAKE2S_OUTBYTES];
314085658deSDaniel Fojt     blake2sp( hash, BLAKE2S_OUTBYTES, buf, i, key, BLAKE2S_KEYBYTES );
315085658deSDaniel Fojt 
316085658deSDaniel Fojt     if( 0 != memcmp( hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES ) )
317085658deSDaniel Fojt     {
318085658deSDaniel Fojt       goto fail;
319085658deSDaniel Fojt     }
320085658deSDaniel Fojt   }
321085658deSDaniel Fojt 
322085658deSDaniel Fojt   /* Test streaming API */
323085658deSDaniel Fojt   for(step = 1; step < BLAKE2S_BLOCKBYTES; ++step) {
324085658deSDaniel Fojt     for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) {
325085658deSDaniel Fojt       uint8_t hash[BLAKE2S_OUTBYTES];
326085658deSDaniel Fojt       blake2sp_state S;
327085658deSDaniel Fojt       uint8_t * p = buf;
328085658deSDaniel Fojt       size_t mlen = i;
329085658deSDaniel Fojt       int err = 0;
330085658deSDaniel Fojt 
331085658deSDaniel Fojt       if( (err = blake2sp_init_key(&S, BLAKE2S_OUTBYTES, key, BLAKE2S_KEYBYTES)) < 0 ) {
332085658deSDaniel Fojt         goto fail;
333085658deSDaniel Fojt       }
334085658deSDaniel Fojt 
335085658deSDaniel Fojt       while (mlen >= step) {
336085658deSDaniel Fojt         if ( (err = blake2sp_update(&S, p, step)) < 0 ) {
337085658deSDaniel Fojt           goto fail;
338085658deSDaniel Fojt         }
339085658deSDaniel Fojt         mlen -= step;
340085658deSDaniel Fojt         p += step;
341085658deSDaniel Fojt       }
342085658deSDaniel Fojt       if ( (err = blake2sp_update(&S, p, mlen)) < 0) {
343085658deSDaniel Fojt         goto fail;
344085658deSDaniel Fojt       }
345085658deSDaniel Fojt       if ( (err = blake2sp_final(&S, hash, BLAKE2S_OUTBYTES)) < 0) {
346085658deSDaniel Fojt         goto fail;
347085658deSDaniel Fojt       }
348085658deSDaniel Fojt 
349085658deSDaniel Fojt       if (0 != memcmp(hash, blake2sp_keyed_kat[i], BLAKE2S_OUTBYTES)) {
350085658deSDaniel Fojt         goto fail;
351085658deSDaniel Fojt       }
352085658deSDaniel Fojt     }
353085658deSDaniel Fojt   }
354085658deSDaniel Fojt 
355085658deSDaniel Fojt   puts( "ok" );
356085658deSDaniel Fojt   return 0;
357085658deSDaniel Fojt fail:
358085658deSDaniel Fojt   puts("error");
359085658deSDaniel Fojt   return -1;
360085658deSDaniel Fojt }
361085658deSDaniel Fojt #endif
362