content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package org.apache.cassandra.utils;
  
  import java.io.IOException;
  import java.nio.ByteBuffer;
  import java.util.zip.CRC32;
  
  import io.netty.buffer.ByteBuf;
  import io.netty.util.concurrent.FastThreadLocal;
  
  public class Crc
  {
      private static final FastThreadLocal<CRC32> crc32 = new FastThreadLocal<CRC32>()
      {
          @Override
          protected CRC32 initialValue()
          {
              return new CRC32();
          }
      };
  
      private static final byte[] initialBytes = new byte[] { (byte) 0xFA, (byte) 0x2D, (byte) 0x55, (byte) 0xCA };
  
      public static final class InvalidCrc extends IOException
      {
          public InvalidCrc(int read, int computed)
          {
              super(String.format("Read %d, Computed %d", read, computed));
          }
      }
  
      public static CRC32 crc32()
      {
          CRC32 crc = crc32.get();
          return initialize(crc);
      }
  
      public static CRC32 initialize(CRC32 crc)
      {
          crc.reset();
          crc.update(initialBytes, 0, initialBytes.length);
          return crc;
      }
  
      public static int computeCrc32(ByteBuf buffer, int startReaderIndex, int endReaderIndex)
      {
          CRC32 crc = crc32();
          crc.update(buffer.internalNioBuffer(startReaderIndex, endReaderIndex - startReaderIndex));
          return (int) crc.getValue();
      }
  
      public static int computeCrc32(ByteBuffer buffer, int start, int end)
      {
          CRC32 crc = crc32();
          updateCrc32(crc, buffer, start, end);
          return (int) crc.getValue();
      }
  
      public static void updateCrc32(CRC32 crc, ByteBuffer buffer, int start, int end)
      {
          int savePosition = buffer.position();
          int saveLimit = buffer.limit();
          buffer.limit(end);
          buffer.position(start);
          crc.update(buffer);
          buffer.limit(saveLimit);
          buffer.position(savePosition);
      }
  
      private static final int CRC24_INIT = 0x875060;
      /**
       * Polynomial chosen from https://users.ece.cmu.edu/~koopman/crc/index.html, by Philip Koopman
       *
       * This webpage claims a copyright to Philip Koopman, which he licenses under the
       * Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0)
       *
       * It is unclear if this copyright can extend to a 'fact' such as this specific number, particularly
       * as we do not use Koopman's notation to represent the polynomial, but we anyway attribute his work and
       * link the terms of his license since they are not incompatible with our usage and we greatly appreciate his work.
       *
       * This polynomial provides hamming distance of 8 for messages up to length 105 bits;
       * we only support 8-64 bits at present, with an expected range of 40-48.
       */
      private static final int CRC24_POLY = 0x1974F0B;
  
      /**
       * NOTE: the order of bytes must reach the wire in the same order the CRC is computed, with the CRC
       * immediately following in a trailer.  Since we read in least significant byte order, if you
       * write to a buffer using putInt or putLong, the byte order will be reversed and
       * you will lose the guarantee of protection from burst corruptions of 24 bits in length.
       *
       * Make sure either to write byte-by-byte to the wire, or to use Integer/Long.reverseBytes if you
       * write to a BIG_ENDIAN buffer.
       *
       * See http://users.ece.cmu.edu/~koopman/pubs/ray06_crcalgorithms.pdf
       *
       * Complain to the ethernet spec writers, for having inverse bit to byte significance order.
       *
       * Note we use the most naive algorithm here.  We support at most 8 bytes, and typically supply
       * 5 or fewer, so any efficiency of a table approach is swallowed by the time to hit L3, even
       * for a tiny (4bit) table.
       *
       * @param bytes an up to 8-byte register containing bytes to compute the CRC over
       *              the bytes AND bits will be read least-significant to most significant.
       * @param len   the number of bytes, greater than 0 and fewer than 9, to be read from bytes
       * @return      the least-significant bit AND byte order crc24 using the CRC24_POLY polynomial
       */
      public static int crc24(long bytes, int len)
      {
          int crc = CRC24_INIT;
          while (len-- > 0)
          {
              crc ^= (bytes & 0xff) << 16;
              bytes >>= 8;
  
              for (int i = 0; i < 8; i++)
              {
                  crc <<= 1;
                  if ((crc & 0x1000000) != 0)
                      crc ^= CRC24_POLY;
              }
          }
          return crc;
      }
  }
  