Encode UINT64 to a float - c#

I have code in C# that converts an UInt64 to a float, the entered value is for example '4537294320117481472'. The code that does the work is in the first block, the second block shows the relevant functions, and the answers are at the bottom.
byte[] rawParameterData = new byte[8];
Console.Write("Enter Value: ");
string rawDataString = Console.ReadLine();
UInt64 rawParameterInteger = UInt64.Parse(rawDataString);
rawParameterData = ConvertFromUInt64(rawParameterInteger);
float convertedParameterData = ConvertToFloat(rawParameterData, 0);
rawParameterData now equals a byte array of [62,247,181,37,0,0,0,0]
convertedParameterData now equals 0.4838039
public static byte[] ConvertFromUInt64(UInt64 data)
{
var databuf = BitConverter.GetBytes(data);
return SwapBytes(databuf, 8); // DIS is big-endian; need to convert to little-endian: least significant byte is at lower byte location.
}
static float ConvertToFloat(byte[] data, int offset)
{
var databuf = CopyData(data, offset, 4);
return BitConverter.ToSingle(databuf, 0);
}
static byte[] SwapBytes(byte[] srcbuf, int datalength)
{
var destbuf = new byte[srcbuf.Length];
for (var i = 0; i < datalength; i++)
destbuf[datalength - 1 - i] = srcbuf[i];
return destbuf;
}
It seems that the code is relying on the BitConverter.ToSingle(databuf, 0) function that is part of C#.
Can this be done in Python? Thanks.

In python, this is as simple as
import struct
a = 4537294320117481472
b = struct.pack('Q', a)
f = struct.unpack('ff', b)
print(f) # (0.0, 0.4838038980960846)
https://docs.python.org/3/library/struct.html

import struct
import math
# We only care about the first 4 of eight of the digits so we
# need to shift by the character size * number of characters
# then we will just have databuf in our significantBits variable
# So we are converting from: 3E F7 B5 25 0 0 0 0 to 3E F7 B5 25
characterWidth = 8
significantBits = 4537294320117481472 >> (characterWidth * 4)
# We can use this python function convert from bits to a float
# Taken from https://stackoverflow.com/a/14431225/825093
def bitsToFloat(b):
s = struct.pack('>l', b)
return struct.unpack('>f', s)[0]
float = bitsToFloat(significantBits)
print(float) # 0.483803898096

Related

Setting bits in a byte array with C#

I have a requirement to encode a byte array from an short integer value
The encoding rules are
The bits representing the integer are bits 0 - 13
bit 14 is set if the number is negative
bit 15 is always 1.
I know I can get the integer into a byte array using BitConverter
byte[] roll = BitConverter.GetBytes(x);
But I cant find how to meet my requirement
Anyone know how to do this?
You should use Bitwise Operators.
Solution is something like this:
Int16 x = 7;
if(x < 0)
{
Int16 mask14 = 16384; // 0b0100000000000000;
x = (Int16)(x | mask14);
}
Int16 mask15 = -32768; // 0b1000000000000000;
x = (Int16)(x | mask15);
byte[] roll = BitConverter.GetBytes(x);
You cannot rely on GetBytes for negative numbers since it complements the bits and that is not what you need.
Instead you need to do bounds checking to make sure the number is representable, then use GetBytes on the absolute value of the given number.
The method's parameter is 'short' so we GetBytes returns a byte array with the size of 2 (you don't need more than 16 bits).
The rest is in the comments below:
static readonly int MAX_UNSIGNED_14_BIT = 16383;// 2^14-1
public static byte[] EncodeSigned14Bit(short x)
{
var absoluteX = Math.Abs(x);
if (absoluteX > MAX_UNSIGNED_14_BIT) throw new ArgumentException($"{nameof(x)} is too large and cannot be represented");
byte[] roll = BitConverter.GetBytes(absoluteX);
if (x < 0)
{
roll[1] |= 0b01000000; //x is negative, set 14th bit
}
roll[1] |= 0b10000000; // 15th bit is always set
return roll;
}
static void Main(string[] args)
{
// testing some values
var r1 = EncodeSigned14Bit(16383); // r1[0] = 255, r1[1] = 191
var r2 = EncodeSigned14Bit(-16383); // r2[0] = 255, r2[1] = 255
}

C#: Create an byte array with int and hex values

I need to create a an byte array with hex and int values.
For example:
int value1 = 13;
int value2 = 31;
byte[] mixedbytes = new byte[] {0x09, (byte)value1, (byte)value2};
Problem: The 31 is converted to 0x1F. It should be 0x31. I've tried to convert the int values to string and back to bytes but that didn't solve the problem. The integers have never more than two digits.
Try this:
int value1 = 0x13;
int value2 = 0x31;
byte[] mixedbytes = new byte[] { 0x09, (byte)value1, (byte)value2 };
Also, you don't seem to understand conversion between decimal and hex. 31 in decimal is 1F in hex, expecting it to be 31 in hex is a bad expectation for a better understanding of the conversion between decimal and hex, please have a look here: http://www.wikihow.com/Convert-from-Decimal-to-Hexadecimal
I think you can try this method
string i = "10";
var b = Convert.ToByte(i, 16)
In this method 10 will be stored as 0x10
This format is commonly known as Binary Coded Decimal (BCD). The idea is that the nibbles in the byte each contain a single decimal digit.
In C#, you can do this conversion very easily:
var number = 31;
var bcd = (number / 10) * 16 + (number % 10);

Convert BitArray to a small byte array

I've read the other posts on BitArray conversions and tried several myself but none seem to deliver the results I want.
My situation is as such, I have some c# code that controls an LED strip. To issue a single command to the strip I need at most 28 bits
1 bit for selecting between 2 led strips
6 for position (Max 48 addressable leds)
7 for color x3 (0-127 value for color)
Suppose I create a BitArray for that structure and as an example we populate it semi-randomly.
BitArray ba = new BitArray(28);
for(int i = 0 ;i < 28; i++)
{
if (i % 3 == 0)
ba.Set(i, true);
else
ba.Set(i, false);
}
Now I want to stick those 28 bits in 4 bytes (The last 4 bits can be a stop signal), and finally turn it into a String so I can send the string via USB to the LED strip.
All the methods I've tried convert each 1 and 0 as a literal char which is not the goal.
Is there a straightforward way to do this bit compacting in C#?
Well you could use BitArray.CopyTo:
byte[] bytes = new byte[4];
ba.CopyTo(bytes, 0);
Or:
int[] ints = new int[1];
ba.CopyTo(ints, 0);
It's not clear what you'd want the string representation to be though - you're dealing with naturally binary data rather than text data...
I wouldn't use a BitArray for this. Instead, I'd use a struct, and then pack that into an int when I need to:
struct Led
{
public readonly bool Strip;
public readonly byte Position;
public readonly byte Red;
public readonly byte Green;
public readonly byte Blue;
public Led(bool strip, byte pos, byte r, byte g, byte b)
{
// set private fields
}
public int ToInt()
{
const int StripBit = 0x01000000;
const int PositionMask = 0x3F; // 6 bits
// bits 21 through 26
const int PositionShift = 20;
const int ColorMask = 0x7F;
const int RedShift = 14;
const int GreenShift = 7;
int val = Strip ? 0 : StripBit;
val = val | ((Position & PositionMask) << PositionShift);
val = val | ((Red & ColorMask) << RedShift);
val = val | (Blue & ColorMask);
return val;
}
}
That way you can create your structures easily without having to fiddle with bit arrays:
var blue17 = new Led(true, 17, 0, 0, 127);
var blah22 = new Led(false, 22, 15, 97, 42);
and to get the values:
int blue17_value = blue17.ToInt();
You can turn the int into a byte array easily enough with BitConverter:
var blue17_bytes = BitConverter.GetBytes(blue17_value);
It's unclear to me why you want to send that as a string.

RC4 Encryption non-alphanumeric wrong

Background: I'm trying to convert Mike Shaffer's VB RC4 encryption to C# (https://web.archive.org/web/20210927195845/https://www.4guysfromrolla.com/articles/091802-1.3.aspx). See a previous question of mine at Converting Mike Shaffer's RC4Encryption to C#.
It seems my encryption is not working.
Using the demo page at: https://web.archive.org/web/20000303125329/http://www.4guysfromrolla.com:80/demos/rc4test.asp, with password of "abc":
Plain text: og;|Q{Fe should result in
A2 FA E2 55 09 A4 AB 16
However, my code is generating the 5th char as 9, instead of 09:
A2 FA E2 55 9 A4 AB 16
Another example - Plain text: cl**z!Ss should result in
AE F1 F3 03 22 FE BE 00
However, my code is generating:
AE F1 F3 3 22 FE BE 0
It seems it's only a problem with certain non-alphanumeric characters.
Here's my code:
private static string EnDeCrypt(string text)
{
int i = 0;
int j = 0;
string cipher = "";
// Call our method to initialize the arrays used here.
RC4Initialize(password);
// Set up a for loop. Again, we use the Length property
// of our String instead of the Len() function
for (int a = 1; a <= text.Length; a++)
{
// Initialize an integer variable we will use in this loop
int itmp = 0;
// Like the RC4Initialize method, we need to use the %
// in place of Mod
i = (i + 1) % 256;
j = (j + sbox[i]) % 256;
itmp = sbox[i];
sbox[i] = sbox[j];
sbox[j] = itmp;
int k = sbox[(sbox[i] + sbox[j]) % 256];
// Again, since the return type of String.Substring is a
// string, we need to convert it to a char using
// String.ToCharArray() and specifying that we want the
// first value, [0].
char ctmp = text.Substring(a - 1, 1).ToCharArray()
[0];
itmp = ctmp; //there's an implicit conversion for char to int
int cipherby = itmp ^ k;
cipher += (char)cipherby; //just cast cipherby to a char
}
// Return the value of cipher as the return value of our
// method
return cipher;
}
public static string ConvertAsciiToHex(string input)
{
return string.Join(string.Empty, input.Select(c => Convert.ToInt32(c).ToString("X")).ToArray());
}
public static string Encrypt(string text)
{
return ConvertAsciiToHex(EnDeCrypt(text));
}
Here's how I get my encrypted result:
var encryptedResult = RC4Encrypt.Encrypt(valuetoencrypt);
The output is correct (leading zeros don't change the value), your code is simply not padding values that fit into a single hex digit (such as 9 or 3 or 0). Use .ToString("X2") instead of .ToString("X").

Fixed length Hash

I'm trying to generate a fixed length hash using the code below.
public int GetStableHash(string s)
{
string strKey = "myHashingKey";
UnicodeEncoding UE = new UnicodeEncoding();
byte[] key = UE.GetBytes(strKey);
byte[] contentBuffer = UE.GetBytes(s);
// Initialize the keyed hash object.
HMACSHA256 myhmacsha256 = new HMACSHA256(key);
byte[] hashValue = myhmacsha256.ComputeHash(contentBuffer);
return BitConverter.ToInt32(hashValue,0);
}
It gives me output like this.
-1635597425
I need a positive number fixed length (8 digits). Can someone plz tell me how to do that.
Thanks in advance.
You're trying to get a 8-digit number from a hash function output which can have up to
lg(2^256) ~ 78
decimal digits.
You should either consider changing hash function or substitute up to 26 bits (2^26 = 67108864, 2^27 = 134217728 - 9 digits already) rounded down to 3 bytes (24 bits) from output and get Int32 from those 3 bytes.
public int GetStableHash(string s)
{
...
byte[] hashValue = myhmacsha256.ComputeHash(contentBuffer);
byte[] hashPart = new byte[3];
hashValue.CopyTo(hashPart, 29); // 32-3
return System.BitConverter.ToInt32(hashPart, 0);
}
unchecked
{
int num = BitConverter.ToInt32(hashValue,0);
if (num < 0)
{
num = -num;
}
num %= 100000000;
}
I'm using the unchecked because otherwise -int.MinValue would break (but note that normally programs are compiled with the unchecked "flag" "on")
The code means:
unchecked
don't do overflow controls
if (num < 0)
{
num = -num;
}
make the number positive if negative
num %= 100000000;
take the remainder (that has 0-8 digits)
much shorter:
return unchecked((int)((uint)BitConverter.ToInt32(hashValue,0) % 100000000));

Categories