1 // SPDX-License-Identifier: LicenseRef-OpenZFS-ThirdParty-PublicDomain
2 /*
3 * Platform-specific definitions for Skein hash function.
4 *
5 * Source code author: Doug Whiting, 2008.
6 *
7 * This algorithm and source code is released to the public domain.
8 *
9 * Many thanks to Brian Gladman for his portable header files.
10 *
11 * To port Skein to an "unsupported" platform, change the definitions
12 * in this file appropriately.
13 */
14 /* Copyright 2013 Doug Whiting. This code is released to the public domain. */
15
16 #ifndef _SKEIN_PORT_H_
17 #define _SKEIN_PORT_H_
18
19 #include <sys/types.h> /* get integer type definitions */
20
21 #ifndef RotL_64
22 #define RotL_64(x, N) (((x) << (N)) | ((x) >> (64 - (N))))
23 #endif
24
25 /*
26 * Skein is "natively" little-endian (unlike SHA-xxx), for optimal
27 * performance on x86 CPUs. The Skein code requires the following
28 * definitions for dealing with endianness:
29 *
30 * SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian
31 * Skein_Put64_LSB_First
32 * Skein_Get64_LSB_First
33 * Skein_Swap64
34 *
35 * If SKEIN_NEED_SWAP is defined at compile time, it is used here
36 * along with the portable versions of Put64/Get64/Swap64, which
37 * are slow in general.
38 *
39 * Otherwise, an "auto-detect" of endianness is attempted below.
40 * If the default handling doesn't work well, the user may insert
41 * platform-specific code instead (e.g., for big-endian CPUs).
42 *
43 */
44 #ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */
45
46 #include <sys/isa_defs.h> /* get endianness selection */
47
48 #if defined(_ZFS_BIG_ENDIAN)
49 /* here for big-endian CPUs */
50 #define SKEIN_NEED_SWAP (1)
51 #else
52 /* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
53 #define SKEIN_NEED_SWAP (0)
54 #define Skein_Put64_LSB_First(dst08, src64, bCnt) memcpy(dst08, src64, bCnt)
55 #define Skein_Get64_LSB_First(dst64, src08, wCnt) \
56 memcpy(dst64, src08, 8 * (wCnt))
57 #endif
58
59 #endif /* ifndef SKEIN_NEED_SWAP */
60
61 /*
62 * Provide any definitions still needed.
63 */
64 #ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */
65 #if SKEIN_NEED_SWAP
66 #define Skein_Swap64(w64) \
67 (((((uint64_t)(w64)) & 0xFF) << 56) | \
68 (((((uint64_t)(w64)) >> 8) & 0xFF) << 48) | \
69 (((((uint64_t)(w64)) >> 16) & 0xFF) << 40) | \
70 (((((uint64_t)(w64)) >> 24) & 0xFF) << 32) | \
71 (((((uint64_t)(w64)) >> 32) & 0xFF) << 24) | \
72 (((((uint64_t)(w64)) >> 40) & 0xFF) << 16) | \
73 (((((uint64_t)(w64)) >> 48) & 0xFF) << 8) | \
74 (((((uint64_t)(w64)) >> 56) & 0xFF)))
75 #else
76 #define Skein_Swap64(w64) (w64)
77 #endif
78 #endif /* ifndef Skein_Swap64 */
79
80 #ifndef Skein_Put64_LSB_First
81 static inline void
Skein_Put64_LSB_First(uint8_t * dst,const uint64_t * src,size_t bCnt)82 Skein_Put64_LSB_First(uint8_t *dst, const uint64_t *src, size_t bCnt)
83 {
84 /*
85 * this version is fully portable (big-endian or little-endian),
86 * but slow
87 */
88 size_t n;
89
90 for (n = 0; n < bCnt; n++)
91 dst[n] = (uint8_t)(src[n >> 3] >> (8 * (n & 7)));
92 }
93 #endif /* ifndef Skein_Put64_LSB_First */
94
95 #ifndef Skein_Get64_LSB_First
96 static inline void
Skein_Get64_LSB_First(uint64_t * dst,const uint8_t * src,size_t wCnt)97 Skein_Get64_LSB_First(uint64_t *dst, const uint8_t *src, size_t wCnt)
98 {
99 /*
100 * this version is fully portable (big-endian or little-endian),
101 * but slow
102 */
103 size_t n;
104
105 for (n = 0; n < 8 * wCnt; n += 8)
106 dst[n / 8] = (((uint64_t)src[n])) +
107 (((uint64_t)src[n + 1]) << 8) +
108 (((uint64_t)src[n + 2]) << 16) +
109 (((uint64_t)src[n + 3]) << 24) +
110 (((uint64_t)src[n + 4]) << 32) +
111 (((uint64_t)src[n + 5]) << 40) +
112 (((uint64_t)src[n + 6]) << 48) +
113 (((uint64_t)src[n + 7]) << 56);
114 }
115 #endif /* ifndef Skein_Get64_LSB_First */
116
117 #endif /* _SKEIN_PORT_H_ */
118