Read 64 bits of entropy using rdrand. * * Must only be called when RdRand is supported. */
| 108 | * Must only be called when RdRand is supported. |
| 109 | */ |
| 110 | static uint64_t GetRdRand() noexcept |
| 111 | { |
| 112 | // RdRand may very rarely fail. Invoke it up to 10 times in a loop to reduce this risk. |
| 113 | #ifdef __i386__ |
| 114 | uint8_t ok; |
| 115 | // Initialize to 0 to silence a compiler warning that r1 or r2 may be used |
| 116 | // uninitialized. Even if rdrand fails (!ok) it will set the output to 0, |
| 117 | // but there is no way that the compiler could know that. |
| 118 | uint32_t r1 = 0, r2 = 0; |
| 119 | for (int i = 0; i < 10; ++i) { |
| 120 | __asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %eax |
| 121 | if (ok) break; |
| 122 | } |
| 123 | for (int i = 0; i < 10; ++i) { |
| 124 | __asm__ volatile (".byte 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r2), "=q"(ok) :: "cc"); // rdrand %eax |
| 125 | if (ok) break; |
| 126 | } |
| 127 | return (((uint64_t)r2) << 32) | r1; |
| 128 | #elif defined(__x86_64__) || defined(__amd64__) |
| 129 | uint8_t ok; |
| 130 | uint64_t r1 = 0; // See above why we initialize to 0. |
| 131 | for (int i = 0; i < 10; ++i) { |
| 132 | __asm__ volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %1" : "=a"(r1), "=q"(ok) :: "cc"); // rdrand %rax |
| 133 | if (ok) break; |
| 134 | } |
| 135 | return r1; |
| 136 | #else |
| 137 | #error "RdRand is only supported on x86 and x86_64" |
| 138 | #endif |
| 139 | } |
| 140 | |
| 141 | /** Read 64 bits of entropy using rdseed. |
| 142 | * |
no outgoing calls
no test coverage detected