#### libremiliacr
#### Copyright(C) 2020-2024 Remilia Scarlet <remilia@posteo.jp>
####
#### This program is free software: you can redistribute it and/or modify
#### it under the terms of the GNU General Public License as published
#### the Free Software Foundation, either version 3 of the License, or
#### (at your option) any later version.
####
#### This program is distributed in the hope that it will be useful,
#### but WITHOUT ANY WARRANTY; without even the implied warranty of
#### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
#### GNU General Public License for more details.
####
#### You should have received a copy of the GNU General Public License
#### along with this program.If not, see<http:####www.gnu.org/licenses/.>
# A 64-bit Cyclic Redundancy Check.
class RemiLib::Digest::Crc64
# The polynomial as defined in ECMA 182.
ECMA_POLY = 0xC96C5795D7870F42_u64
# The polynomial as defined in ISO 3309.
ISO_POLY = 0xD800000000000000_u64
# The current checksum. This is updated each time `#update` is called.
getter crc : UInt64 = 0
# The polynomial that this instance is currently using.
getter polynomial : UInt64 = ECMA_POLY
# CRC table.
@table : Slice(UInt64) = Slice(UInt64).new(0)
# Creates a new `Crc64` instance.
def initialize(poly : UInt64 = ECMA_POLY)
self.polynomial = poly
end
# Updates the checksum with *value*. Returns the new checksum.
@[AlwaysInline]
def update(value : UInt8) : UInt64
@crc = ~@crc
@crc = @table.unsafe_fetch(value ^ (@crc & 0xFF)) ^ (@crc >> 8)
@crc = ~@crc
end
# Updates the checksum with the bytes in *buf*. Returns the new checksum.
@[AlwaysInline]
def update(buf : Bytes|Array(UInt8)) : UInt64
@crc = ~@crc
buf.each do |byte|
@crc = @table.unsafe_fetch(byte ^ (@crc & 0xFF)) ^ (@crc >> 8)
end
@crc = ~@crc
end
# Resets this instance to the initial state.
def reset : Nil
@crc = 0
end
# Changes the polynomial that is used. **NOTE**: This resets this instance to
# the initial state as well.
def polynomial=(@polynomial : UInt64) : Nil
reset
@table = Slice(UInt64).new(256) do |i|
val : UInt64 = i.to_u64!
8.times do |_|
if bitflag?(val, 1)
val = (val >> 1) ^ @polynomial
else
val = val >> 1
end
end
val
end
end
end