--- /dev/null
+USING: help.markup help.syntax math ;
+IN: checksums.crc16
+
+HELP: crc16
+{ $class-description "The crc16 checksum algorithm." } ;
+
+ARTICLE: "checksums.crc16" "crc16 checksum"
+"The crc16 checksum algorithm provides a quick but unreliable way to detect changes in data. Also known as CRC-16 and CRC-16-ANSI. Used in Bisync, Modbus, USB, ANSI X3.28 and many other protocols."
+{ $subsections crc16 } ;
+
+ABOUT: "checksums.crc16"
--- /dev/null
+! Copyright (C) 2016 Alexander Ilin.
+! See http://factorcode.org/license.txt for BSD license.
+USING: tools.test checksums checksums.crc16 ;
+IN: checksums.crc16.tests
+
+{ B{ 0xb8 0x80 } } [
+ B{ 0x01 0x04 0x02 0xFF 0xFF } crc16 checksum-bytes
+] unit-test
+
+{ B{ 0x21 0xc1 } } [
+ B{ 0x68 0x11 0x08 0x18 0x00 0x00 0x01 0x43 0x04 0x6e 0xda }
+ crc16 checksum-bytes
+] unit-test
--- /dev/null
+! Copyright (C) 2016 Alexander Ilin.
+! See http://factorcode.org/license.txt for BSD license.
+USING: checksums io.binary kernel math sequences
+sequences.private ;
+IN: checksums.crc16
+
+CONSTANT: crc16-polynomial 0xa001
+
+CONSTANT: crc16-table V{ }
+
+256 iota [
+ 8 [
+ [ 2/ ] [ even? ] bi [ crc16-polynomial bitxor ] unless
+ ] times
+] map 0 crc16-table copy
+
+: (crc16) ( crc ch -- crc )
+ dupd bitxor
+ mask-byte crc16-table nth-unsafe
+ swap -8 shift bitxor ; inline
+
+SINGLETON: crc16
+
+INSTANCE: crc16 checksum
+
+: init-crc16 ( input checksum -- x input )
+ drop [ 0xffff ] dip ; inline
+
+: finish-crc16 ( x -- bytes )
+ 2 >le ; inline
+
+M: crc16 checksum-bytes
+ init-crc16
+ [ (crc16) ] each
+ finish-crc16 ; inline
+
+M: crc16 checksum-lines
+ init-crc16
+ [ [ (crc16) ] each CHAR: \n (crc16) ] each
+ finish-crc16 ; inline