Coverage Report

Created: 2025-12-31 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nettle/memxor3.c
Line
Count
Source
1
/* memxor3.c
2
3
   Copyright (C) 2010, 2014 Niels Möller
4
5
   This file is part of GNU Nettle.
6
7
   GNU Nettle is free software: you can redistribute it and/or
8
   modify it under the terms of either:
9
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.
13
14
   or
15
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.
19
20
   or both in parallel, as here.
21
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.
26
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/.
30
*/
31
32
/* Implementation inspired by memcmp in glibc, contributed to the FSF
33
   by Torbjorn Granlund.
34
 */
35
36
#if HAVE_CONFIG_H
37
# include "config.h"
38
#endif
39
40
#include <assert.h>
41
#include <limits.h>
42
43
#include "memxor.h"
44
#include "memxor-internal.h"
45
46
64.1k
#define WORD_T_THRESH 16
47
48
/* For fat builds */
49
#if HAVE_NATIVE_memxor3
50
void *
51
_nettle_memxor3_c(void *dst_in, const void *a_in, const void *b_in, size_t n);
52
# define nettle_memxor3 _nettle_memxor3_c
53
#endif
54
55
/* XOR word-aligned areas. n is the number of words, not bytes. */
56
static void
57
memxor3_common_alignment (word_t *dst,
58
        const word_t *a, const word_t *b, size_t n)
59
34.9k
{
60
  /* FIXME: Require n > 0? */
61
34.9k
  if (n & 1)
62
14.9k
    {
63
14.9k
      n--;
64
14.9k
      dst[n] = a[n] ^ b[n];
65
14.9k
    }
66
507k
  while (n > 0)
67
472k
    {
68
472k
      n -= 2;
69
472k
      dst[n+1] = a[n+1] ^ b[n+1];
70
472k
      dst[n] = a[n] ^ b[n];
71
472k
    }
72
34.9k
}
73
74
static void
75
memxor3_different_alignment_b (word_t *dst,
76
             const word_t *a, const unsigned char *b,
77
             unsigned offset, size_t n)
78
36
{
79
36
  int shl, shr;
80
36
  const word_t *b_word;
81
82
36
  word_t s0, s1;
83
84
36
  assert (n > 0);
85
86
36
  shl = CHAR_BIT * offset;
87
36
  shr = CHAR_BIT * (sizeof(word_t) - offset);
88
89
36
  b_word = (const word_t *) ((uintptr_t) b & -sizeof(word_t));
90
91
  /* Read top offset bytes, in native byte order. */
92
36
  READ_PARTIAL (s0, (unsigned char *) &b_word[n], offset);
93
#ifdef WORDS_BIGENDIAN
94
  s0 <<= shr;
95
#endif
96
97
36
  if (n & 1)
98
0
    s1 = s0;
99
36
  else
100
36
    {
101
36
      n--;
102
36
      s1 = b_word[n];
103
36
      dst[n] = a[n] ^ MERGE (s1, shl, s0, shr);
104
36
    }
105
106
144
  while (n > 2)
107
108
    {
108
108
      n -= 2;
109
108
      s0 = b_word[n+1];
110
108
      dst[n+1] = a[n+1] ^ MERGE(s0, shl, s1, shr);
111
108
      s1 = b_word[n];
112
108
      dst[n] = a[n] ^ MERGE(s1, shl, s0, shr);
113
108
    }
114
36
  assert (n == 1);
115
  /* Read low wordsize - offset bytes */
116
36
  READ_PARTIAL (s0, b, sizeof(word_t) - offset);
117
36
#ifndef WORDS_BIGENDIAN
118
36
  s0 <<= shl;
119
36
#endif /* !WORDS_BIGENDIAN */
120
121
36
  dst[0] = a[0] ^ MERGE(s0, shl, s1, shr);
122
36
}
123
124
static void
125
memxor3_different_alignment_ab (word_t *dst,
126
        const unsigned char *a, const unsigned char *b,
127
        unsigned offset, size_t n)
128
1.16k
{
129
1.16k
  int shl, shr;
130
1.16k
  const word_t *a_word;
131
1.16k
  const word_t *b_word;
132
133
1.16k
  word_t s0, s1, t;
134
135
1.16k
  assert (n > 0);
136
137
1.16k
  shl = CHAR_BIT * offset;
138
1.16k
  shr = CHAR_BIT * (sizeof(word_t) - offset);
139
140
1.16k
  a_word = (const word_t *) ((uintptr_t) a & -sizeof(word_t));
141
1.16k
  b_word = (const word_t *) ((uintptr_t) b & -sizeof(word_t));
142
143
  /* Read top offset bytes, in native byte order. */
144
1.16k
  READ_PARTIAL (s0, (unsigned char *) &a_word[n], offset);
145
1.16k
  READ_PARTIAL (t,  (unsigned char *) &b_word[n], offset);
146
1.16k
  s0 ^= t;
147
#ifdef WORDS_BIGENDIAN
148
  s0 <<= shr;
149
#endif
150
151
1.16k
  if (n & 1)
152
1.16k
    s1 = s0;
153
0
  else
154
0
    {
155
0
      n--;
156
0
      s1 = a_word[n] ^ b_word[n];
157
0
      dst[n] = MERGE (s1, shl, s0, shr);
158
0
    }
159
160
1.16k
  while (n > 2)
161
0
    {
162
0
      n -= 2;
163
0
      s0 = a_word[n+1] ^ b_word[n+1];
164
0
      dst[n+1] = MERGE(s0, shl, s1, shr);
165
0
      s1 = a_word[n] ^ b_word[n];
166
0
      dst[n] = MERGE(s1, shl, s0, shr);
167
0
    }
168
1.16k
  assert (n == 1);
169
  /* Read low wordsize - offset bytes */
170
1.16k
  READ_PARTIAL (s0, a, sizeof(word_t) - offset);
171
1.16k
  READ_PARTIAL (t,  b, sizeof(word_t) - offset);
172
1.16k
  s0 ^= t;
173
1.16k
#ifndef WORDS_BIGENDIAN
174
1.16k
  s0 <<= shl;
175
1.16k
#endif /* !WORDS_BIGENDIAN */
176
177
1.16k
  dst[0] = MERGE(s0, shl, s1, shr);
178
1.16k
}
179
180
static void
181
memxor3_different_alignment_all (word_t *dst,
182
         const unsigned char *a, const unsigned char *b,
183
         unsigned a_offset, unsigned b_offset,
184
         size_t n)
185
0
{
186
0
  int al, ar, bl, br;
187
0
  const word_t *a_word;
188
0
  const word_t *b_word;
189
190
0
  word_t a0, a1, b0, b1;
191
192
0
  al = CHAR_BIT * a_offset;
193
0
  ar = CHAR_BIT * (sizeof(word_t) - a_offset);
194
0
  bl = CHAR_BIT * b_offset;
195
0
  br = CHAR_BIT * (sizeof(word_t) - b_offset);
196
197
0
  a_word = (const word_t *) ((uintptr_t) a & -sizeof(word_t));
198
0
  b_word = (const word_t *) ((uintptr_t) b & -sizeof(word_t));
199
200
  /* Read top offset bytes, in native byte order. */
201
0
  READ_PARTIAL (a0, (unsigned char *) &a_word[n], a_offset);
202
0
  READ_PARTIAL (b0, (unsigned char *) &b_word[n], b_offset);
203
#ifdef WORDS_BIGENDIAN
204
  a0 <<= ar;
205
  b0 <<= br;
206
#endif
207
208
0
  if (n & 1)
209
0
    {
210
0
      a1 = a0; b1 = b0;
211
0
    }
212
0
  else
213
0
    {
214
0
      n--;
215
0
      a1 = a_word[n];
216
0
      b1 = b_word[n];
217
218
0
      dst[n] = MERGE (a1, al, a0, ar) ^ MERGE (b1, bl, b0, br);
219
0
    }
220
0
  while (n > 2)
221
0
    {
222
0
      n -= 2;
223
0
      a0 = a_word[n+1]; b0 = b_word[n+1];
224
0
      dst[n+1] = MERGE(a0, al, a1, ar) ^ MERGE(b0, bl, b1, br);
225
0
      a1 = a_word[n]; b1 = b_word[n];
226
0
      dst[n] = MERGE(a1, al, a0, ar) ^ MERGE(b1, bl, b0, br);
227
0
    }
228
0
  assert (n == 1);
229
  /* Read low wordsize - offset bytes */
230
0
  READ_PARTIAL (a0, a, sizeof(word_t) - a_offset);
231
0
  READ_PARTIAL (b0, b, sizeof(word_t) - b_offset);
232
0
#ifndef WORDS_BIGENDIAN
233
0
  a0 <<= al;
234
0
  b0 <<= bl;
235
0
#endif /* !WORDS_BIGENDIAN */
236
237
0
  dst[0] = MERGE(a0, al, a1, ar) ^ MERGE(b0, bl, b1, br);
238
0
}
239
240
/* Current implementation processes data in descending order, to
241
   support overlapping operation with one of the sources overlapping
242
   the start of the destination area. This feature is used only
243
   internally by cbc decrypt, and it is not advertised or documented
244
   to nettle users. */
245
void *
246
nettle_memxor3(void *dst_in, const void *a_in, 
247
         const void *b_in, size_t n)
248
64.1k
{
249
64.1k
  unsigned char *dst = dst_in;
250
64.1k
  const unsigned char *a = a_in;
251
64.1k
  const unsigned char *b = b_in;
252
253
64.1k
  if (n >= WORD_T_THRESH)
254
36.1k
    {
255
36.1k
      unsigned i;
256
36.1k
      unsigned a_offset;
257
36.1k
      unsigned b_offset;
258
36.1k
      size_t nwords;
259
260
55.0k
      for (i = ALIGN_OFFSET(dst + n); i > 0; i--)
261
18.8k
  {
262
18.8k
    n--;
263
18.8k
    dst[n] = a[n] ^ b[n];
264
18.8k
  }
265
266
36.1k
      a_offset = ALIGN_OFFSET(a + n);
267
36.1k
      b_offset = ALIGN_OFFSET(b + n);
268
269
36.1k
      nwords = n / sizeof (word_t);
270
36.1k
      n %= sizeof (word_t);
271
272
36.1k
      if (a_offset == b_offset)
273
36.1k
  {
274
36.1k
    if (!a_offset)
275
34.9k
      memxor3_common_alignment((word_t *) (dst + n),
276
34.9k
             (const word_t *) (a + n),
277
34.9k
             (const word_t *) (b + n), nwords);
278
1.16k
    else
279
1.16k
      memxor3_different_alignment_ab((word_t *) (dst + n),
280
1.16k
             a + n, b + n, a_offset,
281
1.16k
             nwords);
282
36.1k
  }
283
36
      else if (!a_offset)
284
0
  memxor3_different_alignment_b((word_t *) (dst + n),
285
0
              (const word_t *) (a + n), b + n,
286
0
              b_offset, nwords);
287
36
      else if (!b_offset)
288
36
  memxor3_different_alignment_b((word_t *) (dst + n),
289
36
              (const word_t *) (b + n), a + n,
290
36
              a_offset, nwords);
291
0
      else
292
0
  memxor3_different_alignment_all((word_t *) (dst + n), a + n, b + n,
293
0
          a_offset, b_offset, nwords);
294
295
36.1k
    }
296
257k
  while (n-- > 0)
297
193k
    dst[n] = a[n] ^ b[n];
298
299
64.1k
  return dst;
300
64.1k
}