aboutsummaryrefslogtreecommitdiffstats
path: root/crc.scm
blob: 423622bc0e5cae29b6c1e15a73081d597603b654 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
;;;; "crc.scm" Compute Cyclic Checksums
;;; Copyright (C) 1995, 1996, 1997, 2001, 2002 Aubrey Jaffer
;
;Permission to copy this software, to modify it, to redistribute it,
;to distribute modified versions, and to use it for any purpose is
;granted, subject to the following restrictions and understandings.
;
;1.  Any copy made of this software must include this copyright notice
;in full.
;
;2.  I have made no warranty or representation that the operation of
;this software will be error-free, and I am under no obligation to
;provide any services, by way of maintenance, update, or otherwise.
;
;3.  In conjunction with products arising from the use of this
;material, there shall be no use of my name in any advertising,
;promotional, or sales literature without prior written consent in
;each case.

(require 'byte)
(require 'logical)

;;@ (define CRC-32-polynomial    "100000100100000010001110110110111") ; IEEE-802, FDDI
(define CRC-32-polynomial    "100000100110000010001110110110111") ; IEEE-802, AAL5
;@
(define CRC-CCITT-polynomial "10001000000100001")	; X25
;@
(define CRC-16-polynomial    "11000000000000101")	; IBM Bisync, HDLC, SDLC, USB-Data

;;@ (define CRC-12-polynomial    "1100000001101")
(define CRC-12-polynomial    "1100000001111")

;;@ (define CRC-10-polynomial   "11000110001")
(define CRC-10-polynomial   "11000110011")
;@
(define CRC-08-polynomial    "100000111")
;@
(define ATM-HEC-polynomial   "100000111")
;@
(define DOWCRC-polynomial    "100110001")
;@
(define USB-Token-polynomial "100101")

;;This procedure is careful not to use more than DEG bits in
;;computing (- (expt 2 DEG) 1).  It returns #f if the integer would
;;be larger than the implementation supports.
(define (crc:make-mask deg)
  (string->number (make-string deg #\1) 2))
;@
(define (crc:make-table str)
  (define deg (+ -1 (string-length str)))
  (define generator (string->number (substring str 1 (string-length str)) 2))
  (define crctab (make-vector 256))
  (if (not (eqv? #\1 (string-ref str 0)))
      (slib:error 'crc:make-table 'first-digit-of-polynomial-must-be-1 str))
  (if (< deg 8)
      (slib:error 'crc:make-table 'degree-must-be>7 deg str))
  (and
   generator
   (do ((i 0 (+ 1 i))
	(deg-1-mask (crc:make-mask (+ -1 deg)))
	(gen generator
	     (if (logbit? (+ -1 deg) gen)
		 (logxor (ash (logand deg-1-mask gen) 1) generator)
		 (ash (logand deg-1-mask gen) 1)))
	(gens '() (cons gen gens)))
       ((>= i 8) (set! gens (reverse gens))
	(do ((crc 0 0)
	     (m 0 (+ 1 m)))
	    ((> m 255) crctab)
	  (for-each (lambda (gen i)
		      (set! crc (if (logbit? i m) (logxor crc gen) crc)))
		    gens '(0 1 2 3 4 5 6 7))
	  (vector-set! crctab m crc))))))

(define crc-32-table (crc:make-table CRC-32-polynomial))

;;@ Computes the P1003.2/D11.2 (POSIX.2) 32-bit checksum.
(define (cksum file)
  (cond ((not crc-32-table) #f)
	((input-port? file) (cksum-port file))
	(else (call-with-input-file file cksum-port))))

(define cksum-port
  (let ((mask-24 (crc:make-mask 24))
	(mask-32 (crc:make-mask 32)))
    (lambda (port)
      (define crc 0)
      (define (accumulate-crc byt)
	(set! crc
	      (logxor (ash (logand mask-24 crc) 8)
		      (vector-ref crc-32-table (logxor (ash crc -24) byt)))))
      (do ((byt (read-byte port) (read-byte port))
	   (byte-count 0 (+ 1 byte-count)))
	  ((eof-object? byt)
	   (do ((byte-count byte-count (ash byte-count -8)))
	       ((zero? byte-count) (logxor mask-32 crc))
	     (accumulate-crc (logand #xff byte-count))))
	(accumulate-crc byt)))))
;@
(define (crc16 file)
  (cond ((not crc-16-table) #f)
	((input-port? file) (crc16-port file))
	(else (call-with-input-file file crc16-port))))

(define crc-16-table (crc:make-table CRC-16-polynomial))

(define crc16-port
  (let ((mask-8 (crc:make-mask 8))
	(mask-16 (crc:make-mask 16)))
    (lambda (port)
      (define crc mask-16)
      (define (accumulate-crc byt)
	(set! crc
	      (logxor (ash (logand mask-8 crc) 8)
		      (vector-ref crc-16-table (logxor (ash crc -8) byt)))))
      (do ((byt (read-byte port) (read-byte port)))
	  ((eof-object? byt) (logxor mask-16 crc))
	(accumulate-crc byt)))))
;@
(define (crc5 file)
  (cond ((input-port? file) (crc5-port file))
	(else (call-with-input-file file crc5-port))))

(define (crc5-port port)
  (define generator #b00101)
  (define crc #b11111)
  (do ((byt (read-byte port) (read-byte port)))
      ((eof-object? byt) (logxor #b11111 crc))
    (do ((data byt (ash data 1))
	 (len (+ -1 8) (+ -1 len)))
	((negative? len))
      (set! crc
	    (logand #b11111
		    (if (eqv? (logbit? 7 data) (logbit? 4 crc))
			(ash crc 1)
			(logxor (ash crc 1) generator)))))))