Reputation: 1059
Motivation: I would like to convert hashes (MD5/SHA1 etc) into decimal integers for the purpose of making barcodes in Code128C. For simplicity, I prefer all the resulting (large) numbers to be positive.
I am able to convert byte[] to BigInteger in C#...
Sample from what I have so far:
byte[] data;
byte[] result;
BigInteger biResult;
result = shaM.ComputeHash(data);
biResult = new BigInteger(result);
But (rusty CS here) am I correct that a byte array can always be interpreted in two ways:
Is it possible to make an UNSIGNED BigInteger from a byte[] in C#?
Should I simply prepend a 0x00 (zero byte) to the front of the byte[]?
EDIT: Thank you to AakashM, Jon and Adam Robinson, appending a zero byte achieved what I needed.
EDIT2: The main thing I should have done was to read the detailed doc of the BigInteger(byte[]) constructor, then I would have seen the sections about how to restrict to positive numbers by appending the zero byte.
Upvotes: 30
Views: 18772
Reputation: 101
Since .NET Core 2.1, BigInteger
has a constructor with an optional parameter isUnsigned
:
public BigInteger (ReadOnlySpan<byte> value, bool isUnsigned = false, bool isBigEndian = false);
Upvotes: 9
Reputation: 935
As other answers have pointed out, you should append a 00 byte to the end of the array to ensure the resulting BigInteger is positive.
According to the the BigInteger Structure (System.Numerics) MSDN Documentation
To prevent the BigInteger(Byte[]) constructor from confusing the two's complement representation of a negative value with the sign and magnitude representation of a positive value, positive values in which the most significant bit of the last byte in the byte array would ordinarily be set should include an additional byte whose value is 0.
Here's code to do it:
byte[] byteArray;
// ...
var bigInteger = new BigInteger(byteArray.Concat(new byte[] { 0 }).ToArray());
Upvotes: 6
Reputation: 63338
Examining the documentation for the relevant BigInteger
constructor, we see:
The individual bytes in the value array should be in little-endian order, from lowest-order byte to highest-order byte
[...]
The constructor expects positive values in the byte array to use sign-and-magnitude representation, and negative values to use two's complement representation. In other words, if the highest-order bit of the highest-order byte in value is set, the resulting BigInteger value is negative. Depending on the source of the byte array, this may cause a positive value to be misinterpreted as a negative value.
[...]
To prevent positive values from being misinterpreted as negative values, you can add a zero-byte value to the end of the array.
Upvotes: 6
Reputation: 437366
The remarks for the BigInteger
constructor state that you can make sure any BigInteger
created from a byte[]
is unsigned if you append a 00
byte to the end of the array before calling the constructor.
Note: the BigInteger
constructor expects the array to be in little-endian order. Keep that in mind if you expect the resulting BigInteger
to have a particular value.
Upvotes: 39
Reputation: 185643
But (rusty CS here) am I correct that a byte array can always be interpreted in two ways: A: as a signed number B: as an unsigned number
What's more correct is that all numbers (by virtue of being stored in the computer) are basically a series of bytes, which is what a byte array is. It's not true to say that a byte array can always be interpreted as a signed or unsigned version of a particular numeric type, as not all numeric types have signed and unsigned versions. Floating point types generally only have signed versions (there's no udouble
or ufloat
), and, in this particular instance, there is no unsigned version of BigInteger
.
So, in other words, no, it's not possible, but since BigInteger
can represent an arbitrarily large integer value, you're not losing any range by virtue of its being signed.
As to your second question, you would need to append 0x00
to end end of the array, as the BigInteger
constructor parses the values in little-endian byte order.
Upvotes: 4