SORT BY:

LIST ORDER
THREAD
AUTHOR
SUBJECT


SEARCH

IPS HOME


    [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

    CRC32C code -- please check



    Here is some C code at the end, the draft quoted and my
    notes alongside it.
    
    Please tell me where and what is wrong with the
    interpretation, logic, etc.
    
    > Padding bytes, when present, in a segment covered by a
    > CRC, should be set to 0 and are included in the CRC. The
    > CRC should be calculated as follows:
    >
    > - data are assumed to be in the numbering order that
    appears
    >   in the draft - start with byte 0 bit 0 continue byte 1
    bit
    >   0 etc. (Big Endian on bytes / Little Endian on bits)
    
    Ok. The code presented satisfies this requirement.  I swap
    the bits in the bytes on the fly.
    
    Please note that we DO NOT have to swap the bits in the
    last
    4 bytes representing the CRC. This is clearly specified in
    the draft.
    
    Please also note that the draft doesn't specify how the
    data
    is to be transmitted, it only specifies how to build M(x),
    i.e. MSB(lsb).
    
    > - the CRC register is initialized with all 1s (equivalent
    to 
    >   complementing the first 32 bits of the message) 
    
    Ok. The code also satisfies this requirement. In fact this
    has no significance to the algorithm and R(x), if the
    _same_
    algorithm is used in both the sender and the receiver. As
    the draft says, this just complements the first 32 bits of
    the message, e.g. imagine the first 32 bits of the message
    were already 1's.
    
    > - the n PDU bits are considered coefficients of a
    polynomial 
    >   M(x) of order n-1, with bit 0 of byte 0 being x^(n-1) 
    
    Ok.
    
    > - the polynomial is multiplied by x^32 and divided by
    G(x)- the 
    >   generator polynomial - producing a remainder R(x) of
    degree <= 
    >   31 
    > - the coefficients of R(x) are considered a 32 bit
    sequence 
    
    So, here we get M'(x) = x^32 * M(x). Getting R(x) is
    trivial.  So we have:
    
       M'(x) = Q(x)*G(x) + R(x) = Q(x)*G(x) - R(x),         (1)
    
    since plus is same as minus in modulo 2 arithmetic.
    
    > - the bit sequence is complemented and the result is the
    CRC 
    
    Now, from boolean logic we know that b XOR 1 = ~b, then,
    
      ~R(x) = R(x) XOR I(x) = R(x) + I(x)                   (2)
    
    where I(x) is a polynomial of the same degree as R(x) and
    whose coefficients are all equal to 1. So, to get M''(x)
    which we send we have:
    
      M''(x) = M'(x) + ~R(x)                   (draft)
             = Q(x)*G(x) - R(x) + R(x) + I(x)  (using (1) and
    (2))
             = Q(x)*G(x) + I(x).
    
    or succinctly,
    
      M''(x) = Q(x)*G(x) + I(x),                         (3)
    
    and this is the message which we send.  On the other end we
    get M''(x), assuming there was no noise, and all
    link/TCP/Ethernet transformations are transparent for the
    sender and the receiver.
    
    > - after the last bit of the original segment the CRC bits
    are 
    >   transmitted with x^31 first followed by x^30 etc. (
    whenever 
    > examples are given the value to be specified in examples 
    > follows the same rules of representation as the rest of
    this 
    > document) 
    
    Ok.
    
    > - a receiver of a "good" segment (data or header) built
    using 
    >   the generator 0x11edc6f41 will end-up having in the CRC
    
    >   register the value 0x1c2d19ed (this a register value
    and not a 
    >   word as outlined in this draft)
    
    Ok, so the receiver got M''(x) assuming no noise.
    
      M''(x) = Q(x)*G(x) + I(x).            (this is (3))
    
    Now we work the algorithm again: ..., find the remainder:
    Clearly, from (3) the remainder of M''(x) modulo G(x) is
    I(x).
    
    Then we complement the value as per the draft:
    
      ~I(x) = 0.
    
    And we end up with remainder 0.
    
    Now let A(x) be the polynomial represented by 0x1c2d19ed.
    Then, we can add A(x) to M''(x) to get:
    
      M'''(x) = Q(x)*G(x) + I(x) + A(x)      (from (3))
              = Q(x)*G(x) + ~A(x).           (from (2))
    
    Now we send M'''(x), we receive M'''(x), and we work the
    algorithm again. Clearly the remainder is ~A(x) and
    performing the final complement we get:
    
      ~~A(x) = A(x), which is 0x1c2d19ed.
    
    So then I can just go ahead and send M'''(x),
    since iSCSI is expecting to get A(x) as a remainder.
    
    The C code:
    ---------cut-here--------------
    /*
      crc32c.c -- Implement CRC32C: 32 bit CRC of the
    polynomial
                  represented by 0x11EDC6F41.
    
      Copyright (C) 2001 Splentec Ltd.
    */			    
    #include <netinet/in.h>
    #include <linux/types.h>
    #include <stdio.h>
    
    #define  SAMPLE_SIZE   28
    #define  BIT(v, bit)   ((v) & (((typeof ((v))) 1) <<
    (bit)))
    
    const uint32_t Poly  = 0x1edc6f41UL;
    const uint32_t Magic = 0x1c2d19edUL;
    
    uint32_t table[256];
    
    /* 28 bytes + 4 bytes for the CRC */
    uint8_t  zero[SAMPLE_SIZE+4];
    uint8_t  ones[SAMPLE_SIZE+4];
    uint8_t  incs[SAMPLE_SIZE+4];
    uint8_t  decs[SAMPLE_SIZE+4];
    
    int      test_packet(uint8_t *packet, size_t size, uint32_t
    (*crc_func)(uint8_t *, size_t));
    int      calc_table(uint32_t *table, uint32_t poly);
    uint32_t crc(uint8_t *p, size_t size);
    uint32_t crc_force(uint8_t *p, size_t size);
    static inline uint8_t  mirror8(uint8_t v);
    
    /* -------------------------------------------------- */
    
    int main()
    {
    	uint32_t i;
    
    	printf("Making the samples...\n");
    	for (i = 0; i < SAMPLE_SIZE; i++) {
    	        ones[i] = 0xFF;
    		incs[i] = i;
    		decs[i] = 0x1f - i;
    	}
    	
    	/* -------------------------------------------------- */
    
    	printf("Generating the table...\n");
    	calc_table(table, Poly);
    /*
    	for (i = 0; i < 256; i++)
    		printf("0x%08xU%s", table[i], (i % 4) == 3 ? ",\n" : ",
    ");
    */		
    
    	/* -------------------------------------------------- */
    	printf("Testing...with table\n");
    
    	test_packet(zero, SAMPLE_SIZE+4, crc);
    	test_packet(ones, SAMPLE_SIZE+4, crc);
    	test_packet(incs, SAMPLE_SIZE+4, crc);
    	test_packet(decs, SAMPLE_SIZE+4, crc);
    
    	/* -------------------------------------------------- */
    	printf("Testing...without table\n");
    
    	test_packet(zero, SAMPLE_SIZE+4, crc_force);
    	test_packet(ones, SAMPLE_SIZE+4, crc_force);
    	test_packet(incs, SAMPLE_SIZE+4, crc_force);
    	test_packet(decs, SAMPLE_SIZE+4, crc_force);
    
    	return 0;	
    } /* end main() */
    
    /* -------------------------------------------------- */
    
    /* test an augmented packet
     */
    int test_packet(uint8_t *packet, size_t size, uint32_t
    (*crc_func)(uint8_t *, size_t))
    {
    	uint32_t r;
    
    	r = crc_func(packet, size);
    
    	/* Now here we can form M'''(x) by doing the following:
    
    	   r ^= Magic;
    
    	*/
    	
    	*((uint32_t *)(packet + SAMPLE_SIZE)) = htonl(r);
    	printf("packet %p has CRC %#x -> sending -> ", packet, r);
    
    	/* The packet is sent and received on the other end.
    	   Then we process it:
    	*/
    	
    	r = crc_func(packet, size);
    	printf("packet has CRC %#x\n", r);
    
    	/* zero out the CRC space for later testing with no table
    lookup */
    	packet[SAMPLE_SIZE]
    		= packet[SAMPLE_SIZE+1]
    		= packet[SAMPLE_SIZE+2]
    		= packet[SAMPLE_SIZE+3] = 0;
    
    	return 0;
    } /* end test_packet() */
    
    /* -------------------------------------------------- */
    
    int calc_table(uint32_t *table, uint32_t poly)
    {
    	register uint32_t crc, i;
    	
    	for (i = 0; i < 256; i++) {
    		crc = i << 24;
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 0 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 1 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 2 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 3 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 4 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 5 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 6 */
    		crc = BIT(crc, 31) ? ((crc<<1)^poly) : (crc<<1); /* 7 */
    		table[i] = crc;
            }
    	
    	return 0;
    } /* end calc_table() */
    
    /* -------------------------------------------------- */
    
    /* p points to an augmented message, i.e.
       32 bits have been added at the end and set to 0.
    
       The last 4 bytes are never mirrored since the draft
       is clear on that: mirror only when building
       the polynomial, and send the CRC 31 bit first,
       then 30, etc.   
    */
    uint32_t crc(uint8_t *p, size_t size)
    {
    	uint32_t r = ~((uint32_t) 0UL);
    	uint8_t mp;
    
    	for ( ; size-- > 0; p++) {
    		/* do not mirror CRC code! (last 4 bytes) */
    		mp = (size > 4) ? mirror8(*p) : *p;
    		r = ((r << 8) | mp) ^ table[r >> 24];
    	}
    
    	return ~r;
    } /* end crc() */
    
    /* -------------------------------------------------- */
    
    /* p points to an augmented message, i.e.
       32 bits have been added at the end and set to 0.
    
       The last 4 bytes are never mirrored since the draft
       is clear on that: mirror only when building
       the polynomial, and send the CRC 31 bit first,
       then 30, etc.
    */
    uint32_t crc_force(uint8_t *p, size_t size)
    {
    	uint32_t r = ~((uint32_t) 0UL), t;
    	uint8_t  mp;
    	int i;
    
    	for ( ; size-- > 0; p++) {
    		/* do not mirror CRC code (last 4 bytes) */
    		mp = (size > 4) ? mirror8(*p) : *p;
    		for (i = 7; i >= 0; i--) {
    			t = r;
    			r = (r << 1) | (BIT(mp, i) >> i);
    			if (BIT(t, 31))
    				r ^= Poly;
    		}
    	}
    
    	return ~r;
    } /* end crc_force() */
    
    /* -------------------------------------------------- */
    
    static inline uint8_t mirror8(uint8_t v)
    {
    	return    ((0x80 & v) >> 7)
    		| ((0x40 & v) >> 5)
    		| ((0x20 & v) >> 3)
            	| ((0x10 & v) >> 1)
    		| ((8 & v) << 1)
    		| ((4 & v) << 3)
    		| ((2 & v) << 5)
    		| ((1 & v) << 7);
    } /* end mirror8() */
    
    /* -------------------------------------------------- */
    
    ---------------------cut-here----------------------
    
    Thanks in advance,
    Luben
    
    
    =====
    --
    
    __________________________________________________
    Do You Yahoo!?
    Yahoo! GeoCities - quick and easy web site hosting, just $8.95/month.
    http://geocities.yahoo.com/ps/info1
    


Home

Last updated: Mon Nov 26 12:17:37 2001
7906 messages in chronological order