3 Copyright (C) 2010, 2014 Niels Möller
5 This file is part of GNU Nettle.
7 GNU Nettle is free software: you can redistribute it and/or
8 modify it under the terms of either:
10 * the GNU Lesser General Public License as published by the Free
11 Software Foundation; either version 3 of the License, or (at your
12 option) any later version.
16 * the GNU General Public License as published by the Free
17 Software Foundation; either version 2 of the License, or (at your
18 option) any later version.
20 or both in parallel, as here.
22 GNU Nettle is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received copies of the GNU General Public License and
28 the GNU Lesser General Public License along with this program. If
29 not, see http://www.gnu.org/licenses/.
32 /* Implementation inspired by memcmp in glibc, contributed to the FSF
44 #include "memxor-internal.h"
46 #define WORD_T_THRESH 16
48 /* XOR word-aligned areas. n is the number of words, not bytes. */
50 memxor_common_alignment (word_t *dst, const word_t *src, size_t n)
52 /* FIXME: Require n > 0? */
53 /* FIXME: Unroll four times, like memcmp? Probably not worth the
69 /* XOR *un-aligned* src-area onto aligned dst area. n is number of
70 words, not bytes. Assumes we can read complete words at the start
71 and end of the src operand. */
73 memxor_different_alignment (word_t *dst, const unsigned char *src, size_t n)
76 const word_t *src_word;
77 unsigned offset = ALIGN_OFFSET (src);
81 shl = CHAR_BIT * offset;
82 shr = CHAR_BIT * (sizeof(word_t) - offset);
84 src_word = (const word_t *) ((uintptr_t) src & -sizeof(word_t));
86 /* Read top offset bytes, in native byte order. */
87 READ_PARTIAL (s0, (unsigned char *) &src_word[n], offset);
88 #ifdef WORDS_BIGENDIAN
89 s0 <<= shr; /* FIXME: Eliminate this shift? */
92 /* Do n-1 regular iterations */
99 dst[n] ^= MERGE (s1, shl, s0, shr);
107 dst[n+1] ^= MERGE(s0, shl, s1, shr);
108 s1 = src_word[n]; /* FIXME: Overread on last iteration */
109 dst[n] ^= MERGE(s1, shl, s0, shr);
112 /* Read low wordsize - offset bytes */
113 READ_PARTIAL (s0, src, sizeof(word_t) - offset);
114 #ifndef WORDS_BIGENDIAN
115 s0 <<= shl; /* FIXME: eliminate shift? */
116 #endif /* !WORDS_BIGENDIAN */
118 dst[0] ^= MERGE(s0, shl, s1, shr);
121 /* Performance, Intel SU1400 (x86_64): 0.25 cycles/byte aligned, 0.45
122 cycles/byte unaligned. */
124 /* XOR LEN bytes starting at SRCADDR onto DESTADDR. Result undefined
125 if the source overlaps with the destination. Return DESTADDR. */
127 memxor(void *dst_in, const void *src_in, size_t n)
129 unsigned char *dst = dst_in;
130 const unsigned char *src = src_in;
132 if (n >= WORD_T_THRESH)
137 /* There are at least some bytes to compare. No need to test
138 for N == 0 in this alignment loop. */
139 for (i = ALIGN_OFFSET(dst + n); i > 0; i--)
144 offset = ALIGN_OFFSET(src + n);
145 nwords = n / sizeof (word_t);
146 n %= sizeof (word_t);
149 memxor_different_alignment ((word_t *) (dst+n), src+n, nwords);
151 memxor_common_alignment ((word_t *) (dst+n),
152 (const word_t *) (src+n), nwords);