136 lines
3.8 KiB
C
136 lines
3.8 KiB
C
|
/*
|
||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||
|
*
|
||
|
* Licensed 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.
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <stddef.h>
|
||
|
#include <cstdint>
|
||
|
|
||
|
namespace folly {
|
||
|
namespace detail {
|
||
|
|
||
|
/**
|
||
|
* Representation of a polynomial of degree DEG over GF(2) (that is,
|
||
|
* with binary coefficients).
|
||
|
*
|
||
|
* Probably of no use outside of Fingerprint code; used by
|
||
|
* GenerateFingerprintTables and the unittest.
|
||
|
*/
|
||
|
template <int DEG>
|
||
|
class FingerprintPolynomial {
|
||
|
public:
|
||
|
static constexpr int size() {
|
||
|
return 1 + DEG / 64;
|
||
|
}
|
||
|
|
||
|
constexpr FingerprintPolynomial() {}
|
||
|
|
||
|
constexpr explicit FingerprintPolynomial(const uint64_t (&vals)[size()]) {
|
||
|
for (int i = 0; i < size(); i++) {
|
||
|
val_[i] = vals[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
constexpr uint64_t get(size_t i) const {
|
||
|
return val_[i];
|
||
|
}
|
||
|
|
||
|
constexpr void add(const FingerprintPolynomial<DEG>& other) {
|
||
|
for (int i = 0; i < size(); i++) {
|
||
|
val_[i] ^= other.val_[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Multiply by X. The actual degree must be < DEG.
|
||
|
constexpr void mulX() {
|
||
|
uint64_t b = 0;
|
||
|
for (int i = size() - 1; i >= 0; i--) {
|
||
|
uint64_t nb = val_[i] >> 63;
|
||
|
val_[i] = (val_[i] << 1) | b;
|
||
|
b = nb;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Compute (this * X) mod P(X), where P(X) is a monic polynomial of degree
|
||
|
// DEG+1 (represented as a FingerprintPolynomial<DEG> object, with the
|
||
|
// implicit coefficient of X^(DEG+1)==1)
|
||
|
//
|
||
|
// This is a bit tricky. If k=DEG+1:
|
||
|
// Let P(X) = X^k + p_(k-1) * X^(k-1) + ... + p_1 * X + p_0
|
||
|
// Let this = A(X) = a_(k-1) * X^(k-1) + ... + a_1 * X + a_0
|
||
|
// Then:
|
||
|
// A(X) * X
|
||
|
// = a_(k-1) * X^k + (a_(k-2) * X^(k-1) + ... + a_1 * X^2 + a_0 * X)
|
||
|
// = a_(k-1) * X^k + (the binary representation of A, left shift by 1)
|
||
|
//
|
||
|
// if a_(k-1) = 0, we can ignore the first term.
|
||
|
// if a_(k-1) = 1, then:
|
||
|
// X^k mod P(X)
|
||
|
// = X^k - P(X)
|
||
|
// = P(X) - X^k
|
||
|
// = p_(k-1) * X^(k-1) + ... + p_1 * X + p_0
|
||
|
// = exactly the binary representation passed in as an argument to this
|
||
|
// function!
|
||
|
//
|
||
|
// So A(X) * X mod P(X) is:
|
||
|
// the binary representation of A, left shift by 1,
|
||
|
// XOR p if a_(k-1) == 1
|
||
|
constexpr void mulXmod(const FingerprintPolynomial<DEG>& p) {
|
||
|
bool needXOR = (val_[0] & (1ULL << 63));
|
||
|
val_[0] &= ~(1ULL << 63);
|
||
|
mulX();
|
||
|
if (needXOR) {
|
||
|
add(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Compute (this * X^k) mod P(X) by repeatedly multiplying by X (see above)
|
||
|
constexpr void mulXkmod(int k, const FingerprintPolynomial<DEG>& p) {
|
||
|
for (int i = 0; i < k; i++) {
|
||
|
mulXmod(p);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// add X^k, where k <= DEG
|
||
|
constexpr void addXk(int k) {
|
||
|
int word_offset = (DEG - k) / 64;
|
||
|
int bit_offset = 63 - (DEG - k) % 64;
|
||
|
val_[word_offset] ^= (1ULL << bit_offset);
|
||
|
}
|
||
|
|
||
|
// Set the highest 8 bits to val.
|
||
|
// If val is interpreted as polynomial of degree 7, then this sets *this
|
||
|
// to val * X^(DEG-7)
|
||
|
constexpr void setHigh8Bits(uint8_t val) {
|
||
|
val_[0] = ((uint64_t)val) << (64 - 8);
|
||
|
for (int i = 1; i < size(); i++) {
|
||
|
val_[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
// Internal representation: big endian
|
||
|
// val_[0] contains the highest order coefficients, with bit 63 as the
|
||
|
// highest order coefficient
|
||
|
//
|
||
|
// If DEG+1 is not a multiple of 64, val_[size()-1] only uses the highest
|
||
|
// order (DEG+1)%64 bits (the others are always 0)
|
||
|
uint64_t val_[size()] = {};
|
||
|
};
|
||
|
|
||
|
} // namespace detail
|
||
|
} // namespace folly
|