According to the apple docs the Fletcher's checksum algorithm is used. Apple uses a variant of the algorithm described in a paper by John Kodis. The following algorithm shows this procedure. The input is the block without the first 8 byte.
func createChecksum(data []byte) uint64 {
var sum1, sum2 uint64
modValue := uint64(2<<31 - 1)
for i := 0; i < len(data)/4; i++ {
d := binary.LittleEndian.Uint32(data[i*4 : (i+1)*4])
sum1 = (sum1 + uint64(d)) % modValue
sum2 = (sum2 + sum1) % modValue
}
check1 := modValue - ((sum1 + sum2) % modValue)
check2 := modValue - ((sum1 + check1) % modValue)
return (check2 << 32) | check1
}
The nice feature of the algorithm is, that when you check a block in APFS with the following algorithm you should get null as a result. Note that the input in this case is the whole block, including the checksum. However, because APFS stores the checksum at the start, this means that you have to feed through everything except the checksum, followed by the checksum.
func checkChecksum(data []byte) uint64 {
var sum1, sum2 uint64
modValue := uint64(2<<31 - 1)
for i := 0; i < len(data)/4; i++ {
d := binary.LittleEndian.Uint32(data[i*4 : (i+1)*4])
sum1 = (sum1 + uint64(d)) % modValue
sum2 = (sum2 + sum1) % modValue
}
return (sum2 << 32) | sum1
}