1 ;; rdrand.asm - written and placed in public domain by Jeffrey Walton and Uri Blumenthal.
2 ;; Copyright assigned to the Crypto++ project.
4 ;; This ASM file provides RDRAND and RDSEED to downlevel Unix and Linux tool chains.
5 ;; Additionally, the inline assembly code produced by GCC and Clang is not that
6 ;; impressive. However, using this code requires NASM and an edit to the GNUmakefile.
8 ;; nasm -f elf32 rdrand.S -DX86 -g -o rdrand-x86.o
9 ;; nasm -f elfx32 rdrand.S -DX32 -g -o rdrand-x32.o
10 ;; nasm -f elf64 rdrand.S -DX64 -g -o rdrand-x64.o
12 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
13 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15 ;; Naming convention used in rdrand.{h|cpp|asm|S}
16 ;; MSC = Microsoft Compiler (and compatibles)
17 ;; GCC = GNU Compiler (and compatibles)
18 ;; ALL = MSC and GCC (and compatibles)
19 ;; RRA = RDRAND, Assembly
20 ;; RSA = RDSEED, Assembly
21 ;; RRI = RDRAND, Intrinsic
22 ;; RSA = RDSEED, Intrinsic
24 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
25 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
27 ;; C/C++ Function prototypes
29 ;; extern "C" int NASM_RRA_GenerateBlock(byte* ptr, size_t size, unsigned int safety);
31 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
32 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
35 %define RDRAND_SUCCESS 1
36 %define RDRAND_FAILURE 0
38 %define RDSEED_SUCCESS 1
39 %define RDSEED_FAILURE 0
41 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
42 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
44 %ifdef X86 or X32 ;; Set via the command line
48 ;; Arg3, unsigned int safety
49 ;; EAX (out): success (1), failure (0)
51 global NASM_RRA_GenerateBlock
61 NASM_RRA_GenerateBlock:
64 %define arg1 [ebp+04h]
65 %define arg2 [ebp+08h]
66 %define arg3 [ebp+0ch]
67 %define MWSIZE 04h ;; machine word size
69 %define MWSIZE 08h ;; machine word size
87 je .GenerateBlock_PreRet
92 ;; Check remaining size
94 je .GenerateBlock_Success
100 DB 48h ;; X32 can use the full register, issue the REX.w prefix
102 ;; RDRAND is not available prior to VS2012. Just emit
103 ;; the byte codes using DB. This is `rdrand eax`.
106 ;; If CF=1, the number returned by RDRAND is valid.
107 ;; If CF=0, a random number was not available.
112 ;; Exit if we've reached the limit
114 je .GenerateBlock_Failure
117 jmp .GenerateBlock_Top
122 jb .Partial_Machine_Word
127 mov [buffer+4], eax ;; We can only move 4 at a time
128 DB 048h ;; Combined, these result in
129 shr eax, 32 ;; `shr rax, 32`
133 add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
134 sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
137 jmp .GenerateBlock_Top
139 ;; 1,2,3 bytes remain for X86
140 ;; 1,2,3,4,5,6,7 remain for X32
141 .Partial_Machine_Word:
144 ;; Test bit 2 to see if size is at least 4
151 DB 048h ;; Combined, these result in
152 shr eax, 32 ;; `shr rax, 32`
157 ;; Test bit 1 to see if size is at least 2
167 ;; Test bit 0 to see if size is at least 1
169 jz .GenerateBlock_Success
175 ;; We've hit all the bits
176 jmp .GenerateBlock_Success
178 .GenerateBlock_PreRet:
180 ;; Test for success (was the request completely fulfilled?)
182 je .GenerateBlock_Success
184 .GenerateBlock_Failure:
187 mov al, RDRAND_FAILURE
190 .GenerateBlock_Success:
193 mov al, RDRAND_SUCCESS
196 %endif ;; X86 and X32
198 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
199 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
201 %ifdef X64 ;; Set via the command line
203 global NASM_RRA_GenerateBlock
207 ;; Arg1, byte* buffer
208 ;; Arg2, size_t bsize
209 ;; Arg3, unsigned int safety
210 ;; RAX (out): success (1), failure (0)
212 NASM_RRA_GenerateBlock:
214 %define MWSIZE 08h ;; machine word size
219 ;; No need for Load_Arguments due to fastcall
225 je .GenerateBlock_PreRet
230 ;; Check remaining size
232 je .GenerateBlock_Success
235 ;; RDRAND is not available prior to VS2012. Just emit
236 ;; the byte codes using DB. This is `rdrand rax`.
237 DB 048h, 0Fh, 0C7h, 0F0h
239 ;; If CF=1, the number returned by RDRAND is valid.
240 ;; If CF=0, a random number was not available.
245 ;; Exit if we've reached the limit
247 je .GenerateBlock_Failure
250 jmp .GenerateBlock_Top
255 jb .Partial_Machine_Word
264 jmp .GenerateBlock_Top
266 ;; 1,2,3,4,5,6,7 bytes remain
267 .Partial_Machine_Word:
269 ;; Test bit 2 to see if size is at least 4
279 ;; Test bit 1 to see if size is at least 2
289 ;; Test bit 0 to see if size is at least 1
291 jz .GenerateBlock_Success
297 ;; We've hit all the bits
298 jmp .GenerateBlock_Success
300 .GenerateBlock_PreRet:
302 ;; Test for success (was the request completely fulfilled?)
304 je .GenerateBlock_Success
306 .GenerateBlock_Failure:
309 mov al, RDRAND_FAILURE
312 .GenerateBlock_Success:
315 mov al, RDRAND_SUCCESS
320 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
321 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
323 %ifdef X86 or X32 ;; Set via the command line
325 ;; Arg1, byte* buffer
326 ;; Arg2, size_t bsize
327 ;; Arg3, unsigned int safety
328 ;; EAX (out): success (1), failure (0)
330 global NASM_RSA_GenerateBlock
341 NASM_RSA_GenerateBlock:
344 %define arg1 [ebp+04h]
345 %define arg2 [ebp+08h]
346 %define arg3 [ebp+0ch]
347 %define MWSIZE 04h ;; machine word size
349 %define MWSIZE 08h ;; machine word size
367 je .GenerateBlock_PreRet
372 ;; Check remaining size
374 je .GenerateBlock_Success
380 DB 48h ;; X32 can use the full register, issue the REX.w prefix
382 ;; RDSEED is not available prior to VS2012. Just emit
383 ;; the byte codes using DB. This is `rdseed eax`.
386 ;; If CF=1, the number returned by RDSEED is valid.
387 ;; If CF=0, a random number was not available.
392 ;; Exit if we've reached the limit
394 je .GenerateBlock_Failure
397 jmp .GenerateBlock_Top
402 jb .Partial_Machine_Word
407 add buffer, MWSIZE ;; No need for Intel Core 2 slow word workarounds,
408 sub bsize, MWSIZE ;; like `lea buffer,[buffer+MWSIZE]` for faster adds
411 jmp .GenerateBlock_Top
413 ;; 1,2,3 bytes remain for X86
414 ;; 1,2,3,4,5,6,7 remain for X32
415 .Partial_Machine_Word:
418 ;; Test bit 2 to see if size is at least 4
425 DB 048h ;; Combined, these result in
426 shr eax, 32 ;; `shr rax, 32`
431 ;; Test bit 1 to see if size is at least 2
441 ;; Test bit 0 to see if size is at least 1
443 jz .GenerateBlock_Success
449 ;; We've hit all the bits
450 jmp .GenerateBlock_Success
452 .GenerateBlock_PreRet:
454 ;; Test for success (was the request completely fulfilled?)
456 je .GenerateBlock_Success
458 .GenerateBlock_Failure:
461 mov al, RDSEED_FAILURE
464 .GenerateBlock_Success:
467 mov al, RDSEED_SUCCESS
470 %endif ;; X86 and X32
472 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
473 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
475 %ifdef X64 ;; Set via the command line
477 global NASM_RSA_GenerateBlock
481 ;; Arg1, byte* buffer
482 ;; Arg2, size_t bsize
483 ;; Arg3, unsigned int safety
484 ;; RAX (out): success (1), failure (0)
486 NASM_RSA_GenerateBlock:
488 %define MWSIZE 08h ;; machine word size
493 ;; No need for Load_Arguments due to fastcall
499 je .GenerateBlock_PreRet
504 ;; Check remaining size
506 je .GenerateBlock_Success
509 ;; RDSEED is not available prior to VS2012. Just emit
510 ;; the byte codes using DB. This is `rdseed rax`.
511 DB 048h, 0Fh, 0C7h, 0F8h
513 ;; If CF=1, the number returned by RDSEED is valid.
514 ;; If CF=0, a random number was not available.
519 ;; Exit if we've reached the limit
521 je .GenerateBlock_Failure
524 jmp .GenerateBlock_Top
529 jb .Partial_Machine_Word
538 jmp .GenerateBlock_Top
540 ;; 1,2,3,4,5,6,7 bytes remain
541 .Partial_Machine_Word:
543 ;; Test bit 2 to see if size is at least 4
553 ;; Test bit 1 to see if size is at least 2
563 ;; Test bit 0 to see if size is at least 1
565 jz .GenerateBlock_Success
571 ;; We've hit all the bits
572 jmp .GenerateBlock_Success
574 .GenerateBlock_PreRet:
576 ;; Test for success (was the request completely fulfilled?)
578 je .GenerateBlock_Success
580 .GenerateBlock_Failure:
583 mov al, RDSEED_FAILURE
586 .GenerateBlock_Success:
589 mov al, RDSEED_SUCCESS
594 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
595 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;