1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 
4 /******************************************************************************
5  * This Rabbit C source code was morphed fm the EU eSTREAM ECRYPT submission
6  * and should run on any conforming C implementation (C90 or later).
7  *
8  * This implementation supports any key length up to 128 bits (16 bytes) and
9  * works in increments of 8-bit bytes.  Keys must be submitted as whole bytes
10  * and shorter keys will be right-null-padded to 16 bytes.  Likewise, an iv
11  * may be any length up to 8 bytes and will be padded out to 8 bytes.
12  *
13  * The eSTREAM submission was rather picky about the calling sequence of
14  * ECRYPT_process_blocks() and ECRYPT_process_bytes().  That version allowed
15  * calling ECRYPT_process_blocks() multiple times for a multiple of whole
16  * 16-byte blocks, but once ECRYPT_process_bytes() was called. no more calls
17  * were supported correctly.  This implementation handles the keystream
18  * differently and rabbit_crypt() may be called as many times as desired,
19  * crypting any number of bytes each time.
20  *
21  *   http://www.ecrypt.eu.org/stream/e2-rabbit.html
22  *
23  * NB: One of the test vectors distributed by the eSTREAM site in the file
24  *     "rabbit_p3source.zip" is in error.  Referring to "test-vectors.txt"
25  *     in that ZIP file, the 3rd line in "out1" should be
26  *     "96 D6 73 16 88 D1 68 DA 51 D4 0C 70 C3 A1 16 F4".
27  *
28  * Here is the original legal notice accompanying the Rabbit submission
29  * to the EU eSTREAM competition.
30  *---------------------------------------------------------------------------
31  * Copyright (C) Cryptico A/S. All rights reserved.
32  *
33  * YOU SHOULD CAREFULLY READ THIS LEGAL NOTICE BEFORE USING THIS SOFTWARE.
34  *
35  * This software is developed by Cryptico A/S and/or its suppliers.
36  * All title and intellectual property rights in and to the software,
37  * including but not limited to patent rights and copyrights, are owned
38  * by Cryptico A/S and/or its suppliers.
39  *
40  * The software may be used solely for non-commercial purposes
41  * without the prior written consent of Cryptico A/S. For further
42  * information on licensing terms and conditions please contact
43  * Cryptico A/S at info@cryptico.com
44  *
45  * Cryptico, CryptiCore, the Cryptico logo and "Re-thinking encryption"
46  * are either trademarks or registered trademarks of Cryptico A/S.
47  *
48  * Cryptico A/S shall not in any way be liable for any use of this
49  * software. The software is provided "as is" without any express or
50  * implied warranty.
51  *---------------------------------------------------------------------------
52  * On October 6, 2008, Rabbit was "released into the public domain and
53  * may be used freely for any purpose."
54  *   http://www.ecrypt.eu.org/stream/rabbitpf.html
55  *   https://web.archive.org/web/20090630021733/http://www.ecrypt.eu.org/stream/phorum/read.php?1,1244
56  ******************************************************************************/
57 
58 
59 #include "tomcrypt_private.h"
60 
61 #ifdef LTC_RABBIT
62 
63 /* local/private prototypes  (NB: rabbit_ctx and rabbit_state are different)  */
64 static LTC_INLINE ulong32 ss_rabbit_g_func(ulong32 x);
65 static LTC_INLINE void ss_rabbit_next_state(rabbit_ctx *p_instance);
66 static LTC_INLINE void ss_rabbit_gen_1_block(rabbit_state* st, unsigned char *out);
67 
68 /* -------------------------------------------------------------------------- */
69 
70 /* Square a 32-bit unsigned integer to obtain the 64-bit result and return */
71 /* the upper 32 bits XOR the lower 32 bits */
ss_rabbit_g_func(ulong32 x)72 static LTC_INLINE ulong32 ss_rabbit_g_func(ulong32 x)
73 {
74    ulong32 a, b, h, l;
75 
76    /* Construct high and low argument for squaring */
77    a = x &  0xFFFF;
78    b = x >> 16;
79 
80    /* Calculate high and low result of squaring */
81    h = ((((ulong32)(a*a)>>17) + (ulong32)(a*b))>>15) + b*b;
82    l = x * x;
83 
84    /* Return high XOR low */
85    return (ulong32)(h^l);
86 }
87 
88 /* -------------------------------------------------------------------------- */
89 
90 /* Calculate the next internal state */
ss_rabbit_next_state(rabbit_ctx * p_instance)91 static LTC_INLINE void ss_rabbit_next_state(rabbit_ctx *p_instance)
92 {
93    ulong32 g[8], c_old[8], i;
94 
95    /* Save old counter values */
96    for (i=0; i<8; i++) {
97       c_old[i] = p_instance->c[i];
98    }
99 
100    /* Calculate new counter values */
101    p_instance->c[0] = (ulong32)(p_instance->c[0] + 0x4D34D34D + p_instance->carry);
102    p_instance->c[1] = (ulong32)(p_instance->c[1] + 0xD34D34D3 + (p_instance->c[0] < c_old[0]));
103    p_instance->c[2] = (ulong32)(p_instance->c[2] + 0x34D34D34 + (p_instance->c[1] < c_old[1]));
104    p_instance->c[3] = (ulong32)(p_instance->c[3] + 0x4D34D34D + (p_instance->c[2] < c_old[2]));
105    p_instance->c[4] = (ulong32)(p_instance->c[4] + 0xD34D34D3 + (p_instance->c[3] < c_old[3]));
106    p_instance->c[5] = (ulong32)(p_instance->c[5] + 0x34D34D34 + (p_instance->c[4] < c_old[4]));
107    p_instance->c[6] = (ulong32)(p_instance->c[6] + 0x4D34D34D + (p_instance->c[5] < c_old[5]));
108    p_instance->c[7] = (ulong32)(p_instance->c[7] + 0xD34D34D3 + (p_instance->c[6] < c_old[6]));
109    p_instance->carry = (p_instance->c[7] < c_old[7]);
110 
111    /* Calculate the g-values */
112    for (i=0;i<8;i++) {
113       g[i] = ss_rabbit_g_func((ulong32)(p_instance->x[i] + p_instance->c[i]));
114    }
115 
116    /* Calculate new state values */
117    p_instance->x[0] = (ulong32)(g[0] + ROLc(g[7],16) + ROLc(g[6], 16));
118    p_instance->x[1] = (ulong32)(g[1] + ROLc(g[0], 8) + g[7]);
119    p_instance->x[2] = (ulong32)(g[2] + ROLc(g[1],16) + ROLc(g[0], 16));
120    p_instance->x[3] = (ulong32)(g[3] + ROLc(g[2], 8) + g[1]);
121    p_instance->x[4] = (ulong32)(g[4] + ROLc(g[3],16) + ROLc(g[2], 16));
122    p_instance->x[5] = (ulong32)(g[5] + ROLc(g[4], 8) + g[3]);
123    p_instance->x[6] = (ulong32)(g[6] + ROLc(g[5],16) + ROLc(g[4], 16));
124    p_instance->x[7] = (ulong32)(g[7] + ROLc(g[6], 8) + g[5]);
125 }
126 
127 /* ------------------------------------------------------------------------- */
128 
ss_rabbit_gen_1_block(rabbit_state * st,unsigned char * out)129 static LTC_INLINE void ss_rabbit_gen_1_block(rabbit_state* st, unsigned char *out)
130 {
131     ulong32 *ptr;
132 
133     /* Iterate the work context once */
134     ss_rabbit_next_state(&(st->work_ctx));
135 
136     /* Generate 16 bytes of pseudo-random data */
137     ptr = (ulong32*)&(st->work_ctx.x);
138     STORE32L((ptr[0] ^ (ptr[5]>>16) ^ (ulong32)(ptr[3]<<16)), out+ 0);
139     STORE32L((ptr[2] ^ (ptr[7]>>16) ^ (ulong32)(ptr[5]<<16)), out+ 4);
140     STORE32L((ptr[4] ^ (ptr[1]>>16) ^ (ulong32)(ptr[7]<<16)), out+ 8);
141     STORE32L((ptr[6] ^ (ptr[3]>>16) ^ (ulong32)(ptr[1]<<16)), out+12);
142 }
143 
144 /* -------------------------------------------------------------------------- */
145 
146 /* Key setup */
rabbit_setup(rabbit_state * st,const unsigned char * key,unsigned long keylen)147 int rabbit_setup(rabbit_state* st, const unsigned char *key, unsigned long keylen)
148 {
149    ulong32 k0, k1, k2, k3, i;
150    unsigned char  tmpkey[16] = {0};
151 
152    LTC_ARGCHK(st != NULL);
153    LTC_ARGCHK(key != NULL);
154    LTC_ARGCHK(keylen <= 16);
155 
156    /* init state */
157    XMEMSET(st, 0, sizeof(rabbit_state));
158 
159    /* pad key in tmpkey */
160    XMEMCPY(tmpkey, key, keylen);
161 
162    /* Generate four subkeys */
163    LOAD32L(k0, tmpkey+ 0);
164    LOAD32L(k1, tmpkey+ 4);
165    LOAD32L(k2, tmpkey+ 8);
166    LOAD32L(k3, tmpkey+12);
167 
168 #ifdef LTC_CLEAN_STACK
169    /* done with tmpkey, wipe it */
170    zeromem(tmpkey, sizeof(tmpkey));
171 #endif
172 
173    /* Generate initial state variables */
174    st->master_ctx.x[0] = k0;
175    st->master_ctx.x[2] = k1;
176    st->master_ctx.x[4] = k2;
177    st->master_ctx.x[6] = k3;
178    st->master_ctx.x[1] = (ulong32)(k3<<16) | (k2>>16);
179    st->master_ctx.x[3] = (ulong32)(k0<<16) | (k3>>16);
180    st->master_ctx.x[5] = (ulong32)(k1<<16) | (k0>>16);
181    st->master_ctx.x[7] = (ulong32)(k2<<16) | (k1>>16);
182 
183    /* Generate initial counter values */
184    st->master_ctx.c[0] = ROLc(k2, 16);
185    st->master_ctx.c[2] = ROLc(k3, 16);
186    st->master_ctx.c[4] = ROLc(k0, 16);
187    st->master_ctx.c[6] = ROLc(k1, 16);
188    st->master_ctx.c[1] = (k0&0xFFFF0000) | (k1&0xFFFF);
189    st->master_ctx.c[3] = (k1&0xFFFF0000) | (k2&0xFFFF);
190    st->master_ctx.c[5] = (k2&0xFFFF0000) | (k3&0xFFFF);
191    st->master_ctx.c[7] = (k3&0xFFFF0000) | (k0&0xFFFF);
192 
193    /* Clear carry bit */
194    st->master_ctx.carry = 0;
195 
196    /* Iterate the master context four times */
197    for (i=0; i<4; i++) {
198       ss_rabbit_next_state(&(st->master_ctx));
199    }
200 
201    /* Modify the counters */
202    for (i=0; i<8; i++) {
203       st->master_ctx.c[i] ^= st->master_ctx.x[(i+4)&0x7];
204    }
205 
206    /* Copy master instance to work instance */
207    for (i=0; i<8; i++) {
208       st->work_ctx.x[i] = st->master_ctx.x[i];
209       st->work_ctx.c[i] = st->master_ctx.c[i];
210    }
211    st->work_ctx.carry = st->master_ctx.carry;
212    /* ...and prepare block for crypt() */
213    XMEMSET(&(st->block), 0, sizeof(st->block));
214    st->unused = 0;
215 
216    return CRYPT_OK;
217 }
218 
219 /* -------------------------------------------------------------------------- */
220 
221 /* IV setup */
rabbit_setiv(rabbit_state * st,const unsigned char * iv,unsigned long ivlen)222 int rabbit_setiv(rabbit_state* st, const unsigned char *iv, unsigned long ivlen)
223 {
224    ulong32 i0, i1, i2, i3, i;
225    unsigned char  tmpiv[8] = {0};
226 
227    LTC_ARGCHK(st != NULL);
228    LTC_ARGCHK(iv != NULL || ivlen == 0);
229    LTC_ARGCHK(ivlen <= 8);
230 
231    /* pad iv in tmpiv */
232    if (iv && ivlen > 0) XMEMCPY(tmpiv, iv, ivlen);
233 
234    /* Generate four subvectors */
235    LOAD32L(i0, tmpiv+0);
236    LOAD32L(i2, tmpiv+4);
237    i1 = (i0>>16) | (i2&0xFFFF0000);
238    i3 = (i2<<16) | (i0&0x0000FFFF);
239 
240    /* Modify counter values */
241    st->work_ctx.c[0] = st->master_ctx.c[0] ^ i0;
242    st->work_ctx.c[1] = st->master_ctx.c[1] ^ i1;
243    st->work_ctx.c[2] = st->master_ctx.c[2] ^ i2;
244    st->work_ctx.c[3] = st->master_ctx.c[3] ^ i3;
245    st->work_ctx.c[4] = st->master_ctx.c[4] ^ i0;
246    st->work_ctx.c[5] = st->master_ctx.c[5] ^ i1;
247    st->work_ctx.c[6] = st->master_ctx.c[6] ^ i2;
248    st->work_ctx.c[7] = st->master_ctx.c[7] ^ i3;
249 
250    /* Copy state variables */
251    for (i=0; i<8; i++) {
252       st->work_ctx.x[i] = st->master_ctx.x[i];
253    }
254    st->work_ctx.carry = st->master_ctx.carry;
255 
256    /* Iterate the work context four times */
257    for (i=0; i<4; i++) {
258       ss_rabbit_next_state(&(st->work_ctx));
259    }
260 
261    /* reset keystream buffer and unused count */
262    XMEMSET(&(st->block), 0, sizeof(st->block));
263    st->unused = 0;
264 
265    return CRYPT_OK;
266 }
267 
268 /* ------------------------------------------------------------------------- */
269 
270 /* Crypt a chunk of any size (encrypt/decrypt) */
rabbit_crypt(rabbit_state * st,const unsigned char * in,unsigned long inlen,unsigned char * out)271 int rabbit_crypt(rabbit_state* st, const unsigned char *in, unsigned long inlen, unsigned char *out)
272 {
273    unsigned char buf[16];
274    unsigned long i, j;
275 
276    if (inlen == 0) return CRYPT_OK; /* nothing to do */
277 
278    LTC_ARGCHK(st        != NULL);
279    LTC_ARGCHK(in        != NULL);
280    LTC_ARGCHK(out       != NULL);
281 
282    if (st->unused > 0) {
283       j = MIN(st->unused, inlen);
284       for (i = 0; i < j; ++i, st->unused--) out[i] = in[i] ^ st->block[16 - st->unused];
285       inlen -= j;
286       if (inlen == 0) return CRYPT_OK;
287       out += j;
288       in  += j;
289    }
290    for (;;) {
291      /* gen a block for buf */
292      ss_rabbit_gen_1_block(st, buf);
293      if (inlen <= 16) {
294        /* XOR and send to out */
295        for (i = 0; i < inlen; ++i) out[i] = in[i] ^ buf[i];
296        st->unused = 16 - inlen;
297        /* copy remainder to block */
298        for (i = inlen; i < 16; ++i) st->block[i] = buf[i];
299        return CRYPT_OK;
300      }
301      /* XOR entire buf and send to out */
302      for (i = 0; i < 16; ++i) out[i] = in[i] ^ buf[i];
303      inlen -= 16;
304      out += 16;
305      in  += 16;
306    }
307 }
308 
309 /* ------------------------------------------------------------------------- */
310 
rabbit_keystream(rabbit_state * st,unsigned char * out,unsigned long outlen)311 int rabbit_keystream(rabbit_state *st, unsigned char *out, unsigned long outlen)
312 {
313    if (outlen == 0) return CRYPT_OK; /* nothing to do */
314 
315    LTC_ARGCHK(out != NULL);
316 
317    XMEMSET(out, 0, outlen);
318    return rabbit_crypt(st, out, outlen, out);
319 }
320 
321 /* -------------------------------------------------------------------------- */
322 
rabbit_done(rabbit_state * st)323 int rabbit_done(rabbit_state *st)
324 {
325    LTC_ARGCHK(st != NULL);
326 
327    zeromem(st, sizeof(rabbit_state));
328    return CRYPT_OK;
329 }
330 
331 /* -------------------------------------------------------------------------- */
332 
rabbit_test(void)333 int rabbit_test(void)
334 {
335 #ifndef LTC_TEST
336    return CRYPT_NOP;
337 #else
338    rabbit_state st;
339    int err;
340    unsigned char out[1000] = { 0 };
341    {
342       /* all 3 tests use key and iv fm set 6, vector 3, the last vector in:
343          http://www.ecrypt.eu.org/stream/svn/viewcvs.cgi/ecrypt/trunk/submissions/rabbit/verified.test-vectors?rev=210&view=log
344       */
345 
346       /* --- Test 1 (generate whole blocks) --------------------------------- */
347 
348       {
349          unsigned char k[]  = { 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
350                                 0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC };
351          unsigned char iv[] = { 0x28, 0x8F, 0xF6, 0x5D, 0xC4, 0x2B, 0x92, 0xF9 };
352          char pt[64]        = { 0 };
353          unsigned char ct[] = { 0x61, 0x3C, 0xB0, 0xBA, 0x96, 0xAF, 0xF6, 0xCA,
354                                 0xCF, 0x2A, 0x45, 0x9A, 0x10, 0x2A, 0x7F, 0x78,
355                                 0xCA, 0x98, 0x5C, 0xF8, 0xFD, 0xD1, 0x47, 0x40,
356                                 0x18, 0x75, 0x8E, 0x36, 0xAE, 0x99, 0x23, 0xF5,
357                                 0x19, 0xD1, 0x3D, 0x71, 0x8D, 0xAF, 0x8D, 0x7C,
358                                 0x0C, 0x10, 0x9B, 0x79, 0xD5, 0x74, 0x94, 0x39,
359                                 0xB7, 0xEF, 0xA4, 0xC4, 0xC9, 0xC8, 0xD2, 0x9D,
360                                 0xC5, 0xB3, 0x88, 0x83, 0x14, 0xA6, 0x81, 0x6F };
361          unsigned long ptlen = sizeof(pt);
362 
363          /* crypt 64 nulls */
364          if ((err = rabbit_setup(&st, k, sizeof(k)))                   != CRYPT_OK) return err;
365          if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                 != CRYPT_OK) return err;
366          if ((err = rabbit_crypt(&st, (unsigned char*)pt, ptlen, out)) != CRYPT_OK) return err;
367          if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV1", 1))   return CRYPT_FAIL_TESTVECTOR;
368       }
369 
370       /* --- Test 2 (generate unusual number of bytes each time) ------------ */
371 
372       {
373          unsigned char k[]  = { 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
374                                 0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC };
375          unsigned char iv[] = { 0x28, 0x8F, 0xF6, 0x5D, 0xC4, 0x2B, 0x92, 0xF9 };
376          char          pt[39] = { 0 };
377          unsigned char ct[] = { 0x61, 0x3C, 0xB0, 0xBA,   0x96, 0xAF, 0xF6, 0xCA,
378                                 0xCF, 0x2A, 0x45, 0x9A,   0x10, 0x2A, 0x7F, 0x78,
379                                 0xCA, 0x98, 0x5C, 0xF8,   0xFD, 0xD1, 0x47, 0x40,
380                                 0x18, 0x75, 0x8E, 0x36,   0xAE, 0x99, 0x23, 0xF5,
381                                 0x19, 0xD1, 0x3D, 0x71,   0x8D, 0xAF, 0x8D };
382          unsigned long ptlen = sizeof(pt);
383 
384          /* crypt piece by piece (hit at least one 16-byte boundary) */
385          if ((err = rabbit_setup(&st, k, sizeof(k)))                          != CRYPT_OK) return err;
386          if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                        != CRYPT_OK) return err;
387          if ((err = rabbit_crypt(&st, (unsigned char*)pt,       5, out))      != CRYPT_OK) return err;
388          if ((err = rabbit_crypt(&st, (unsigned char*)pt +  5, 11, out +  5)) != CRYPT_OK) return err;
389          if ((err = rabbit_crypt(&st, (unsigned char*)pt + 16, 14, out + 16)) != CRYPT_OK) return err;
390          if ((err = rabbit_crypt(&st, (unsigned char*)pt + 30,  2, out + 30)) != CRYPT_OK) return err;
391          if ((err = rabbit_crypt(&st, (unsigned char*)pt + 32,  7, out + 32)) != CRYPT_OK) return err;
392          if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV2", 1))   return CRYPT_FAIL_TESTVECTOR;
393       }
394 
395       /* --- Test 3 (use non-null data) ------------------------------------- */
396 
397       {
398          unsigned char k[]  = { 0x0F, 0x62, 0xB5, 0x08, 0x5B, 0xAE, 0x01, 0x54,
399                                 0xA7, 0xFA, 0x4D, 0xA0, 0xF3, 0x46, 0x99, 0xEC };
400          unsigned char iv[] = { 0x28, 0x8F, 0xF6, 0x5D, 0xC4, 0x2B, 0x92, 0xF9 };
401          char          pt[] = "Kilroy was here, there, and everywhere!";
402          unsigned char ct[] = { 0x2a, 0x55, 0xdc, 0xc8,   0xf9, 0xd6, 0xd6, 0xbd,
403                                 0xae, 0x59, 0x65, 0xf2,   0x75, 0x58, 0x1a, 0x54,
404                                 0xea, 0xec, 0x34, 0x9d,   0x8f, 0xb4, 0x6b, 0x60,
405                                 0x79, 0x1b, 0xea, 0x16,   0xcb, 0xef, 0x46, 0x87,
406                                 0x60, 0xa6, 0x55, 0x14,   0xff, 0xca, 0xac };
407          unsigned long ptlen = XSTRLEN(pt);
408          unsigned char out2[1000] = { 0 };
409          unsigned char nulls[1000] = { 0 };
410 
411          /* crypt piece by piece */
412          if ((err = rabbit_setup(&st, k, sizeof(k)))                          != CRYPT_OK) return err;
413          if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                        != CRYPT_OK) return err;
414          if ((err = rabbit_crypt(&st, (unsigned char*)pt,       5, out))      != CRYPT_OK) return err;
415          if ((err = rabbit_crypt(&st, (unsigned char*)pt +  5, 29, out +  5)) != CRYPT_OK) return err;
416          if ((err = rabbit_crypt(&st, (unsigned char*)pt + 34,  5, out + 34)) != CRYPT_OK) return err;
417          if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV3", 1))   return CRYPT_FAIL_TESTVECTOR;
418 
419       /* --- Test 4 (crypt in a single call) ------------------------------------ */
420 
421          if ((err = rabbit_memory(k, sizeof(k), iv, sizeof(iv),
422                                    (unsigned char*)pt, sizeof(pt), out))      != CRYPT_OK) return err;
423          if (compare_testvector(out, ptlen, ct, ptlen, "RABBIT-TV4", 1))   return CRYPT_FAIL_TESTVECTOR;
424          /* use 'out' (ciphertext) in the next decryption test */
425 
426       /* --- Test 5 (decrypt ciphertext) ------------------------------------ */
427 
428          /* decrypt ct (out) and compare with pt (start with only setiv() to reset) */
429          if ((err = rabbit_setiv(&st, iv, sizeof(iv)))                        != CRYPT_OK) return err;
430          if ((err = rabbit_crypt(&st, out, ptlen, out2))                      != CRYPT_OK) return err;
431          if (compare_testvector(out2, ptlen, pt, ptlen, "RABBIT-TV5", 1))  return CRYPT_FAIL_TESTVECTOR;
432 
433       /* --- Test 6 (wipe state, incl key) ---------------------------------- */
434 
435          if ((err = rabbit_done(&st))                      != CRYPT_OK) return err;
436          if (compare_testvector(&st, sizeof(st), nulls, sizeof(st), "RABBIT-TV6", 1))  return CRYPT_FAIL_TESTVECTOR;
437 
438       }
439 
440       return CRYPT_OK;
441    }
442 #endif
443 }
444 
445 /* -------------------------------------------------------------------------- */
446 
447 #endif
448