0

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?

erickson
  • 265,237
  • 58
  • 395
  • 493
Eng. Aws
  • 169
  • 1
  • 2
  • 7
  • 1
    A byte has 256 possible values. How do you expect eight or nine decimals of an irrational value to fit? – David Thornley Dec 02 '11 at 17:34
  • do you have some requirement or restriction that would prevent you from using a float or double? Using bytes to store floating point numbers is a real pain, it's best to use .Net's built in types for storing those types of numbers. – Neil N Dec 02 '11 at 17:40
  • my situation is as follows: 1- i have to make XOR for 8 bytes and addition for another 8 Bytes. 2- i need to make Power base 45 to 8 bytes and Log base 45 to another 8 Bytes. 3- the result of the previous stage should be treated with XOR and Addition also. 4- i need to Make a Byte matrices Multiplication. and this is mentioned in the algorithm data sheet, so i need to keep wroking with Bytes – Eng. Aws Dec 02 '11 at 17:51
  • In that case, do something else. You can't possibly put a non-integral algorithm into a byte with any sort of accuracy, since you're limited to integer values from 0 to 255 or -128 to 127. Why this preoccupation with using bytes? – David Thornley Dec 02 '11 at 18:14
  • @DavidThornley You're thinking about exponentiation in the [field](http://en.wikipedia.org/wiki/Field_%28mathematics%29) of real numbers, which is just one of many, and not the one in question. – erickson Dec 02 '11 at 20:14
  • @erickson: Yes, given no hint to the contrary I assumed real numbers. What ring or field are we exponentiating in, such that we get that result? Note that the tags are "c#", "math", "byte", and "logarithm", and last I looked it was customary to assume real numbers in mathematics unless otherwise stated. – David Thornley Dec 02 '11 at 20:32
  • @DavidThornley My hint was SAFER+. You can read more about the field in my answer. – erickson Dec 02 '11 at 20:36
  • @erickson: I, among other people, saw SAFER+, didn't know what it was, and didn't realize it was significant. Now, what's the OP doing implementing a cryptosystem (and one that wasn't an AES finalist), without having a clue about discrete logs in modular arithmetic? Either this is an exercise of some sort or this isn't going to end well. – David Thornley Dec 02 '11 at 20:52
  • @DavidThornley If I had to guess, I would agree with you, but I'm just here to answer questions. I was looking for help with this a few years ago, and would have been happy to find an answer like the one I gave. If not Eng. Aws with SAFER+, hopefully someone else will benefit. – erickson Dec 02 '11 at 21:02

4 Answers4

4

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

erickson
  • 265,237
  • 58
  • 395
  • 493
  • 1
    Thank you so much, this is what i was seeking for, thanks again. – Eng. Aws Dec 03 '11 at 17:13
  • Actually, for `mod 256` one doesn't really need *arbitrary precision* (as one-byte precision is already enough). Though it might be more comfortable (and efficient) to use an existing `ModPow` function than implementing it oneself. – Paŭlo Ebermann Dec 04 '11 at 15:58
  • Yes, see [here](http://stackoverflow.com/q/8287144/3474) for an implementation. On .NET there's no reason to implement yourself though. – erickson Dec 05 '11 at 02:22
1

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%.

Jim Mischel
  • 131,090
  • 20
  • 188
  • 351
0

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.

Samuel Allan
  • 392
  • 2
  • 20
0

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.

Chris
  • 27,210
  • 6
  • 71
  • 92
  • this is the problem exactly, what i need to do is to keep it in a byte array brcause later i will need to make a byte by byte xor or addtion then i will have to make mertrices multiplication. so this is my problem in fact. – Eng. Aws Dec 02 '11 at 17:44
  • Can you not store things as doubles in intermediate steps? At the end of the day you will never get a fractional number into a byte, you have to use another data-type. I can't say I understand why you are taking base 45 logs of things but maybe you can rearrange the maths to remove the logs? I see you are talking about doign exponents as well as logs so maybe the maths can be made so that you don't need to worry abotu these after all? Then you might be able to stick in bytes.... – Chris Dec 02 '11 at 18:38