aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/rng
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2019-06-30 16:10:23 -0400
committerJack Lloyd <[email protected]>2019-07-05 07:45:52 -0400
commit6279da6687ce7fc0e9b2ea3699daf5d55276a21b (patch)
treed939dd6bfb4cc8a1d81ca6cb1215655d68e313cd /src/lib/rng
parent596892be9ae6a3b04f6d8222fdc7a4aef75ca83c (diff)
Use 64-bit RDRAND on x86-64
This doubles RDRAND performance on 64-bit systems. Based on a patch from Jeffrey Walton in #934 Closes #934
Diffstat (limited to 'src/lib/rng')
-rw-r--r--src/lib/rng/rdrand_rng/rdrand_rng.cpp50
1 files changed, 47 insertions, 3 deletions
diff --git a/src/lib/rng/rdrand_rng/rdrand_rng.cpp b/src/lib/rng/rdrand_rng/rdrand_rng.cpp
index ba36c9aac..5b4b05ddb 100644
--- a/src/lib/rng/rdrand_rng/rdrand_rng.cpp
+++ b/src/lib/rng/rdrand_rng/rdrand_rng.cpp
@@ -67,20 +67,64 @@ uint32_t RDRAND_RNG::rdrand_status(bool& ok)
return r;
}
+#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
+
+namespace {
+
+BOTAN_FUNC_ISA("rdrnd")
+uint64_t rdrand64()
+ {
+ for(;;)
+ {
+ uint64_t r = 0;
+
+#if defined(BOTAN_USE_GCC_INLINE_ASM)
+ int cf = 0;
+
+ // Encoding of rdrand %rax
+ asm(".byte 0x48, 0x0F, 0xC7, 0xF0; adcl $0,%1" :
+ "=a" (r), "=r" (cf) : "0" (r), "1" (cf) : "cc");
+#else
+ int cf = _rdrand64_step(&r);
+#endif
+ if(1 == cf)
+ {
+ return r;
+ }
+ }
+
+ return 0;
+ }
+
+}
+
+#endif
+
void RDRAND_RNG::randomize(uint8_t out[], size_t out_len)
{
+#if defined(BOTAN_TARGET_ARCH_IS_X86_64)
+ while(out_len >= 8)
+ {
+ const uint64_t r = rdrand64();
+
+ store_le(r, out);
+ out += 8;
+ out_len -= 8;
+ }
+#endif
+
while(out_len >= 4)
{
- uint32_t r = RDRAND_RNG::rdrand();
+ const uint32_t r = RDRAND_RNG::rdrand();
store_le(r, out);
out += 4;
out_len -= 4;
}
- if(out_len) // between 1 and 3 trailing bytes
+ if(out_len) // final trailing bytes, at most 3
{
- uint32_t r = RDRAND_RNG::rdrand();
+ const uint32_t r = RDRAND_RNG::rdrand();
for(size_t i = 0; i != out_len; ++i)
out[i] = get_byte(i, r);
}