Crypto++  8.8
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 
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.
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 
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
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
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition: secblock.h:876
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
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
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition: misc.h:1436
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:657
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