CPU-функции RDRAND и RDSEED стали доступнее

в 22:28, , рубрики: Delphi, RDRAND. RDSEED, ассемблер, генератор случайных чисел, ГСЧ, криптография

Всем привет!

Сам я криптографией не занимаюсь, но кому то вполне может пригодится мое небольшое исследование. Решил разобраться со встроенными в процессор функциями RDRAND и RDSEED. Компилятор Delphi сказал Undeclared identifier. Хмм. Уже давно существует BMI, BMI2, AVX, AVX2 и даже AVX-512, а дельфийцы остановились на SSE4.2. Не беда. Скомпилируем код сами.

Сначала сделал проверку на поддержку данных функций процессором. Конечно же CPUID. Использовать CPUID можно начиная с первых Pentium процессоров. Надеюсь никто не додумается запустить CPUID на 486 машине, ибо ее там еще не было. Кстати RDRAND и RDSEED до процессоров IvyBridge также не существует.

function CPU_support_RDRAND: Boolean;
asm
  mov rax, $01
  cpuid
  test ecx, 40000000h //тестируем 30-й бит
  setne al
end;

function CPU_support_RDSEED: Boolean;
asm
  mov rcx, 0
  mov rax, $07 //страница №7
  cpuid
  test ebx, 40000h //тестируем 18-й бит
  setne al
end;

Оказалось, что мой Core i7 G6950X Extreme поддерживает данные функции. Поэтому дальше решил скомпилировать байт-код вручную. Для опытных приведу код REX и REX.W префиксов. Возможно вы захотите записать результат в другой регистр:

const
  REX_RDRAND32: Byte = $F0; //(11b:REG, 110b:OPCODE, 000b:EAX) 
  REX_RDSEED32: Byte = $F8; //(11b:REG, 111b:OPCODE, 000b:EAX)
  REX_W_RDRAND64: Byte = $48; //(11b:REG, 110b:OPCODE, 000b:RAX)
  REX_W_RDSEED64: Byte = $48; //(11b:REG, 111b:OPCODE, 000b:RAX)


Функции могут работать как в 32-х битном режиме, так и в 64-х битном. Поэтому сделал обе и даже в двух вариантах. В итоге получилось 4 функции:

function RDRand32: DWord;
asm
 @Retry:
  db $0F, $C7, $F0 //RDRAND EAX (CF = 1 говорит о корректности данных)
  jnc @Retry
end;

function RDSeed32: DWord;
asm
 @Retry:
  db $0F, $C7, $F8 //RDSEED EAX (CF = 1 говорит о корректности данных)
  jnc @Retry
end;

function RDRand64: QWord;
asm
  .NOFRAME

 @Retry:
  db $48, $0F, $C7, $F0  //RDRAND RAX (CF = 1 говорит о корректности данных)
  jnc @Retry
end;

function RDSeed64: QWord;
asm
  .NOFRAME

 @Retry:
  db $48, $0F, $C7, $F8 //RDSEED RAX (CF = 1 говорит о корректности данных)
  jnc @Retry
end;

По скорости они медленней, чем библиотечная функция Random. RDRand примерно на 35%, а RDSeed процентов на 50% и даже более, но качество уникальности генерируемых значений значительно выше. На данном ресурсе есть неплохие статьи на эту тему, ну а моя миссия (сделать функции доступными в Delphi) завершена. В Lazarus не тестировал, но скорее всего будет работать без каких либо изменений. В конец объявления функции нужно лишь добавить резервное слово assembler.

Здесь исходные тексты тестового консольного приложения. Там можно найти прототип функций Random32 и Random64 на основе встроенных в процессор. Возможно это то, что вы искали. Всем пока!

Автор: eDmk

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js