如何计算加密中的对数?
我试图在字节上执行非线性函数来实现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
类。