На ум приходят два подхода:
- Возьмите биты, которые содержат целое число, поместите их в переменную, которая должна содержать число с одинаковым количеством битов, и работайте с этими битами, как если бы они были плавающей точкой. Надеюсь, что в оборудовании есть некоторые операции с плавающей запятой, которые работают с этими битами так же, как целочисленные операции, которые использует SHA256.
- Запишите целое число в переменную с плавающей точкой с большим количеством битов (например, поместите Int32 в Double, который может содержать 53 бита без потери точности), а затем реализуйте операцию поворота вправо с помощью математических операций.
Первый вариант вряд ли сработает. Если ваше оборудование основано на стандарте IEEE 754 (наиболее распространенный стандарт для представлений с плавающей точкой), то значения с плавающей запятой сохраняются как битовые поля; например, double имеет один знаковый бит, 11 битов экспоненты и 53 бита дроби. Не будет никаких операций, которые сдвигают значение знакового бита в один из слотов экспонентного бита. И затем есть битовые шаблоны, которые имеют особое значение и несут это значение в течение всей операции, например, NaN и бесконечности. Так что эта идея, вероятно, не является началом.
Я не уверен, что второй подход тоже подойдет; вам понадобится полный контроль над такими вещами, как поведение округления, и вы захотите убедить себя в том, что у вас есть правильное число битов в ваших значениях с плавающей запятой, и вам абсолютно необходимо будет провести целый ряд тестов, чтобы убедить себя, что ожидаемые результаты для всего диапазона входных данных. Но здесь идет.
Операция поворота вправо - скажем, x ror y - прерывается таким образом. Пусть b будет количеством бит в х. Я предполагаю, что все сделано с использованием беззнаковой арифметики, потому что это делает логику намного проще.
- Начнем с
x ror y
.
- Это может быть выражено как сдвиг вправо, сдвиг влево и ИЛИ, как
(x shr y) or (x shl (b - y))
.
- Shr - это то же самое, что делить на степень два. Shr удаляет любые биты, которые падают с нижнего конца, поэтому мы можем эмулировать это, используя функцию floor. Так что теперь у нас есть
floor(x / 2^y) or (x shl (b - y))
.
- ЗЫ - это то же самое, что умножение на степень два. Shl отбрасывает все биты, которые выпадают из верхнего конца, который мы можем эмулировать, выполнив умножение по модулю 2 ^ b. Это дает нам
floor(x / 2^y) or ((x * 2^(b - y)) mod 2^b)
.
- Так как результаты shl и shr не пересекаются (они влияют на разные биты в результате), или можно было бы также сделать с добавлением. Итак, теперь у нас есть математическая запись для всей операции поворота:
floor(x / 2^y) + ((x * 2^(b - y)) mod 2^b)
.
Теперь просто вставьте эту формулу в любое место, где SHA256 выполняет операцию вращения вправо, и посмотрите, быстрее ли она, чем целочисленная арифметика. Это кажется маловероятным, но не невозможным - добавление двух чисел с плавающей запятой с разными показателями потребует быстрых операций сдвига внутри аппаратного обеспечения FP, даже если целочисленное аппаратное обеспечение не имеет быстрых сдвигов.