如何计算加密中的对数?

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

log 45 (201)= 1.39316393

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

我怎么处理这个?

密码学通常使用素数域,在本例中为GF(257)。 创建一个如下所示的取幂表 :

 exp | 日志
 ---- + ----
   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文档中猜测;数据类型可能存在错误。)

所以你有一个字节值(从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%。

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

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

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

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

这不是一个真正的答案,但是观看这个问题的用户中有一小部分可能会对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类。