From 58d9d3459226b14c45c9133eb48ce722f16c22cf Mon Sep 17 00:00:00 2001 From: Ghulam Nasir Date: Thu, 12 Nov 2020 15:46:14 +0100 Subject: [PATCH] crc-8, crc-16 and crc-32 implementations --- Playgrounds/CRC16.playground/Contents.swift | 38 +++++++++++ .../CRC16.playground/Sources/CRC.swift | 45 +++++++++++++ .../CRC16.playground/Sources/CRC16.swift | 60 ++++++++++++++++++ .../CRC16.playground/contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 7 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../xcschemes/xcschememanagement.plist | 16 +++++ Playgrounds/CRC32.playground/Contents.swift | 37 +++++++++++ .../CRC32.playground/Sources/CRC.swift | 47 ++++++++++++++ .../CRC32.playground/Sources/CRC32.swift | 59 +++++++++++++++++ .../CRC32.playground/contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 7 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ Playgrounds/CRC8.playground/Contents.swift | 38 +++++++++++ Playgrounds/CRC8.playground/Sources/CRC.swift | 47 ++++++++++++++ .../CRC8.playground/Sources/CRC8.swift | 58 +++++++++++++++++ .../CRC8.playground/contents.xcplayground | 4 ++ .../contents.xcworkspacedata | 4 ++ .../xcshareddata/IDEWorkspaceChecks.plist | 8 +++ .../xcschemes/xcschememanagement.plist | 16 +++++ README.md | 11 +++- Source Files/CRC.swift | 47 ++++++++++++++ Source Files/CRC16.swift | 60 ++++++++++++++++++ Source Files/CRC32.swift | 59 +++++++++++++++++ Source Files/CRC8.swift | 58 +++++++++++++++++ .../Data-Integrity-CRC-with-swift-on-ios.jpg | Bin 0 -> 90329 bytes 26 files changed, 749 insertions(+), 1 deletion(-) create mode 100644 Playgrounds/CRC16.playground/Contents.swift create mode 100644 Playgrounds/CRC16.playground/Sources/CRC.swift create mode 100644 Playgrounds/CRC16.playground/Sources/CRC16.swift create mode 100644 Playgrounds/CRC16.playground/contents.xcplayground create mode 100644 Playgrounds/CRC16.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Playgrounds/CRC16.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Playgrounds/CRC16.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Playgrounds/CRC32.playground/Contents.swift create mode 100644 Playgrounds/CRC32.playground/Sources/CRC.swift create mode 100644 Playgrounds/CRC32.playground/Sources/CRC32.swift create mode 100644 Playgrounds/CRC32.playground/contents.xcplayground create mode 100644 Playgrounds/CRC32.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Playgrounds/CRC32.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Playgrounds/CRC8.playground/Contents.swift create mode 100644 Playgrounds/CRC8.playground/Sources/CRC.swift create mode 100644 Playgrounds/CRC8.playground/Sources/CRC8.swift create mode 100644 Playgrounds/CRC8.playground/contents.xcplayground create mode 100644 Playgrounds/CRC8.playground/playground.xcworkspace/contents.xcworkspacedata create mode 100644 Playgrounds/CRC8.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 Source Files/CRC.swift create mode 100644 Source Files/CRC16.swift create mode 100644 Source Files/CRC32.swift create mode 100644 Source Files/CRC8.swift create mode 100644 images/Data-Integrity-CRC-with-swift-on-ios.jpg diff --git a/Playgrounds/CRC16.playground/Contents.swift b/Playgrounds/CRC16.playground/Contents.swift new file mode 100644 index 0000000..419bc2b --- /dev/null +++ b/Playgrounds/CRC16.playground/Contents.swift @@ -0,0 +1,38 @@ +// +// CRC16.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +let crc16 = CRC16() + +crc16.currentValue // initial value is 0 +crc16.append(1.0) +crc16.append(1) // we are passing integer (If you want to pass UInt8, see the line below) +crc16.append(UInt8(1)) +crc16.append([1, 20]) // We are passing [UInt8] (because that is the only type of array the append method accepts) + +// get the current crc value +crc16.currentValue + +// append more +crc16.append(5.6) +crc16.append(225) + +// get the current crc value +crc16.currentValue + +// reset the crc value +crc16.reset() + +crc16.currentValue // value is 0 after reset + + +// CRC16's lookup table +crc16.lookupTable + +// CRC16's lookup table (hexadecimal representation) +let lookupTableHexa = crc16.lookupTable.map { String($0, radix: 16) } +lookupTableHexa diff --git a/Playgrounds/CRC16.playground/Sources/CRC.swift b/Playgrounds/CRC16.playground/Sources/CRC.swift new file mode 100644 index 0000000..5a02361 --- /dev/null +++ b/Playgrounds/CRC16.playground/Sources/CRC.swift @@ -0,0 +1,45 @@ +// +// CRC.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public protocol CRC { + associatedtype Size + + var currentValue: Size { get } + + func append(_ bytes: [UInt8]) + + func reset() +} + +extension CRC { + public func append(_ byte: UInt8) { + append([byte]) + } + + public func append(_ integer: T) { + append(integer.bigEndianBytes) + } + + public func append(_ floatingPoint: T) { + append(floatingPoint.bigEndianBytes) + } +} + +extension FixedWidthInteger { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self.bigEndian) { Data($0) }) + } +} + +// Please keep in mind that Float has different representations and you need to make sure +// you are using the same representation as the system you are communicating with +extension BinaryFloatingPoint { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self) { Data($0) }).reversed() + } +} diff --git a/Playgrounds/CRC16.playground/Sources/CRC16.swift b/Playgrounds/CRC16.playground/Sources/CRC16.swift new file mode 100644 index 0000000..1cab333 --- /dev/null +++ b/Playgrounds/CRC16.playground/Sources/CRC16.swift @@ -0,0 +1,60 @@ +// +// CRC16.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Class to conveniently calculate CRC-16. It uses the CRC16-CCITT polynomial (0x1021) by default +public class CRC16: CRC { + + /// The table that stores the precomputed remainders for all possible divisions for 1 byte + /// This table is used as a lookup (to speed up the calculation) + public let lookupTable: [UInt16] + + private(set) public var currentValue: UInt16 = 0 + + /// Creates the instance for calculating CRC + /// - Parameter polynomial: The polynomial to use. It uses CRC16-CCITT's polynomial (0x1021) by default + public init(polynomial: UInt16 = 0x1021) { + /// Generates the lookup table (make sure to generate it only once) + self.lookupTable = (0...255).map { Self.crc16(for: UInt8($0), polynomial: polynomial) } + } + + public func append(_ bytes: [UInt8]) { + currentValue = crc16(for: bytes, initialValue: currentValue) + } + + public func reset() { + currentValue = 0 + } +} + +/// Same code as the blog article +extension CRC16 { + /// Caculates CRC-16 of an array of Bytes (UInt8) + private func crc16(for inputs: [UInt8], initialValue: UInt16 = 0) -> UInt16 { + inputs.reduce(initialValue) { remainder, byte in + let bigEndianInput = UInt16(byte).bigEndian + let index = (bigEndianInput ^ remainder) >> 8 + return lookupTable[Int(index)] ^ (remainder << 8) + } + } + + /// Calculates the CRC-16 of 1 Byte + private static func crc16(for input: UInt8, polynomial: UInt16) -> UInt16 { + var result = UInt16(input).bigEndian + for _ in 0..<8 { + let isMostSignificantBitOne = result & 0x8000 != 0 + + result = result << 1 + + if isMostSignificantBitOne { + result = result ^ polynomial + } + } + + return result + } +} diff --git a/Playgrounds/CRC16.playground/contents.xcplayground b/Playgrounds/CRC16.playground/contents.xcplayground new file mode 100644 index 0000000..a751024 --- /dev/null +++ b/Playgrounds/CRC16.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Playgrounds/CRC16.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/CRC16.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Playgrounds/CRC16.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Playgrounds/CRC16.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Playgrounds/CRC16.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Playgrounds/CRC16.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Playgrounds/CRC16.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist b/Playgrounds/CRC16.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..ade3cc6 --- /dev/null +++ b/Playgrounds/CRC16.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,16 @@ + + + + + SchemeUserState + + CRC16 (Playground).xcscheme + + isShown + + orderHint + 0 + + + + diff --git a/Playgrounds/CRC32.playground/Contents.swift b/Playgrounds/CRC32.playground/Contents.swift new file mode 100644 index 0000000..0199a73 --- /dev/null +++ b/Playgrounds/CRC32.playground/Contents.swift @@ -0,0 +1,37 @@ +// +// CRC32.playground +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +let crc32 = CRC32() + +crc32.currentValue // initial value is 0 +crc32.append(1.0) +crc32.append(1) // we are passing integer (If you want to pass UInt8, see the line below) +crc32.append(UInt8(1)) +crc32.append([1, 20]) // We are passing [UInt8] (because that is the only type of array the append method accepts) + +// get the current crc value +crc32.currentValue + +// append more +crc32.append(5.6) +crc32.append(225) + +// get the current crc value +crc32.currentValue + +// reset the crc value +crc32.reset() + +crc32.currentValue // value is 0 after reset + + +// CRC32's lookup table +crc32.lookupTable + +// CRC32's lookup table (hexadecimal representation) +let lookupTableHexa = crc32.lookupTable.map { String($0, radix: 16) } diff --git a/Playgrounds/CRC32.playground/Sources/CRC.swift b/Playgrounds/CRC32.playground/Sources/CRC.swift new file mode 100644 index 0000000..f325dc3 --- /dev/null +++ b/Playgrounds/CRC32.playground/Sources/CRC.swift @@ -0,0 +1,47 @@ +// +// CRC.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public protocol CRC { + associatedtype Size + + var currentValue: Size { get } + + func append(_ bytes: [UInt8]) + + func reset() +} + +extension CRC { + public func append(_ byte: UInt8) { + append([byte]) + } + + public func append(_ integer: T) { + append(integer.bigEndianBytes) + } + + public func append(_ floatingPoint: T) { + append(floatingPoint.bigEndianBytes) + } +} + +// MARK: - Convenience Extension Methods + +extension FixedWidthInteger { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self.bigEndian) { Data($0) }) + } +} + +// `BinaryFloatingPoint` conforms to 754-2008 - IEEE Standard for Floating-Point Arithmetic (https://ieeexplore.ieee.org/document/4610935) +// If you target system is using a different floating point representation, you need to adapt accordingly +extension BinaryFloatingPoint { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self) { Data($0) }).reversed() + } +} diff --git a/Playgrounds/CRC32.playground/Sources/CRC32.swift b/Playgrounds/CRC32.playground/Sources/CRC32.swift new file mode 100644 index 0000000..72da711 --- /dev/null +++ b/Playgrounds/CRC32.playground/Sources/CRC32.swift @@ -0,0 +1,59 @@ +// +// CRC32.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Class to conveniently calculate CRC-32 It uses the CRC32 polynomial (0x04C11DB7) by default +public class CRC32: CRC { + + /// The table that stores the precomputed remainders for all possible divisions for 1 byte + /// This table is used as a lookup (to speed up the calculation) + public let lookupTable: [UInt32] + + private(set) public var currentValue: UInt32 = 0 + + /// Creates the instance for calculating CRC + /// - Parameter polynomial: The polynomial to use. It uses CRC32's polynomial (0x04C11DB7) by default + public init(polynomial: UInt32 = 0x04C11DB7) { + /// Generates the lookup table (make sure to generate it only once) + self.lookupTable = (0...255).map { Self.crc32(for: UInt8($0), polynomial: polynomial) } + } + + public func append(_ bytes: [UInt8]) { + currentValue = crc32(for: bytes, initialValue: currentValue) + } + + public func reset() { + currentValue = 0 + } +} + +extension CRC32 { + /// Caculates CRC-32 of an array of Bytes (UInt8) + private func crc32(for inputs: [UInt8], initialValue: UInt32 = 0) -> UInt32 { + inputs.reduce(initialValue) { remainder, byte in + let bigEndianInput = UInt32(byte).bigEndian + let index = (bigEndianInput ^ remainder) >> 24 + return lookupTable[Int(index)] ^ (remainder << 8) + } + } + + /// Calculates the CRC-32 of 1 Byte + private static func crc32(for input: UInt8, polynomial: UInt32) -> UInt32 { + var result = UInt32(input).bigEndian + for _ in 0..<8 { + let isMostSignificantBitOne = result & 0x80000000 != 0 + + result = result << 1 + + if isMostSignificantBitOne { + result = result ^ polynomial + } + } + + return result + } +} diff --git a/Playgrounds/CRC32.playground/contents.xcplayground b/Playgrounds/CRC32.playground/contents.xcplayground new file mode 100644 index 0000000..a751024 --- /dev/null +++ b/Playgrounds/CRC32.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Playgrounds/CRC32.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/CRC32.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Playgrounds/CRC32.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Playgrounds/CRC32.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Playgrounds/CRC32.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Playgrounds/CRC32.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Playgrounds/CRC8.playground/Contents.swift b/Playgrounds/CRC8.playground/Contents.swift new file mode 100644 index 0000000..7111276 --- /dev/null +++ b/Playgrounds/CRC8.playground/Contents.swift @@ -0,0 +1,38 @@ +// +// CRC8.playground +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +let crc8 = CRC8() + +crc8.currentValue // initial value is 0 +crc8.append(1.0) +crc8.append(1) // we are passing integer (If you want to pass UInt8, see the line below) +crc8.append(UInt8(1)) +crc8.append([1, 20]) // We are passing [UInt8] (because that is the only type of array the append method accepts) + +// get the current crc value +crc8.currentValue + +// append more +crc8.append(5.6) +crc8.append(225) + +// get the current crc value +crc8.currentValue + +// reset the crc value +crc8.reset() + +crc8.currentValue // value is 0 after reset + + +// CRC8's lookup table +crc8.lookupTable + +// CRC8's lookup table (hexadecimal representation) +let lookupTableHexa = crc8.lookupTable.map { String($0, radix: 16) } +lookupTableHexa diff --git a/Playgrounds/CRC8.playground/Sources/CRC.swift b/Playgrounds/CRC8.playground/Sources/CRC.swift new file mode 100644 index 0000000..f325dc3 --- /dev/null +++ b/Playgrounds/CRC8.playground/Sources/CRC.swift @@ -0,0 +1,47 @@ +// +// CRC.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public protocol CRC { + associatedtype Size + + var currentValue: Size { get } + + func append(_ bytes: [UInt8]) + + func reset() +} + +extension CRC { + public func append(_ byte: UInt8) { + append([byte]) + } + + public func append(_ integer: T) { + append(integer.bigEndianBytes) + } + + public func append(_ floatingPoint: T) { + append(floatingPoint.bigEndianBytes) + } +} + +// MARK: - Convenience Extension Methods + +extension FixedWidthInteger { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self.bigEndian) { Data($0) }) + } +} + +// `BinaryFloatingPoint` conforms to 754-2008 - IEEE Standard for Floating-Point Arithmetic (https://ieeexplore.ieee.org/document/4610935) +// If you target system is using a different floating point representation, you need to adapt accordingly +extension BinaryFloatingPoint { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self) { Data($0) }).reversed() + } +} diff --git a/Playgrounds/CRC8.playground/Sources/CRC8.swift b/Playgrounds/CRC8.playground/Sources/CRC8.swift new file mode 100644 index 0000000..0bf5ccd --- /dev/null +++ b/Playgrounds/CRC8.playground/Sources/CRC8.swift @@ -0,0 +1,58 @@ +// +// CRC8.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Class to conveniently calculate CRC-8. It uses the CRC8-Bluetooth polynomial (0xA7) by default +public class CRC8: CRC { + + /// The table that stores the precomputed remainders for all possible divisions for 1 byte + /// This table is used as a lookup (to speed up the calculation) + public let lookupTable: [UInt8] + + private(set) public var currentValue: UInt8 = 0 + + /// Creates the instance for calculating CRC + /// - Parameter polynomial: The polynomial to use. It uses CRC8-Bluetooth's polynomial (0xA7) by default + public init(polynomial: UInt8 = 0xA7) { + /// Generates the lookup table (make sure to generate it only once) + self.lookupTable = (0...255).map { Self.CRC8(for: UInt8($0), polynomial: polynomial) } + } + + public func append(_ bytes: [UInt8]) { + currentValue = CRC8(for: bytes, initialValue: currentValue) + } + + public func reset() { + currentValue = 0 + } +} + +/// Same code as the blog article +extension CRC8 { + /// Caculates CRC-8 of an array of Bytes (UInt8) + private func CRC8(for inputs: [UInt8], initialValue: UInt8 = 0) -> UInt8 { + inputs.reduce(initialValue) { remainder, byte in + let index = byte ^ remainder + return lookupTable[Int(index)] + } + } + + /// Calculates the CRC-8 of 1 Byte + private static func CRC8(for input: UInt8, polynomial: UInt8) -> UInt8 { + var result = input + for _ in 0..<8 { + let isMostSignificantBitOne = result & 0x80 != 0 + + result = result << 1 + if isMostSignificantBitOne { + result = result ^ polynomial + } + } + + return result + } +} diff --git a/Playgrounds/CRC8.playground/contents.xcplayground b/Playgrounds/CRC8.playground/contents.xcplayground new file mode 100644 index 0000000..a751024 --- /dev/null +++ b/Playgrounds/CRC8.playground/contents.xcplayground @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Playgrounds/CRC8.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/CRC8.playground/playground.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..94b2795 --- /dev/null +++ b/Playgrounds/CRC8.playground/playground.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,4 @@ + + + diff --git a/Playgrounds/CRC8.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Playgrounds/CRC8.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Playgrounds/CRC8.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist b/Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..adc4499 --- /dev/null +++ b/Playgrounds/CRC8.playground/xcuserdata/nasir.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,16 @@ + + + + + SchemeUserState + + CRC8 (Playground).xcscheme + + isShown + + orderHint + 0 + + + + diff --git a/README.md b/README.md index e33dc3d..a4ac516 100644 --- a/README.md +++ b/README.md @@ -1 +1,10 @@ -# crc-swift \ No newline at end of file +# Data Integrity: CRC with Swift on iOS + + +
+ +This repository contains the implementation of 8, 16 and 32 bit CRCs (CRC-8, CRC-16 and CRC-32). The implementation uses the *Big Endian* format for input and polynomial. + +If you want to understand how the CRC works in more detail, please check our article on [How to Validate Your Data with a Cyclic Redundancy Check (CRC)](https://quickbirdstudios.com/blog/validate-data-with-crc/). + +If you want to read more about how these implementations works, please check our article on [Data Integrity: CRC with Swift on iOS](https://quickbirdstudios.com/blog/data-integrity-crc-swift-ios/). diff --git a/Source Files/CRC.swift b/Source Files/CRC.swift new file mode 100644 index 0000000..f325dc3 --- /dev/null +++ b/Source Files/CRC.swift @@ -0,0 +1,47 @@ +// +// CRC.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +public protocol CRC { + associatedtype Size + + var currentValue: Size { get } + + func append(_ bytes: [UInt8]) + + func reset() +} + +extension CRC { + public func append(_ byte: UInt8) { + append([byte]) + } + + public func append(_ integer: T) { + append(integer.bigEndianBytes) + } + + public func append(_ floatingPoint: T) { + append(floatingPoint.bigEndianBytes) + } +} + +// MARK: - Convenience Extension Methods + +extension FixedWidthInteger { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self.bigEndian) { Data($0) }) + } +} + +// `BinaryFloatingPoint` conforms to 754-2008 - IEEE Standard for Floating-Point Arithmetic (https://ieeexplore.ieee.org/document/4610935) +// If you target system is using a different floating point representation, you need to adapt accordingly +extension BinaryFloatingPoint { + public var bigEndianBytes: [UInt8] { + [UInt8](withUnsafeBytes(of: self) { Data($0) }).reversed() + } +} diff --git a/Source Files/CRC16.swift b/Source Files/CRC16.swift new file mode 100644 index 0000000..1cab333 --- /dev/null +++ b/Source Files/CRC16.swift @@ -0,0 +1,60 @@ +// +// CRC16.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Class to conveniently calculate CRC-16. It uses the CRC16-CCITT polynomial (0x1021) by default +public class CRC16: CRC { + + /// The table that stores the precomputed remainders for all possible divisions for 1 byte + /// This table is used as a lookup (to speed up the calculation) + public let lookupTable: [UInt16] + + private(set) public var currentValue: UInt16 = 0 + + /// Creates the instance for calculating CRC + /// - Parameter polynomial: The polynomial to use. It uses CRC16-CCITT's polynomial (0x1021) by default + public init(polynomial: UInt16 = 0x1021) { + /// Generates the lookup table (make sure to generate it only once) + self.lookupTable = (0...255).map { Self.crc16(for: UInt8($0), polynomial: polynomial) } + } + + public func append(_ bytes: [UInt8]) { + currentValue = crc16(for: bytes, initialValue: currentValue) + } + + public func reset() { + currentValue = 0 + } +} + +/// Same code as the blog article +extension CRC16 { + /// Caculates CRC-16 of an array of Bytes (UInt8) + private func crc16(for inputs: [UInt8], initialValue: UInt16 = 0) -> UInt16 { + inputs.reduce(initialValue) { remainder, byte in + let bigEndianInput = UInt16(byte).bigEndian + let index = (bigEndianInput ^ remainder) >> 8 + return lookupTable[Int(index)] ^ (remainder << 8) + } + } + + /// Calculates the CRC-16 of 1 Byte + private static func crc16(for input: UInt8, polynomial: UInt16) -> UInt16 { + var result = UInt16(input).bigEndian + for _ in 0..<8 { + let isMostSignificantBitOne = result & 0x8000 != 0 + + result = result << 1 + + if isMostSignificantBitOne { + result = result ^ polynomial + } + } + + return result + } +} diff --git a/Source Files/CRC32.swift b/Source Files/CRC32.swift new file mode 100644 index 0000000..72da711 --- /dev/null +++ b/Source Files/CRC32.swift @@ -0,0 +1,59 @@ +// +// CRC32.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Class to conveniently calculate CRC-32 It uses the CRC32 polynomial (0x04C11DB7) by default +public class CRC32: CRC { + + /// The table that stores the precomputed remainders for all possible divisions for 1 byte + /// This table is used as a lookup (to speed up the calculation) + public let lookupTable: [UInt32] + + private(set) public var currentValue: UInt32 = 0 + + /// Creates the instance for calculating CRC + /// - Parameter polynomial: The polynomial to use. It uses CRC32's polynomial (0x04C11DB7) by default + public init(polynomial: UInt32 = 0x04C11DB7) { + /// Generates the lookup table (make sure to generate it only once) + self.lookupTable = (0...255).map { Self.crc32(for: UInt8($0), polynomial: polynomial) } + } + + public func append(_ bytes: [UInt8]) { + currentValue = crc32(for: bytes, initialValue: currentValue) + } + + public func reset() { + currentValue = 0 + } +} + +extension CRC32 { + /// Caculates CRC-32 of an array of Bytes (UInt8) + private func crc32(for inputs: [UInt8], initialValue: UInt32 = 0) -> UInt32 { + inputs.reduce(initialValue) { remainder, byte in + let bigEndianInput = UInt32(byte).bigEndian + let index = (bigEndianInput ^ remainder) >> 24 + return lookupTable[Int(index)] ^ (remainder << 8) + } + } + + /// Calculates the CRC-32 of 1 Byte + private static func crc32(for input: UInt8, polynomial: UInt32) -> UInt32 { + var result = UInt32(input).bigEndian + for _ in 0..<8 { + let isMostSignificantBitOne = result & 0x80000000 != 0 + + result = result << 1 + + if isMostSignificantBitOne { + result = result ^ polynomial + } + } + + return result + } +} diff --git a/Source Files/CRC8.swift b/Source Files/CRC8.swift new file mode 100644 index 0000000..0bf5ccd --- /dev/null +++ b/Source Files/CRC8.swift @@ -0,0 +1,58 @@ +// +// CRC8.swift +// +// Copyright © 2020 QuickBird Studios. All rights reserved. +// + +import Foundation + +/// Class to conveniently calculate CRC-8. It uses the CRC8-Bluetooth polynomial (0xA7) by default +public class CRC8: CRC { + + /// The table that stores the precomputed remainders for all possible divisions for 1 byte + /// This table is used as a lookup (to speed up the calculation) + public let lookupTable: [UInt8] + + private(set) public var currentValue: UInt8 = 0 + + /// Creates the instance for calculating CRC + /// - Parameter polynomial: The polynomial to use. It uses CRC8-Bluetooth's polynomial (0xA7) by default + public init(polynomial: UInt8 = 0xA7) { + /// Generates the lookup table (make sure to generate it only once) + self.lookupTable = (0...255).map { Self.CRC8(for: UInt8($0), polynomial: polynomial) } + } + + public func append(_ bytes: [UInt8]) { + currentValue = CRC8(for: bytes, initialValue: currentValue) + } + + public func reset() { + currentValue = 0 + } +} + +/// Same code as the blog article +extension CRC8 { + /// Caculates CRC-8 of an array of Bytes (UInt8) + private func CRC8(for inputs: [UInt8], initialValue: UInt8 = 0) -> UInt8 { + inputs.reduce(initialValue) { remainder, byte in + let index = byte ^ remainder + return lookupTable[Int(index)] + } + } + + /// Calculates the CRC-8 of 1 Byte + private static func CRC8(for input: UInt8, polynomial: UInt8) -> UInt8 { + var result = input + for _ in 0..<8 { + let isMostSignificantBitOne = result & 0x80 != 0 + + result = result << 1 + if isMostSignificantBitOne { + result = result ^ polynomial + } + } + + return result + } +} diff --git a/images/Data-Integrity-CRC-with-swift-on-ios.jpg b/images/Data-Integrity-CRC-with-swift-on-ios.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0ede6e6d95d791cd2e0508da6a8cbe3f6d6e420 GIT binary patch literal 90329 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 literal 0 HcmV?d00001