crc32
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a6ef824
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/bazel-*
diff --git a/WORKSPACE b/WORKSPACE
new file mode 100644
index 0000000..2433dd7
--- /dev/null
+++ b/WORKSPACE
@@ -0,0 +1,15 @@
+workspace(name = "protodatastore-cpp")
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+http_archive(
+    name = "com_google_absl",
+    strip_prefix = "abseil-cpp-master",
+    urls = ["https://github.com/abseil/abseil-cpp/archive/master.zip"],
+)
+
+http_archive(
+    name = "googletest",
+    strip_prefix = "googletest-master",
+    urls = ["https://github.com/google/googletest/archive/master.zip"],
+)
diff --git a/protostore/BUILD b/protostore/BUILD
new file mode 100644
index 0000000..ee5be81
--- /dev/null
+++ b/protostore/BUILD
@@ -0,0 +1,21 @@
+load("@rules_cc//cc:defs.bzl", "cc_library")
+
+cc_library(
+    name = "crc32",
+    srcs = ["crc32.cc"],
+    hdrs = ["crc32.h"],
+    visibility = ["//visibility:private"],
+    deps = [
+      "@com_google_absl//absl/strings",
+    ]
+)
+
+cc_test(
+    name = "crc32_test",
+    srcs = ["crc32_test.cc"],
+    visibility = ["//visibility:private"],
+    deps = [
+        ":crc32",
+        "@googletest//:gtest_main",
+    ],
+)
diff --git a/protostore/crc32.cc b/protostore/crc32.cc
new file mode 100644
index 0000000..4adfe74
--- /dev/null
+++ b/protostore/crc32.cc
@@ -0,0 +1,29 @@
+#include "protostore/crc32.h"
+
+#include <cstdint>
+#include <zlib.h>
+
+#include "absl/strings/string_view.h"
+
+namespace protostore {
+
+namespace {
+uint32_t UpdateCrc32(uint32_t crc, const absl::string_view str) {
+  if (str.length() > 0) {
+    // crc32() already includes a pre- and post-condition of taking the one's
+    // complement of the value.
+    crc =
+        ~crc32(~crc, reinterpret_cast<const Bytef*>(str.data()), str.length());
+  }
+  return crc;
+}
+}  // namespace
+
+uint32_t Crc32::Get() const { return crc_; }
+
+uint32_t Crc32::Append(const absl::string_view str) {
+  crc_ = UpdateCrc32(crc_, str);
+  return crc_;
+}
+
+}  // namespace mobstore
diff --git a/protostore/crc32.h b/protostore/crc32.h
new file mode 100644
index 0000000..4aa123c
--- /dev/null
+++ b/protostore/crc32.h
@@ -0,0 +1,52 @@
+#ifndef PROTOSTORE_CRC32_H_
+#define PROTOSTORE_CRC32_H_
+
+#include <cstdint>
+#include <zlib.h>
+
+#include "absl/strings/string_view.h"
+
+namespace protostore {
+
+// Efficient mechanism to incrementally compute checksum of a file and keep it
+// updated when its content changes. Internally uses zlib based crc32()
+// implementation.
+//
+// See https://www.zlib.net/manual.html#Checksum for more details.
+//
+// CRC32C::Extend in //util/hash/crc32c.h crashes as described in b/145837799.
+class Crc32 {
+ public:
+  // Default to the checksum of an empty string, that is "0".
+  Crc32() : crc_(0) {}
+
+  explicit Crc32(uint32_t init_crc) : crc_(init_crc) {}
+
+  inline bool operator==(const Crc32& other) const {
+    return crc_ == other.Get();
+  }
+
+  // Returns the checksum of all the data that has been processed till now.
+  uint32_t Get() const;
+
+  // Incrementally update the current checksum to reflect the fact that the
+  // underlying data has been appended with 'str'. It calculates a new crc32
+  // based on the current crc value and the newly appended string.
+  //
+  // NOTE: As this method accepts incremental appends, all these 3 will lead to
+  // the same checksum:
+  // 1) crc32.Append("AAA"); crc32.Append("BBB");
+  // 2) crc32.Append("AAABBB");
+  // 3) crc32.Append("AA"); crc32.Append("AB"); crc32.Append("BB");
+  //
+  // NOTE: While this class internally uses zlib's crc32(),
+  // Crc32(base_crc).Append(str) is not the same as zlib::crc32(base_crc, str);
+  uint32_t Append(absl::string_view str);
+
+ private:
+  uint32_t crc_;
+};
+
+}  // namespace protostore
+
+#endif  // PROTOSTORE_CRC32_H_
diff --git a/protostore/crc32_test.cc b/protostore/crc32_test.cc
new file mode 100644
index 0000000..186db6b
--- /dev/null
+++ b/protostore/crc32_test.cc
@@ -0,0 +1,45 @@
+#include "protostore/crc32.h"
+
+#include <cstdint>
+
+#include "googlemock/include/gmock/gmock.h"
+#include "googletest/include/gtest/gtest.h"
+
+namespace protostore {
+
+namespace {
+
+using ::testing::Eq;
+
+TEST(Crc32Test, Get) {
+  Crc32 crc32_test{10};
+  Crc32 crc32_test_empty{};
+  EXPECT_THAT(crc32_test.Get(), Eq(10));
+  EXPECT_THAT(crc32_test_empty.Get(), Eq(0));
+}
+
+TEST(Crc32Test, Append) {
+  // Test the complement logic inside Append()
+  const uLong kCrcInitZero = crc32(0L, nullptr, 0);
+  uint32_t foo_crc =
+      crc32(kCrcInitZero, reinterpret_cast<const Bytef*>("foo"), 3);
+  uint32_t foobar_crc =
+      crc32(kCrcInitZero, reinterpret_cast<const Bytef*>("foobar"), 6);
+
+  Crc32 crc32_test(~foo_crc);
+  ASSERT_THAT(~crc32_test.Append("bar"), Eq(foobar_crc));
+
+  // Test Append() that appending things separately should be the same as
+  // appending in one shot
+  Crc32 crc32_foobar{};
+  crc32_foobar.Append("foobar");
+  Crc32 crc32_foo_and_bar{};
+  crc32_foo_and_bar.Append("foo");
+  crc32_foo_and_bar.Append("bar");
+
+  EXPECT_THAT(crc32_foo_and_bar.Get(), Eq(crc32_foobar.Get()));
+}
+
+}  // namespace
+
+}  // namespace mobstore