writing an 8 bit checksum in C [closed] - c

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I am having trouble writing an algorithm for a 1byte / 8 bit checksum.
Obviously with 8bits over a decimal value of 255 the Most significant bits have to wrap around. I think I am doing it correctly.
Here is the code...
#include <stdio.h>
int main(void)
{
int check_sum = 0; //checksum
int lcheck_sum = 0; //left checksum bits
int rcheck_sum = 0; //right checksum bits
short int mask = 0x00FF; // 16 bit mask
//Create the frame - sequence number (S) and checksum 1 byte
int c;
//calculate the checksum
for (c = 0; c < length; c++)
{
check_sum = (int)buf[c] + check_sum;
printf("\n Check Sum %d ", check_sum); //debug
}
printf("\nfinal Check Sum %d", check_sum); //debug
//Take checksum and make it a 8 bit checksum
if (check_sum > 255) //if greater than 8 bits then encode bits
{
lcheck_sum = check_sum;
lcheck_sum >> 8; //shift 8 bits to the right
rcheck_sum = check_sum & mask;
check_sum = lcheck_sum + rcheck_sum;
}
//Take the complement
check_sum = ~check_sum;
//Truncate - to get rid of the 8 bits to the right and keep the 8 LSB's
check_sum = check_sum & mask;
printf("\nTruncated and complemented final Check Sum %d\n",check_sum);
return 0;
}

Short answer: you are not doing it correctly, even if the algorithm would be as your code implies (which is unlikely).
Standard warning: Do not use int if your variable might wrap (undefined behaviour) or you want to right-shift potentially negative values (implementation defined). OTOH, for unsigned types, wrapping and shifting behaviour is well defined by the standard.
Further note: Use stdint.h types if you need a specific bit-size! The built-in standard types are not guaranteed (including char) to provide such.
Normally an 8 bit checksum of an 8 bit buffer is calculated as follows:
#include <stdint.h>
uint8_t chksum8(const unsigned char *buff, size_t len)
{
unsigned int sum; // nothing gained in using smaller types!
for ( sum = 0 ; len != 0 ; len-- )
sum += *(buff++); // parenthesis not required!
return (uint8_t)sum;
}
It is not clear what you are doing with all the typecasts or shifts; uint8_t as being guaranteed the smallest (unsigned) type, the upper bits are guaranteed to be "cut off".
Just compare this and your code and you should be able to see if your code will work.
Also note that there is not the single checksum algorithm. I did not invert the result in my code, nor did I fold upper and lower bytes as you did (the latter is pretty uncommon, as it does not add much more protection).
So, you have to verify the algorithm to use. If that really requires to fold the two bytes of a 16 bit result, change sum to uint16_t` and fold the bytes as follows:
uint16_t sum;
...
// replace return with:
while ( sum > 0xFFU )
sum = (sum & 0xFFU) + ((sum >> 8) & 0xFFU);
return sum;
This cares about any overflow from adding the two bytes of sum (the loop could also be unrolled, as the overflow can only occur once).
Sometimes, CRC algorithms are called "checksum", but these are actually a very different beast (mathematically, they are the remainder of a binary polynomial division) and require much more processing (either at run-time, or to generate a lookup-table). OTOH, CRCs provide a much better detection of data corruption - but not to manipulation.

Related

How to store a binary string into uint8_t array bits? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 months ago.
Improve this question
I have binary string( only 0s or 1s) "0101011111011111000001001001110110", for Huffman encoding I want to store each char in the string as bit representation in a uint8_t array.
If I write the binary string as-is into a file it occupies 35 bytes. If we can store each binary char in the string as bit representation in uint8_t array, it can be stored in ~5 bytes.
static uint8_t out_buffer[1024];
static uint32_t bit_pos = 0;
void printbuffer()
{
printf("Just printing bits\n");
int i;
for (i = 0; i < bit_pos; i++) {
printf("%c", (out_buffer[i / 8] & 1 << (i % 8)) ? '1' : '0');
}
}
void append_to_bit_array(char* in, int len, uint8_t* buf)
{
int i;
printbuffer();
for (i = 0; i < len; i++) {
if (in[i])
{
buf[bit_pos / 8] |= 1 << (bit_pos % 8);
}
bit_pos++;
}
}
You need to first decide on what order you want to put the bits in the bytes — i.e. put the first bit in the most significant bit of the first byte, or the least? You also need to have a strategy to deal with the extra 0 to 7 bits in the last byte. Those could look like another Huffman code, and give you extraneous symbols when decoding. Either you will need a count of symbols to decode, or you will need an end symbol that you add to your set before Huffman coding, and send that symbol at the end.
Learn the bitwise operators in C noted in your tag, and use those to place each bit, one by one, into the sequence of bytes. Those are at least the shifts << and >>, and &, and or |.
For example, 1 << n gives you a one bit in position n. a |= 1 << n would set that bit in a, given that a is initialized to zero. On the decoding end, you can use & to see if a bit is set. E.g. a & (1 << n) would be non-zero if bit n in a is set.

CRC-15 giving wrong values

I am trying to create a CRC-15 check in c and the output is never correct for each line of the file. I am trying to output the CRC for each line cumulatively next to each line. I use: #define POLYNOMIAL 0xA053 for the divisor and text for the dividend. I need to represent numbers as 32-bit unsigned integers. I have tried printing out the hex values to keep track and flipping different shifts around. However, I just can't seem to figure it out! I have a feeling it has something to do with the way I am padding things. Is there a flaw to my logic?
The CRC is to be represented in four hexadecimal numbers, that sequence will have four leading 0's. For example, it will look like 0000xxxx where the x's are the hexadecimal digits. The polynomial I use is 0xA053.
I thought about using a temp variable and do 4 16 bit chunks of code per line every XOR, however, I'm not quite sure how I could use shifts to accomplish this so I settled for a checksum of the letters on the line and then XORing that to try to calculate the CRC code.
I am testing my code using the following input and padding with . until the string is of length 504 because that is what the pad character needs to be via the requirements given:
"This is the lesson: never give in, never give in, never, never, never, never - in nothing, great or small, large or petty - never give in except to convictions of honor and good sense. Never yield to force; never yield to the apparently overwhelming might of the enemy."
The CRC of the first 64 char line ("This is the lesson: never give in, never give in, never, never,) is supposed to be 000015fa and I am getting bfe6ec00.
My logic:
In CRCCalculation I add each character to a 32-bit unsigned integer and after 64 (the length of one line) I send it into the XOR function.
If it the top bit is not 1, I shift the number to the left one
causing 0s to pad the right and loop around again.
If the top bit is 1, I XOR the dividend with the divisor and then shift the dividend to the left one.
After all calculations are done, I return the dividend shifted to the left four ( to add four zeros to the front) to the calculation function
Add result to the running total of the result
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <ctype.h>
#define POLYNOMIAL 0xA053
void crcCalculation(char *text, int length)
{
int i;
uint32_t dividend = atoi(text);
uint32_t result;
uint32_t sumText = 0;
// Calculate CRC
printf("\nCRC 15 calculation progress:\n");
i = length;
// padding
if(i < 504)
{
for(; i!=504; i++)
{
// printf("i is %d\n", i);
text[i] = '.';
}
}
// Try calculating by first line of crc by summing the values then calcuating, then add in the next line
for (i = 0; i < 504; i++)
{
if(i%64 == 0 && i != 0)
{
result = XOR(POLYNOMIAL, sumText);
printf(" - %x\n",result);
}
sumText +=(uint32_t)text[i];
printf("%c", text[i]);
}
printf("\n\nCRC15 result : %x\n", result);
}
uint32_t XOR(uint32_t divisor, uint32_t dividend)
{
uint32_t divRemainder = dividend;
uint32_t currentBit;
// Note: 4 16 bit chunks
for(currentBit = 32; currentBit > 0; --currentBit)
{
// if topbit is 1
if(divRemainder & 0x80)
{
//divRemainder = (divRemainder << 1) ^ divisor;
divRemainder ^= divisor;
printf("%x %x\n", divRemainder, divisor);
}
// else
// divisor = divisor >> 1;
divRemainder = (divRemainder << 1);
}
//return divRemainder; , have tried shifting to right and left, want to add 4 zeros to front so >>
//return divRemainder >> 4;
return divRemainder >> 4;
}
The first issue I see is the top bit check, it should be:
if(divRemainder & 0x8000)
The question doesn't state if the CRC is bit reflected (xor data into low order bits of CRC, right shift for cycle) or not (xor data into high order bits of CRC, left shift for cycle), so I can't offer help for the rest of the code.
The question doesn't state the initial value of CRC (0x0000 or 0x7fff), or if the CRC is post complemented.
The logic for a conventional CRC is:
xor a byte of data into the CRC (upper or lower bits)
cycle the CRC 8 times (or do a table lookup)
After generating the CRC for an entire message, the CRC can be appended to the message. If a CRC is generated for a message with the appended CRC and there are no errors, the CRC will be zero (or a constant value if the CRC is post complemented).
here is a typical CRC16, extracted from: <www8.cs.umu.se/~isak/snippets/crc-16.c>
#define POLY 0x8408
/*
// 16 12 5
// this is the CCITT CRC 16 polynomial X + X + X + 1.
// This works out to be 0x1021, but the way the algorithm works
// lets us use 0x8408 (the reverse of the bit pattern). The high
// bit is always assumed to be set, thus we only use 16 bits to
// represent the 17 bit value.
*/
unsigned short crc16(char *data_p, unsigned short length)
{
unsigned char i;
unsigned int data;
unsigned int crc = 0xffff;
if (length == 0)
return (~crc);
do
{
for (i=0, data=(unsigned int)0xff & *data_p++;
i < 8;
i++, data >>= 1)
{
if ((crc & 0x0001) ^ (data & 0x0001))
crc = (crc >> 1) ^ POLY;
else crc >>= 1;
}
} while (--length);
crc = ~crc;
data = crc;
crc = (crc << 8) | (data >> 8 & 0xff);
return (crc);
}
Since you want to calculate a CRC15 rather than a CRC16, the logic will be more complex as cannot work with whole bytes, so there will be a lot of bit shifting and ANDing to extract the desire 15 bits.
Note: the OP did not mention if the initial value of the CRC is 0x0000 or 0x7FFF, nor if the result is to be complemented, nor certain other criteria, so this posted code can only be a guide.

C - Stripping least significant byte [duplicate]

This question already has answers here:
What does least significant byte mean?
(4 answers)
Closed 7 years ago.
I am working on an assignment and it is asking me to calculate a checksum by stripping off the least significant byte of a ones complement version of an integer...
This is the part of the assignment outline I am confused by:
"The CHECKSUM field (MM) value is calculated by taking the least significant byte of the 1’s Complement value of the sum of the COUNT, ADDRESS
and DATA fields of the record"
Im a little bit unclear on what this means, as I haven't really worked with ones complements or LSB's in C.
What I have so far is:
int checkSum(int count, int address, char* data)
{
int i = 0;
int dataTotal = 0;
for(i = 0; i < strlen(data); i += 2)
{
dataTotal += (getIntFromHex(data[i]) * 16) + getIntFromHex(data[i + 1]);
}
int checksum = ~(count + address + dataTotal) & 1;
printf("Checksum: %.2X\n", checksum);
return checksum;
}
I didn't really expect this to work but I've done some research and this is what I came up with.
I need some clarification on what is meant by the least significant byte.
P.S. The reason for the for loop is simply just to get the total of the data. Not important for this but the code uses the variable so I figured I would just copy the whole thing to avoid confusion.
I need some clarification on what is meant by the least significant byte.
The last significant byte means the number mod 256, a result from zero to 255.
unsigned leastSignificantByte(unsigned j)
{
return j & 0xff;
}

Internet Checksum function move 8bits or not

This is my implementation of the Internet Checksum (RFC 1071):
static unsigned short
compute_checksum(unsigned short *addr, unsigned int count) {
register unsigned long sum = 0;
while (count > 1) {
sum += * addr++;
count -= 2;
}
//if any bytes left, pad the bytes and add
if(count > 0) {
sum+=*(unsigned char*)addr;// left move 8 bits or not?
}
//Fold sum to 16 bits: add carrier to result
while (sum>>16) {
sum = (sum & 0xffff) + (sum >> 16);
}
//one's complement
sum = ~sum;
return ((unsigned short)sum);
}
when meet the odd byte, why we don't need left move 8 bits like this,and RFC does't left move 8 bits too. why? I think this is right one
sum += (*(unsigned char*)addr << 8) & 0xFF00;
The code you posted from the RFC is correct for a littleendian machine. On a bigendian machine, your shifted solution would be necessary.
With an odd number of bytes, a (theoretical) 0 byte is added on to the end of the sequence. So the last byte XX should be treated as a short with byte sequence XX 00, which needs to be handled differently depending on the endianness of your machine.
Here's one way to handle it correctly for either endianness:
if (count > 0) {
unsigned char temp[2];
temp[0] = *(unsigned char *) addr;
temp[1] = 0;
sum += *(unsigned short *) temp;
}
For those of you who don't believe the RFC code is wrong, I refer you to this linux source, where it is clear that the littleendian case and the bigendian case must be treated differently in the way I described. The linux code is a little more complicated because it handles unaligned buffers.
Short is at-least 16 bits, there's no guarantee that' it's not 32 or 64 bits.
you should be using uint_16t from <stdint.h>
you kind of need to shift, the last add would be
{
uint16_t tmp=0;
memcpy(addr,&tmp,1);
sum += tmp;
}
which preserves the alignment, so, on a little endian machhine that's not shifted
but on a big-endian it is compared to it's aligment as a char.
sum += ( *addr && *((uint16_t*)"\xff"));
but that code may not work unless you have some trick to word-align the string.
Be aware that the result is in network byte order, so
if you need it in host byte order use the
ntohs() function to convert it.
foo=compute_checksum(blah,blah_size);
printf("the internet checksum is %04h\n",(int)ntohs(foo));

Bitwise memmove

What is the best way to implement a bitwise memmove? The method should take an additional destination and source bit-offset and the count should be in bits too.
I saw that ARM provides a non-standard _membitmove, which does exactly what I need, but I couldn't find its source.
Bind's bitset includes isc_bitstring_copy, but it's not efficient
I'm aware that the C standard library doesn't provide such a method, but I also couldn't find any third-party code providing a similar method.
Assuming "best" means "easiest", you can copy bits one by one. Conceptually, an address of a bit is an object (struct) that has a pointer to a byte in memory and an index of a bit in the byte.
struct pointer_to_bit
{
uint8_t* p;
int b;
};
void membitmovebl(
void *dest,
const void *src,
int dest_offset,
int src_offset,
size_t nbits)
{
// Create pointers to bits
struct pointer_to_bit d = {dest, dest_offset};
struct pointer_to_bit s = {src, src_offset};
// Bring the bit offsets to range (0...7)
d.p += d.b / 8; // replace division by right-shift if bit offset can be negative
d.b %= 8; // replace "%=8" by "&=7" if bit offset can be negative
s.p += s.b / 8;
s.b %= 8;
// Determine whether it's OK to loop forward
if (d.p < s.p || d.p == s.p && d.b <= s.b)
{
// Copy bits one by one
for (size_t i = 0; i < nbits; i++)
{
// Read 1 bit
int bit = (*s.p >> s.b) & 1;
// Write 1 bit
*d.p &= ~(1 << d.b);
*d.p |= bit << d.b;
// Advance pointers
if (++s.b == 8)
{
s.b = 0;
++s.p;
}
if (++d.b == 8)
{
d.b = 0;
++d.p;
}
}
}
else
{
// Copy stuff backwards - essentially the same code but ++ replaced by --
}
}
If you want to write a version optimized for speed, you will have to do copying by bytes (or, better, words), unroll loops, and handle a number of special cases (memmove does that; you will have to do more because your function is more complicated).
P.S. Oh, seeing that you call isc_bitstring_copy inefficient, you probably want the speed optimization. You can use the following idea:
Start copying bits individually until the destination is byte-aligned (d.b == 0). Then, it is easy to copy 8 bits at once, doing some bit twiddling. Do this until there are less than 8 bits left to copy; then continue copying bits one by one.
// Copy 8 bits from s to d and advance pointers
*d.p = *s.p++ >> s.b;
*d.p++ |= *s.p << (8 - s.b);
P.P.S Oh, and seeing your comment on what you are going to use the code for, you don't really need to implement all the versions (byte/halfword/word, big/little-endian); you only want the easiest one - the one working with words (uint32_t).
Here is a partial implementation (not tested). There are obvious efficiency and usability improvements.
Copy n bytes from src to dest (not overlapping src), and shift bits at dest rightwards by bit bits, 0 <= bit <= 7. This assumes that the least significant bits are at the right of the bytes
void memcpy_with_bitshift(unsigned char *dest, unsigned char *src, size_t n, int bit)
{
int i;
memcpy(dest, src, n);
for (i = 0; i < n; i++) {
dest[i] >> bit;
}
for (i = 0; i < n; i++) {
dest[i+1] |= (src[i] << (8 - bit));
}
}
Some improvements to be made:
Don't overwrite first bit bits at beginning of dest.
Merge loops
Have a way to copy a number of bits not divisible by 8
Fix for >8 bits in a char

Resources