如何计算密码学中的对数?

发布于 2024-12-19 01:19:09 字数 174 浏览 5 评论 0原文

我正在尝试对字节执行非线性函数来实现 SAFER+。该算法需要计算字节的以 45 为底的对数,我不明白如何做到这一点。

log45(201) = 1.39316393

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

我该怎么处理这个事情?

I am trying to perform non-linear functions on bytes to implement SAFER+. The algorithm requires computing base-45 logarithm on bytes, and I don't understand how to do it.

log45(201) = 1.39316393

When I assign this to a byte, the value is truncated to 1, and I can't recover the exact result.

How am I supposed to handle this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

那请放手 2024-12-26 01:19:09

密码学经常使用 素数域,在本例中为 GF(257)。 <一href="http://books.google.com/books?id=_g-fDjmi1xAC&pg=PA60&lpg=PA60&dq=field%2045%20257%20safer%2b&source=bl&ots=pxx5Qxhvx3& ;sig=Js7MaBkdiyeLdCOeMXBcAIsXVUU&hl=en&ei=yyvZTrX5A5TciQL1uPC7Bg&sa=X&oi=book_result&ct=结果&resnum=1&ved=0CBwQ6AEwAA" rel="nofollow">创建一个指数表,如下所示:

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

“log”值为 45exp % 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;

例如,使用此设置,log45(131) = log[131] = 63 和 4538 = exp[38] = 59。

(我从未编写过 C#;我只是从 BigInteger 文档可能有;数据类型错误。)

Cryptography often uses prime fields, in this case, GF(257). Create an exponentiation table that looks like this:

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

The "log" values are 45exp % 257. You'll need an arbitrary precision arithmetic library with a modPow function (raise a number to a power, modulo some value) to build this table. You can see that the value for "exp" 128 is a special case, since normally the logarithm of zero is undefined.

Compute the logarithm of a number by finding the it in the "log" column; the value in the "exp" column of that row is the logarithm.

Here's a sketch of the initialization:

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;

With this setup, for example, log45(131) = log[131] = 63, and 4538 = exp[38] = 59.

(I've never written C#; I'm just guessing from the BigInteger documentation; there are likely to be errors with the data types.)

嘴硬脾气大 2024-12-26 01:19:09

那么您有一个字节值(从 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%。

So you have a byte value (from 0 to 255), and you want to get the log base 45, and store it in another byte? As others have said, you're going to lose some accuracy in doing that. However, you can do better than just casting the double result to a byte.

The log base 45 of 255 is approximately 1.455675. You can store that in a byte, with some loss of accuracy, by multiplying it by a constant factor. What constant factor? You could use 100, which would give you a value of 145, but you're losing almost half the range of a byte. Since the largest value you want to represent is 1.455675, you can use a constant multiplier of 255/log45(255), or about 175.176.

How well does this work? Let's see ...

        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);

Under .NET 4 on my machine, that gives me a maximum error of 2.1419%, and an average error of 1.0501%.

You can reduce the average error by rounding the result from Math.Pow. That is:

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

That reduces the average error to 0.9300%, but increases the maximum error to 3.8462%.

热情消退 2024-12-26 01:19:09

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

如果您想存储非整数,您不想将其放入字节中,因为这会截断它(如您所见)。相反,将结果存储为双精度或更合适的形式:

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

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

Showing us the code might help but I suspect your problem comes from storing the result.

If you want to store a non-integer number you don't want to put it into a byte since that will truncate it (as you are seeing). Instead store the result in a double or something more appropriate:

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

I should add that I'm not sure what SAFER+ is so this answer may not be helpful but hopefully it should point you in the right direction.

眼眸印温柔 2024-12-26 01:19:09

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

This is not really an answer, but a fraction of the users viewing this question will probably be interrested in the conversion of a double type to a byte[] type.
What could be done is simply:

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

and

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

this uses the BitConverter class which I believe exists in .NET initialy.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文