aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/entropy/p9_darn/p9_darn.cpp
blob: 8731b94e13d37c66add275a9bcd2b25af3634fa5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/*
* (C) 2019 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#include <botan/internal/p9_darn.h>
#include <botan/cpuid.h>

namespace Botan {

namespace {

bool read_darn(secure_vector<uint64_t>& seed)
   {
   const size_t DARN_RETRIES = 512;

   for(size_t i = 0; i != DARN_RETRIES; ++i)
      {
      uint64_t r = 0;

      // DARN 0: 32-bit conditioned, 1: 64-bit condition, 2: 64-bit raw (ala RDSEED)
      asm volatile("darn %0, 2" : "=r" (r));

      // DARN indicates error by 0xFF..FF, ie is biased (!?!?)
      if((~r) != 0)
         {
         seed.push_back(r);
         return true;
         }
      }

   return false; // failed to produce an output after many attempts
   }

}

size_t POWER9_DARN::poll(RandomNumberGenerator& rng)
   {
   const size_t DARN_BYTES = 1024;
   static_assert(DARN_BYTES % 8 == 0, "Bad DARN configuration");

   if(CPUID::has_darn_rng())
      {
      secure_vector<uint64_t> seed;
      seed.reserve(DARN_BYTES / 8);

      for(size_t p = 0; p != DARN_BYTES / 8; ++p)
         {
         if(!read_darn(seed))
            break;
         }

      if(seed.size() > 0)
         {
         rng.add_entropy(reinterpret_cast<const uint8_t*>(seed.data()),
                         seed.size() * sizeof(uint32_t));
         }
      }

   // DARN is used but not trusted
   return 0;
   }

}