如何计算加密中的对数?

时间:2011-12-02 17:08:18

标签: c# math cryptography logarithm galois-field

我试图在字节上执行非线性函数来实现SAFER +。该算法需要计算基数为45的字节对数,我不明白该怎么做。

log 45 (201)= 1.39316393

当我将其分配给一个字节时,该值被截断为1,我无法恢复确切的结果。

我该怎么办呢?

4 个答案:

答案 0 :(得分:4)

在这种情况下,密码术经常使用prime fields,,GF(257)。 Create an exponentiation table看起来像这样:

exp | log
----+----
  0 |   1
  1 |  45
  2 | 226
  3 | 147
... | ...
128 |   0
... | ...
255 |  40
---------

“log”值为45 exp %257。您需要一个具有modPow函数的任意精度算术库(将数字提升为幂,以某个值为模)建立这个表。您可以看到“exp”128的值是一种特殊情况,因为通常零的对数是未定义的。

通过在“log”列中找到它来计算数字的对数;该行的“exp”列中的值是对数。

这是初始化草图:

BigInteger V45 = new BigInteger(45);
BigInteger V257 = new BigInteger(257);
byte[] exp = new byte[256];
for (int idx = 0; idx < 256; ++idx)
  exp[idx] = BigInteger.ModPow(V45, new BigInteger(idx), V257) % 256;
byte[] log = new byte[256];
for (int idx = 0; idx < 256; ++idx)
  log[exp[idx]] = idx;

通过此设置,例如,log 45 (131)= log[131] = 63,并且45 38 = exp[38] = 59。

(我从未写过C#;我只是在BigInteger文档中猜测;数据类型可能存在错误。)

答案 1 :(得分:1)

所以你有一个字节值(从0到255),你想获得日志基数45,并将其存储在另一个字节中?正如其他人所说,你这样做会失去一些准确性。但是,您可以做的不仅仅是将double结果转换为byte

255的对数基数45约为1.455675。您可以通过将其乘以常数因子将其存储在一个字节中,但精度会有所降低。什么常数因素?你可以使用100,它会给你145的值,但你几乎失去了一个字节的一半范围。由于您要表示的最大值为1.455675,因此您可以使用255/log45(255)的常数乘数,或约175.176。

这有多好?我们看看......

        var mult = 255.0 / Math.Log(255, 45);
        Console.WriteLine("Scaling factor is {0}", mult);
        double errMax = double.MinValue;
        double errMin = double.MaxValue;
        double errTot = 0;
        for (int i = 1; i < 256; ++i)
        {
            // Get the log of the number you want
            var l = Math.Log(i, 45);

            // Convert to byte
            var b = (byte)(l * mult);

            // Now go back the other way.
            var a = Math.Pow(45, (double)b / mult);

            var err = (double)(i - a) / i;
            errTot += err;
            errMax = Math.Max(errMax, err);
            errMin = Math.Min(errMin, err);
            Console.WriteLine("{0,3:N0}, {1,3:N0}, {2}, {3:P4}", i, b, a, err);
        }
        Console.WriteLine("max error = {0:P4}", errMax);
        Console.WriteLine("min error = {0:P4}", errMin);
        Console.WriteLine("avg error = {0:P4}", errTot / 255);

在我的机器上的.NET 4下,最大误差为2.1419%,平均误差为1.0501%。

您可以通过舍入Math.Pow的结果来减少平均错误。那就是:

var a = Math.Round(Math.Pow(45, (double)b / mult));

将平均误差降低到0.9300%,但将最大误差增加到3.8462%。

答案 2 :(得分:0)

向我们展示代码可能有所帮助,但我怀疑您的问题来自存储结果。

如果你想存储一个非整数,你不想把它放到一个字节中,因为那会截断它(如你所见)。而是将结果存储为双精度或更合适的结果:

double result = math.log(154,45);

我应该补充一点,我不确定SAFER +是什么,所以这个答案可能没有帮助,但希望它能指出你正确的方向。

答案 3 :(得分:0)

这不是一个真正的答案,但是在查看此问题的用户中,有一部分可能会对将double类型转换为byte[]类型感兴趣。 可以做的只是:

double theDouble = 78.24435;
byte[] theResult = BitConverter.GetBytes(theDouble);

byte[] theByteArray = new byte[]{0, 4, 2, 3}; //for example
double theCorrespondingDouble = BitConverter.ToDouble(theByteArray);

这使用我认为最初存在于.NET中的BitConverter类。