Как использовать встроенные функции RDRAND?


person jww    schedule 03.07.2015    source источник
comment
@Filip - Да, BullRun получил много негативной критики из-за утечек Сноудена (и др.). В этом случае я использую собственный генератор случайных чисел, который извлекает, а затем расширяет энтропию. Существует несколько источников, поэтому бэкдоры АНБ не приведут к катастрофическому отказу генератора.   -  person jww    schedule 04.07.2015


Ответы (1)


Если вы посмотрите на <immintrin.h> (мой находится в `/usr/lib/gcc/x86_64-linux-gnu/4.9/include/', Ubuntu 15.04 64bit), там определены совместимые (с MSVC, Intel CC) функции, которые передают данные обратно к встроенным модулям GCC

extern __inline int __attribute__((__gnu_inline__, __always_inline__, __artificial__))
_rdrand64_step (unsigned long long *__P)
{
     return __builtin_ia32_rdrand64_step (__P);
}

для 64-битного параметра и два других для 16-битных и 32-битных параметров

_rdrand16_step (unsigned short *__P)
_rdrand32_step (unsigned int *__P)

Вы должны были использовать их, чтобы ваш код был совместим с MSVC, Intel CC и другими компиляторами.

_rdrand64_step заполнит 64-битный параметр, переданный указателем, случайными битами и вернет код ошибки. То же самое для 32-битной и 16-битной версий

ОБНОВИТЬ

Эти встроенные функции генерируют случайные числа из 16/32/64-битных случайных целых чисел. Сгенерированное случайное значение записывается в указанную ячейку памяти, и возвращается статус успеха: «1», если аппаратное обеспечение вернуло допустимое случайное значение, и «0» в противном случае.

https://software.intel.com/en-us/node/523864

ОБНОВИТЬ

По запросу @vy32 это работает для меня. Что ж, моя система обновлена ​​после первоначального ответа, так что теперь это Ubuntu 20.04.1, x64, GCC v9.3, флаги компиляции.

gcc -m64 -mrdrnd -O3 a.c

Код

#include <stdio.h>
#include <immintrin.h>

int main() {
    unsigned long long result = 0ULL;

    int rc = _rdrand64_step (&result);

    printf("%i %llu", rc, result);

    return (rc != 1);
}

Что касается флага CF и игнорирования этого, это распространенная ошибка реализации, которая не проявляется при тестировании, но появляется, когда вы запускаете DRNG под нагрузкой, я считаю, что это то, что делает встроенный. Если вы закомментируете printf и скомпилируете на ассемблере с флагом -S, код будет выглядеть так:

xorl    %eax, %eax
rdrand  %rax
movl    $1, %edx
...    
cmovc   %edx, %eax

это означает, что %eax обнуляется, %edx устанавливается в 1, а затем через cmovc %edx может быть установлено в 0, если CF повышается. И это значение возвращается из функции.

Поэтому я считаю, что встроенная функция уже правильно обрабатывает флаг переноса, и пользователь должен просто проверить вывод _rdrandXX_step(ull*), как описано в руководстве.

person Severin Pappadeux    schedule 04.07.2015
comment
Каковы возвращаемые значения? Как мы узнаем, успешно ли выполнилась функция или нет? - person jww; 06.07.2015
comment
GCC сделал беспорядок из этого. Их использование unsigned long long разочаровывает. - person jww; 31.07.2016
comment
@ vy32, что именно вы просите? Зачем вам нужен перенос флага по случайным числам? - person Severin Pappadeux; 29.07.2020
comment
@SeverinPappadeux, вы должны прочитать примечание к применению Intel. DRNG может передавать только 800 МБ/с случайности и очищает CF, если случайность отсутствует. Игнорирование этого является распространенной ошибкой реализации, которая не проявляется при тестировании, но проявляется при запуске DRNG под нагрузкой. - person vy32; 30.07.2020
comment
Кстати, не могли бы вы опубликовать весь рабочий пример? Я не могу заставить _rdrand64_step работать в реальной программе. Спасибо! - person vy32; 30.07.2020
comment
@vy32 и еще пару предложений по Carry flag. Я считаю, что встроенный передает это правильно - person Severin Pappadeux; 30.07.2020
comment
Встроенная (и встроенная) функция возвращает результат CF через возвращаемое значение 0 или 1, ничего обрабатывать не нужно. Бессмыслица cmov состоит в том, чтобы материализовать значение флага как целое число 0/1 в регистре (для printf). Это довольно неэффективный подход, глупый gcc/clang! Они используют 0 целочисленный вывод RDRAND для случая сбоя. Это также полностью отделено от возвращаемого значения rc != 1 clang, материализовавшегося обычным способом (xor-zero / rdrand / setc). godbolt.org/z/3e6aYb - person Peter Cordes; 30.07.2020
comment
@vyx32 очень признателен! - person vy32; 31.07.2020