Crypto++ 8.2 Free C++ class library of cryptographic schemes

darn.cpp
1 // darn.cpp - written and placed in public domain by Jeffrey Walton
2
3 #include "pch.h"
4 #include "config.h"
5 #include "cryptlib.h"
6 #include "secblock.h"
7 #include "darn.h"
8 #include "cpu.h"
9
10 // At the moment only GCC 7.0 (and above) seems to support __builtin_darn()
11 // and __builtin_darn_32(). Clang 7.0 does not provide them, but it does
12 // support assembly instructions. XLC is unknown, but there are no hits when
13 // searching IBM's site. To cover more platforms we provide GCC inline
14 // assembly like we do with RDRAND and RDSEED. Platforms that don't support
15 // GCC inline assembly or the builtin will fail the compile.
16
17 // Inline assembler available in GCC 3.2 or above. For practical
18 // purposes we check for GCC 4.0 or above. GCC imposters claim
19 // to be GCC 4.2.1 so it will capture them, too. We exclude the
20 // Apple machines because they are not Power9 and use a slightly
21 // different syntax in their assembler.
22 #if ((__GNUC__ >= 4) || defined(__IBM_GCC_ASM)) && !defined(__APPLE__)
23 # define GCC_DARN_ASM_AVAILABLE 1
24 #endif
25
26 // warning C4702: unreachable code
27 #if CRYPTOPP_MSC_VERSION
28 # pragma warning(disable: 4702)
29 #endif
30
31 /////////////////////////////////////////////////////////////////////
32 /////////////////////////////////////////////////////////////////////
33
34 NAMESPACE_BEGIN(CryptoPP)
35
36 #if (CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64)
37
38 // *************************** 32-bit *************************** //
39
40 #if (CRYPTOPP_BOOL_PPC32)
41
42 // Fills 4 bytes, buffer must be aligned
43 inline void DARN32(void* output)
44 {
45 CRYPTOPP_ASSERT(IsAlignedOn(output, GetAlignmentOf<word32>()));
46 word32* ptr = reinterpret_cast<word32*>(output);
47
48 #if defined(GCC_DARN_ASM_AVAILABLE)
49 // This is "darn r3, 0". When L=0 a 32-bit conditioned word
50 // is returned. On failure 0xffffffffffffffff is returned.
51 // The Power manual recommends only checking the low 32-bit
52 // word for this case. See Power ISA 3.0 specification, p. 78.
53 do
54 {
55 __asm__ __volatile__ (
56 #if (CRYPTOPP_BIG_ENDIAN)
57 ".byte 0x7c, 0x60, 0x05, 0xe6 \n\t" // r3 = darn 3, 0
58 "mr %0, 3 \n\t" // val = r3
59 #else
60 ".byte 0xe6, 0x05, 0x60, 0x7c \n\t" // r3 = darn 3, 0
61 "mr %0, 3 \n\t" // val = r3
62 #endif
63 : "=r" (*ptr) : : "r3"
64 );
65 } while (*ptr == 0xFFFFFFFFu);
66 #elif defined(_ARCH_PWR9)
67 // This is probably going to break some platforms.
68 // We will deal with them as we encounter them.
69 *ptr = __builtin_darn_32();
70 #elif defined(__APPLE__)
71 // Nop. Apple G4 and G5 machines are too old. They will
72 // avoid this code path because HasPower9() returns false.
73 CRYPTOPP_ASSERT(0);
74 #else
75 // Catch other compile breaks
76 int XXX[-1];
77 #endif
78 }
79 #endif // PPC32
80
81 // *************************** 64-bit *************************** //
82
83 #if (CRYPTOPP_BOOL_PPC64)
84
85 // Fills 8 bytes, buffer must be aligned
86 inline void DARN64(void* output)
87 {
88 CRYPTOPP_ASSERT(IsAlignedOn(output, GetAlignmentOf<word64>()));
89 word64* ptr = reinterpret_cast<word64*>(output);
90
91 #if defined(GCC_DARN_ASM_AVAILABLE)
92 // This is "darn r3, 1". When L=1 a 64-bit conditioned word
93 // is returned. On failure 0xffffffffffffffff is returned.
94 // See Power ISA 3.0 specification, p. 78.
95 do
96 {
97 __asm__ __volatile__ (
98 #if (CRYPTOPP_BIG_ENDIAN)
99 ".byte 0x7c, 0x61, 0x05, 0xe6 \n\t" // r3 = darn 3, 1
100 "mr %0, 3 \n\t" // val = r3
101 #else
102 ".byte 0xe6, 0x05, 0x61, 0x7c \n\t" // r3 = darn 3, 1
103 "mr %0, 3 \n\t" // val = r3
104 #endif
105 : "=r" (*ptr) : : "r3"
106 );
107 } while (*ptr == 0xFFFFFFFFFFFFFFFFull);
108 #elif defined(_ARCH_PWR9)
109 // This is probably going to break some platforms.
110 // We will deal with them as we encounter them.
111 *ptr = __builtin_darn();
112 #elif defined(__APPLE__)
113 // Nop. Apple G4 and G5 machines are too old. They will
114 // avoid this code path because HasPower9() returns false.
115 CRYPTOPP_ASSERT(0);
116 #else
117 // Catch other compile breaks
118 int XXX[-1];
119 #endif
120 }
121 #endif // PPC64
122
123 // ************************ Standard C++ ************************ //
124
125 DARN::DARN()
126 {
127 if (!HasDARN())
128 throw DARN_Err("HasDARN");
129
130 // Scratch buffer in case user buffers are unaligned.
131 m_temp.New(8);
132 }
133
134 void DARN::GenerateBlock(byte *output, size_t size)
135 {
136 CRYPTOPP_ASSERT((output && size) || !(output || size));
137 if (size == 0) return;
138 size_t i = 0;
139
140 #if (CRYPTOPP_BOOL_PPC64)
141
142 // Check alignment
143 i = reinterpret_cast<uintptr_t>(output) & 0x7;
144 if (i != 0)
145 {
146 DARN64(m_temp);
147 std::memcpy(output, m_temp, i);
148
149 output += i;
150 size -= i;
151 }
152
153 // Output is aligned
154 for (i = 0; i < size/8; i++)
155 DARN64(output+i*8);
156
157 output += i*8;
158 size -= i*8;
159
160 if (size)
161 {
162 DARN64(m_temp);
163 std::memcpy(output, m_temp, size);
164 }
165
166 #elif (CRYPTOPP_BOOL_PPC32)
167
168 // Check alignment
169 i = reinterpret_cast<uintptr_t>(output) & 0x3;
170 if (i != 0)
171 {
172 DARN32(m_temp);
173 std::memcpy(output, m_temp, i);
174
175 output += i;
176 size -= i;
177 }
178
179 // Output is aligned
180 for (i = 0; i < size/4; i++)
181 DARN32(output+i*4);
182
183 output += i*4;
184 size -= i*4;
185
186 if (size)
187 {
188 DARN32(m_temp);
189 std::memcpy(output, m_temp, size);
190 }
191
192 #else
193 // No suitable compiler found
194 CRYPTOPP_UNUSED(output);
195 throw NotImplemented("DARN: failed to find a suitable implementation");
196 #endif
197 }
198
199 void DARN::DiscardBytes(size_t n)
200 {
201 // RoundUpToMultipleOf is used because a full word is read, and its cheaper
202 // to discard full words. There's no sense in dealing with tail bytes.
203 FixedSizeSecBlock<word64, 16> discard;
204 n = RoundUpToMultipleOf(n, sizeof(word64));
205
206 size_t count = STDMIN(n, discard.SizeInBytes());
207 while (count)
208 {
209 GenerateBlock(discard.BytePtr(), count);
210 n -= count;
211 count = STDMIN(n, discard.SizeInBytes());
212 }
213 }
214
215 #else // not PPC32 or PPC64
216
217 DARN::DARN()
218 {
219 throw DARN_Err("HasDARN");
220 }
221
222 void DARN::GenerateBlock(byte *output, size_t size)
223 {
224 // Constructor will throw, should not get here
225 CRYPTOPP_UNUSED(output); CRYPTOPP_UNUSED(size);
226 }
227
228 void DARN::DiscardBytes(size_t n)
229 {
230 // Constructor will throw, should not get here
231 CRYPTOPP_UNUSED(n);
232 }
233
234 #endif // PPC32 or PPC64
235
236 NAMESPACE_END
DARN::DARN
DARN()
Construct a DARN generator.
Definition: darn.cpp:217
HasDARN
bool HasDARN()
Determine if a PowerPC processor has DARN available.
Definition: cpu.h:836
DARN_Err
Exception thrown when a DARN generator encounters a generator related error.
Definition: darn.h:29
SecBlock::SizeInBytes
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition: secblock.h:845
cryptlib.h
Abstract base classes that provide a uniform interface to this library.
config.h
Library configuration file.
SecBlock::New
void New(size_type newSize)
Change size without preserving contents.
Definition: secblock.h:1004
DARN::GenerateBlock
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: darn.cpp:222
secblock.h
Classes and functions for secure memory allocations.
DARN::DiscardBytes
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition: darn.cpp:228
IsAlignedOn
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition: misc.h:1207
NotImplemented
A method was called which was not implemented.
Definition: cryptlib.h:232
pch.h
Precompiled header file.
FixedSizeSecBlock
Fixed size stack-based SecBlock.
Definition: secblock.h:1116
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:635
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68
darn.h
Classes for DARN RNG.
cpu.h
Functions for CPU features and intrinsics.
RoundUpToMultipleOf
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1154
CryptoPP
Crypto++ library namespace.
SecBlock::BytePtr
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:838