aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/arch/x86/odp_random.h
blob: 14551f47ed10e9aed18c20e833292c9e0e74ffd6 (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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* SPDX-License-Identifier: BSD-3-Clause
 * Copyright (c) 2021 Nokia
 */

/*
 * These functions implement ODP_RANDOM_CRYPTO random data using rdrand [1],
 * and ODP_RANDOM_TRUE random data using rdseed [1], via compiler builtin
 * functions.
 *
 * Note that there may be issues with the quality or security of rdrand and
 * rdseed. [2]
 *
 * [1] Intel Digital Random Number Generator (DRNG) Software Implementation
 *     Guide. John P Mechalas, 17 October 2018.
 *     https://www.intel.com/content/www/us/en/developer/articles/guide/intel-digital-random-number-generator-drng-software-implementation-guide.html
 *
 * [2] RDRAND. Wikipedia, 29 September 2021.
 *     https://en.wikipedia.org/wiki/RDRAND#Reception
 */

#ifndef ODP_X86_RANDOM_H_
#define ODP_X86_RANDOM_H_

#ifdef __cplusplus
extern "C" {
#endif

#include <odp/api/spec/random.h>

#include <stdint.h>

odp_random_kind_t _odp_random_max_kind_generic(void);
int32_t _odp_random_true_data_generic(uint8_t *buf, uint32_t len);
int32_t _odp_random_crypto_data_generic(uint8_t *buf, uint32_t len);

#ifdef __RDRND__

static inline int _odp_random_max_kind(void)
{
#ifdef __RDSEED__
	return ODP_RANDOM_TRUE;
#else
	return ODP_RANDOM_CRYPTO;
#endif
}

#else

static inline int _odp_random_max_kind(void)
{
	return _odp_random_max_kind_generic();
}

#endif

#ifdef __RDSEED__

static inline int32_t _odp_random_true_data(uint8_t *buf, uint32_t len)
{
#ifdef __x86_64__
	for (uint32_t i = 0; i < len / 8; i++) {
		while (!__builtin_ia32_rdseed_di_step((unsigned long long *)buf))
			;
		buf += 8;
	}

	if (len & 4) {
		while (!__builtin_ia32_rdseed_si_step((unsigned int *)buf))
			;
		buf += 4;
	}
#else
	for (uint32_t i = 0; i < len / 4; i++) {
		while (!__builtin_ia32_rdseed_si_step((unsigned int *)buf))
			;
		buf += 4;
	}
#endif
	if (len & 2) {
		while (!__builtin_ia32_rdseed_hi_step((unsigned short int *)buf))
			;
		buf += 2;
	}

	if (len & 1) {
		uint16_t w;

		while (!__builtin_ia32_rdseed_hi_step(&w))
			;
		*((uint8_t *)buf) = w & 0xff;
	}

	return len;
}

#else

static inline int32_t _odp_random_true_data(uint8_t *buf, uint32_t len)
{
	return _odp_random_true_data_generic(buf, len);
}

#endif

#ifdef __RDRND__

static inline int32_t _odp_random_crypto_data(uint8_t *buf, uint32_t len)
{
#ifdef __x86_64__
	for (uint32_t i = 0; i < len / 8; i++) {
		while (!__builtin_ia32_rdrand64_step((unsigned long long *)buf))
			;
		buf += 8;
	}

	if (len & 4) {
		while (!__builtin_ia32_rdrand32_step((unsigned int *)buf))
			;
		buf += 4;
	}
#else
	for (uint32_t i = 0; i < len / 4; i++) {
		while (!__builtin_ia32_rdrand32_step((unsigned int *)buf))
			;
		buf += 4;
	}
#endif
	if (len & 2) {
		while (!__builtin_ia32_rdrand16_step((unsigned short int *)buf))
			;
		buf += 2;
	}

	if (len & 1) {
		uint16_t w;

		while (!__builtin_ia32_rdrand16_step(&w))
			;
		*((uint8_t *)buf) = w & 0xff;
	}

	return len;
}

#else

static inline int32_t _odp_random_crypto_data(uint8_t *buf, uint32_t len)
{
	return _odp_random_crypto_data_generic(buf, len);
}

#endif

#ifdef __cplusplus
}
#endif

#endif