1 /**
2 * Entropy Source Using Intel's rdrand instruction
3 * 
4 * Copyright:
5 * (C) 2012 Jack Lloyd
6 * (C) 2014-2015 Etienne Cimon
7 *
8 * License:
9 * Botan is released under the Simplified BSD License (see LICENSE.md)
10 */
11 module botan.entropy.rdrand;
12 
13 import botan.constants;
14 static if (BOTAN_HAS_ENTROPY_SRC_RDRAND):
15 
16 import botan.entropy.entropy_src;
17 import botan.utils.cpuid;
18 
19 //import botan.utils.simd.immintrin;
20 
21 /**
22 * Entropy source using the rdrand instruction first introduced on
23 * Intel's Ivy Bridge architecture.
24 */
25 final class IntelRdrand : EntropySource
26 {
27 public:
28     @property string name() const { return "Intel Rdrand"; }
29     /*
30     * Get the timestamp
31     */
32     void poll(ref EntropyAccumulator accum)
33     {
34         if (!CPUID.hasRdrand())
35             return;
36         
37         /*
38         * Put an upper bound on the total entropy we're willing to claim
39         * for any one polling of rdrand to prevent it from swamping our
40         * poll. Internally, the rdrand system is a DRGB that reseeds at a
41         * somewhat unpredictable rate (the current conditions are
42         * documented, but that might not be true for different
43         * implementations, eg on Haswell or a future AMD chip, so I don't
44         * want to assume). This limit ensures we're going to poll at least
45         * one other source so we have some diversity in our inputs.
46         */
47 
48         __gshared immutable size_t POLL_UPPER_BOUND = 96;
49         __gshared immutable size_t RDRAND_POLLS = 32;
50         __gshared immutable double ENTROPY_PER_POLL = cast(double)(POLL_UPPER_BOUND) / (RDRAND_POLLS * 4);
51         
52         foreach (size_t i; 0 .. RDRAND_POLLS)
53         {
54             uint r = 0;
55             int cf = _rdrand32_step(&r);
56 
57             if (cf == 1)
58                 accum.add(r, ENTROPY_PER_POLL);
59         }
60     }
61 }
62 
63 version(D_InlineAsm_X86) {
64 
65     // todo: move this to another module
66     int _rdrand32_step(uint* r) {
67         int ret;
68         
69         asm
70         {
71             mov EAX, ret;
72             rdrand EAX;
73             mov ret, EAX;
74         }
75         if (ret != 0)
76             *r = ret;
77         else
78             return 0;
79         return 1;
80     }
81 
82 }
83 version(GDC) {
84     static import gcc.attribute;
85     import gcc.builtins;
86     enum inline = gcc.attribute.attribute("forceinline");
87 
88     @inline
89     int _rdrand32_step(uint* i) {
90         return __builtin_ia32_rdrand32_step(i);
91     }
92 
93 }
94 
95 version(none) {
96     pragma(LDC_intrinsic, "llvm.x86.rdrand.32")
97         int _rdrand32_step(uint*);
98 }
99 
100 version(D_InlineAsm_X86_64) {
101     
102     // todo: move this to another module
103     int _rdrand32_step(uint* r) {
104         int ret;
105         //(for LDC) rdrand EAX => db 0x0F, 0xC7, 0xF0
106         asm
107         {
108             mov EAX, ret;
109             db 0x0F, 0xC7, 0xF0;
110             mov ret, EAX;
111         }
112         if (ret != 0)
113             *r = ret;
114         else
115             return 0;
116         return 1;
117     }
118     
119 }