industria crc port added by sethalves on Tue Jun 24 01:42:52 2014

;; -*- mode: scheme; coding: utf-8 -*-
;; Copyright © 2009, 2011, 2012 Göran Weinholt 

;; Permission is hereby granted, free of charge, to any person obtaining a
;; copy of this software and associated documentation files (the "Software"),
;; to deal in the Software without restriction, including without limitation
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
;; and/or sell copies of the Software, and to permit persons to whom the
;; Software is furnished to do so, subject to the following conditions:

;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.

;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;; DEALINGS IN THE SOFTWARE.
;; #!r6rs

;; Syntax for defining procedures that calculate Cyclic Redundancy Codes.

;; Ross N. Williams, "A painless guide to CRC error detection
;; algorithms". http://www.ross.net/crc/crcpaper.html

;;; Simple usage with pre-defined CRCs

;; If you want to use one of the pre-defined CRCs

;; (define-crc crc-32)
;;     calculates the CRC table at expand-time and defines the
;;     procedures below

;; (crc-32 bytevector)
;;     returns the final CRC of the entire bytevector
;; (crc-32-init)
;;     returns an initial CRC state
;; (crc-32-update state bv)
;; (crc-32-update state bv start)
;; (crc-32-update state bv start end)
;;     returns a new state which includes the CRC on the given bytes
;; (crc-32-finish state)
;;     returns the final CRC
;; (crc-32-width)
;;     returns the bit-width of the CRC, e.g. 32 for CRC-32
;; (crc-32-self-test)
;;     returns 'sucess, 'failure, or 'no-self-test

;;; Advanced usage

;; Quick and possibly confusing guide to using define-crc with new
;; CRCs, for those who are too busy to read the above paper:

;; Syntax: (define-src name width polynomial init ref-in ref-out
;;                     xor-out check)

;; The width is the bitwise length of the polynomial. You might be
;; lead to believe that it should sometimes be 33, but if so you've
;; been counting the highest bit, which doesn't count.

;; The polynomial for CRC-16 is given sometimes given as x^16 + x^15 +
;; x^2 + 1. This translates to #b1000000000000101 (#x8005). Notice
;; that x^16 is absent. CRCs use polynomial division with modulo two
;; arithmetic (better known as XOR). Don't use the reversed polynomial
;; if you have one of those, instead set ref-in and ref-out properly.

;; After a CRC has been calculated it is sometimes XOR'd with a final
;; value, this is xor-out.

;; check is either the CRC of the ASCII string "123456789", or #f.

;; Syntax: (define-crc name (coefficients ...) init ref-in ref-out
;;                     xor-out check)

;; This is the slightly easier interface where you can simply specify
;; the powers of the coefficients. CRC-16 in this syntax becomes:

;; (define-crc crc-16 (16 15 2 0) #x0000 #t #t #x0000 #xBB3D)

;; Another example: the polynomial x^8 + x^2 + x + 1 in this syntax
;; becomes: (8 2 1 0)

(define-library (weinholt crypto crc)
  (export define-crc decode-coefficients

          crc-32 crc-32-init crc-32-finish
          crc-32-self-test crc-32-width crc-32-update

          crc-16 crc-16-init crc-16-finish crc-16-self-test
          crc-16-width crc-16-update

          crc-16/ccitt crc-16/ccitt-init crc-16/ccitt-finish
          crc-16/ccitt-self-test crc-16/ccitt-width crc-16/ccitt-update

          crc-32c crc-32c-init crc-32c-finish crc-32c-self-test
          crc-32c-width crc-32c-update

          crc-24 crc-24-init crc-24-finish crc-24-self-test
          crc-24-width crc-24-update

          crc-64 crc-64-init crc-64-finish crc-64-self-test
          crc-64-width crc-64-update

          crc-64/ecma-182-init crc-64/ecma-182-finish
          crc-64/ecma-182-self-test crc-64/ecma-182-width
          crc-64/ecma-182-update
          )
  (import (scheme base)
          (scheme case-lambda)
          (only (srfi 1) iota)
          ;; (for (only (srfi :1 lists) iota) expand)
          (srfi 60)
          (weinholt bytevectors)
          (weinholt r6rs-compatibility)
          )

  (cond-expand
   (chicken
    (import (numbers)))
   (else))

  (begin

    (define (decode-coefficients coeffs)
      (do ((i coeffs (cdr i))
           (p 0 (bitwise-ior p (arithmetic-shift 1 (car i)))))
          ((null? i) p)))


    (define (calc-table width ref-in poly)
      (define (calc-table-i index)
        (do ((bit 0 (+ bit 1))
             (r (arithmetic-shift index (- width 8))
                (if (bitwise-bit-set? r (- width 1))
                    (bitwise-xor (arithmetic-shift r 1) poly)
                    (arithmetic-shift r 1))))
            ((= bit 8)
             (bitwise-bit-field r 0 width))))
      (list->vector
       (map (lambda (index)
              (if ref-in
                  (bitwise-reverse-bit-field
                   (calc-table-i (bitwise-reverse-bit-field index 0 8))
                   0 width)
                  (calc-table-i index)))
            (iota 256))))


    (define-syntax define-crc
      (syntax-rules ()
        ((define-crc name width polynomial init ref-in ref-out xor-out check
           crc-init crc-finish crc-self-test crc-width crc-update)
         (begin
           (define (crc-init) init)
           (define (crc-finish r) (bitwise-xor r xor-out))

           (define (crc-self-test)
             (if check
                 (if (= (name (string->utf8 "123456789")) check)
                     'success 'failure)
                 'no-self-test))

           (define (crc-width) width)

           (define (crc-update r* bv . maybe-start+end)
             (let* ((start (if (pair? maybe-start+end)
                               (car maybe-start+end)
                               0))
                    (end (if (and (pair? maybe-start+end)
                                  (pair? (cdr maybe-start+end)))
                             (cadr maybe-start+end)
                             (bytevector-length bv))))
               (let ((t (calc-table width ref-in polynomial)) ;; XXX
                     (mask (- (arithmetic-shift 1 (- width 8)) 1)))
                 (do ((i start (+ i 1))
                      (r r*
                         ;; TODO: implement the other ref-in ref-out
                         ;; combinations?
                         (cond ((and ref-in ref-out)
                                (bitwise-xor
                                 (arithmetic-shift r -8)
                                 (vector-ref
                                  t (bitwise-xor (bitwise-and r #xff)
                                                 (bytevector-u8-ref bv i)))))
                               ((and (not ref-in) (not ref-out))
                                (bitwise-xor
                                 (arithmetic-shift (bitwise-and mask r) 8)
                                 (vector-ref
                                  t (bitwise-xor
                                     (bytevector-u8-ref bv i)
                                     (bitwise-and
                                      (arithmetic-shift r (- 8 width))
                                      #xff)))))
                               (else (error "unimplemented reflection")))))
                     ((= i end) r)))))

           (define (name bv)
             (crc-finish (crc-update (crc-init) bv)))))))


    ;; Used for .ZIP, AUTODIN II, Ethernet, FDDI, PNG, MPEG-2
    ;; and various other things.
    (define-crc crc-32 32 #x04C11DB7 #xFFFFFFFF #t #t #xFFFFFFFF #xCBF43926
      crc-32-init crc-32-finish crc-32-self-test crc-32-width crc-32-update)

    (define-crc crc-16 16 #x8005 #x0000 #t #t #x0000 #xBB3D
      crc-16-init crc-16-finish crc-16-self-test crc-16-width crc-16-update)

    ;; Used by XMODEM, PPP and much more
    (define-crc crc-16/ccitt 16 #x1021 #xffff #f #f 0 #x29B1
      crc-16/ccitt-init crc-16/ccitt-finish crc-16/ccitt-self-test
      crc-16/ccitt-width crc-16/ccitt-update)

    ;; CRC-32C specified in e.g. RFC4960 or RFC3385. Used by SCTP
    ;; and iSCSI. Finds more errors than CRC-32.
    (define-crc crc-32c 32 #x1EDC6F41 #xFFFFFFFF #t #t #xFFFFFFFF #xE3069283
      crc-32c-init crc-32c-finish crc-32c-self-test crc-32c-width
      crc-32c-update)

    ;; OpenPGP, see RFC2440.
    (define-crc crc-24 24
      (decode-coefficients '(24 23 18 17 14 11 10 7 6 5 4 3 1 0))
      #xB704CE #f #f 0 #x21CF02
      crc-24-init crc-24-finish crc-24-self-test crc-24-width crc-24-update)

    (define-crc crc-64 64
      (decode-coefficients '(64 4 3 1 0))
      0 #t #t 0 #x46A5A9388A5BEFFE
      crc-64-init crc-64-finish crc-64-self-test crc-64-width crc-64-update)

    (define-crc crc-64/ecma-182
      64
      (decode-coefficients
       '(64 62 57 55 54 53 52 47 46 45 40 39 38 37 35 33 32 31
            29 27 24 23 22 21 19 17 13 12 10 9 7 4 1 0))
      #xFFFFFFFFFFFFFFFF #t #t #xFFFFFFFFFFFFFFFF
      #x995DC9BBDF1939FA
      crc-64/ecma-182-init crc-64/ecma-182-finish
      crc-64/ecma-182-self-test crc-64/ecma-182-width
      crc-64/ecma-182-update)


    ))