Crypto++ 8.9
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 impostors 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
34NAMESPACE_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
43inline 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.
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
86inline 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.
116#else
117 // Catch other compile breaks
118 int XXX[-1];
119#endif
120}
121#endif // PPC64
122
123// ************************ Standard C++ ************************ //
124
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
134void 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
199void 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.
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
218{
219 throw DARN_Err("HasDARN");
220}
221
222void 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
228void 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
236NAMESPACE_END
Exception thrown when a DARN generator encounters a generator related error.
Definition darn.h:30
DARN()
Construct a DARN generator.
Definition darn.cpp:217
virtual void DiscardBytes(size_t n)
Generate and discard n bytes.
Definition darn.cpp:228
virtual void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition darn.cpp:222
Fixed size stack-based SecBlock.
Definition secblock.h:1246
A method was called which was not implemented.
Definition cryptlib.h:238
void New(size_type newSize)
Change size without preserving contents.
Definition secblock.h:1126
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition secblock.h:885
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition secblock.h:876
Library configuration file.
unsigned int word32
32-bit unsigned datatype
Definition config_int.h:72
unsigned long long word64
64-bit unsigned datatype
Definition config_int.h:101
Functions for CPU features and intrinsics.
Abstract base classes that provide a uniform interface to this library.
Classes for DARN RNG.
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition misc.h:1384
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition misc.h:657
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition misc.h:1436
Crypto++ library namespace.
Precompiled header file.
Classes and functions for secure memory allocations.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition trap.h:68