pw_kvs: Implement CRC16 checksum for KVS

- Create CRC16 implementation of pw::kvs::ChecksumAlgorithm.
- Add tests for the ChecksumAlgorithm class.

Change-Id: I3d7268e49c4eec06d61e113602ce24c05a3b0fa0
diff --git a/pw_kvs/BUILD b/pw_kvs/BUILD
index 5433285..69a13ec 100644
--- a/pw_kvs/BUILD
+++ b/pw_kvs/BUILD
@@ -33,6 +33,7 @@
     ],
     hdrs = [
         "public/pw_kvs/checksum.h",
+        "public/pw_kvs/crc16_checksum.h",
         "public/pw_kvs/flash_memory.h",
         "public/pw_kvs/in_memory_fake_flash.h",
         "public/pw_kvs/key_value_store.h",
@@ -45,10 +46,33 @@
     ],
 )
 
+pw_cc_library(
+    name = "crc16",
+    hdrs = [
+        "public/pw_kvs/crc16_checksum.h",
+    ],
+    deps = [
+        ":pw_kvs",
+        "//pw_checksum",
+    ],
+)
+
+pw_cc_test(
+    name = "checksum_test",
+    srcs = ["checksum_test.cc"],
+    deps = [
+        ":crc16",
+        ":pw_kvs",
+        "//pw_checksum",
+        "//pw_log",
+    ],
+)
+
 pw_cc_test(
     name = "key_value_store_test",
     srcs = ["key_value_store_test.cc"],
     deps = [
+        ":crc16",
         ":pw_kvs",
         "//pw_checksum",
         "//pw_log",
diff --git a/pw_kvs/BUILD.gn b/pw_kvs/BUILD.gn
index 35e02d2..0c17d87 100644
--- a/pw_kvs/BUILD.gn
+++ b/pw_kvs/BUILD.gn
@@ -45,12 +45,38 @@
   friend = [ ":key_value_store_test" ]
 }
 
+source_set("crc16") {
+  public = [
+    "public/pw_kvs/crc16_checksum.h",
+  ]
+  sources = public
+  public_deps = [
+    ":pw_kvs",
+    dir_pw_checksum,
+  ]
+}
+
 pw_test_group("tests") {
-  tests = [ ":key_value_store_test" ]
+  tests = [
+    ":checksum_test",
+    ":key_value_store_test",
+  ]
+}
+
+pw_test("checksum_test") {
+  deps = [
+    ":crc16",
+    ":pw_kvs",
+    dir_pw_log,
+  ]
+  sources = [
+    "checksum_test.cc",
+  ]
 }
 
 pw_test("key_value_store_test") {
   deps = [
+    ":crc16",
     ":pw_kvs",
     dir_pw_checksum,
     dir_pw_log,
diff --git a/pw_kvs/checksum_test.cc b/pw_kvs/checksum_test.cc
new file mode 100644
index 0000000..e5333ad
--- /dev/null
+++ b/pw_kvs/checksum_test.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 The Pigweed Authors
+//
+// 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
+//
+//     https://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.
+
+#include "pw_kvs/checksum.h"
+
+#include "gtest/gtest.h"
+#include "pw_kvs/crc16_checksum.h"
+
+namespace pw::kvs {
+namespace {
+
+using std::byte;
+
+constexpr std::string_view kString =
+    "In the beginning the Universe was created. This has made a lot of "
+    "people very angry and been widely regarded as a bad move.";
+constexpr uint16_t kStringCrc = 0xC184;
+
+TEST(Checksum, UpdateAndVerify) {
+  ChecksumCrc16 crc16_algo;
+  ChecksumAlgorithm& algo = crc16_algo;
+
+  algo.Update(kString.data(), kString.size());
+  EXPECT_EQ(Status::OK, algo.Verify(as_bytes(span(&kStringCrc, 1))));
+}
+
+TEST(Checksum, Verify_Failure) {
+  ChecksumCrc16 algo;
+  EXPECT_EQ(Status::DATA_LOSS, algo.Verify(as_bytes(span(kString.data(), 2))));
+}
+
+TEST(Checksum, Verify_InvalidSize) {
+  ChecksumCrc16 algo;
+  EXPECT_EQ(Status::INVALID_ARGUMENT, algo.Verify({}));
+  EXPECT_EQ(Status::INVALID_ARGUMENT, algo.Verify(as_bytes(span(kString))));
+}
+
+TEST(Checksum, Reset) {
+  ChecksumCrc16 crc_algo;
+  crc_algo.Update(as_bytes(span(kString)));
+  crc_algo.Reset();
+  EXPECT_EQ(crc_algo.state()[0], byte{0xFF});
+  EXPECT_EQ(crc_algo.state()[1], byte{0xFF});
+}
+
+}  // namespace
+}  // namespace pw::kvs
diff --git a/pw_kvs/key_value_store_test.cc b/pw_kvs/key_value_store_test.cc
index b839d2e..e9baf24 100644
--- a/pw_kvs/key_value_store_test.cc
+++ b/pw_kvs/key_value_store_test.cc
@@ -31,6 +31,7 @@
 
 #include "gtest/gtest.h"
 #include "pw_checksum/ccitt_crc16.h"
+#include "pw_kvs/crc16_checksum.h"
 #include "pw_kvs/flash_memory.h"
 #include "pw_kvs_private/format.h"
 #include "pw_kvs_private/macros.h"
@@ -143,8 +144,8 @@
 FlashPartition& test_partition = FlashExternalTestPartition();
 #endif  // USE_MEMORY_BUFFER
 
-// TODO: Need a checksum implementation (e.g. CRC16) to use for tests.
-constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3, .checksum = nullptr};
+ChecksumCrc16 checksum;
+constexpr EntryHeaderFormat format{.magic = 0xBAD'C0D3, .checksum = &checksum};
 
 KeyValueStore kvs(&test_partition, format);
 
diff --git a/pw_kvs/public/pw_kvs/checksum.h b/pw_kvs/public/pw_kvs/checksum.h
index f7b01a1..9f974b3 100644
--- a/pw_kvs/public/pw_kvs/checksum.h
+++ b/pw_kvs/public/pw_kvs/checksum.h
@@ -26,24 +26,24 @@
   virtual void Reset() = 0;
 
   // Updates the checksum with the provided data.
-  virtual Status Update(span<const std::byte> data_to_checksum) = 0;
+  virtual void Update(span<const std::byte> data) = 0;
 
-  // Convnenience wrapper.
-  Status Update(const void* data, size_t size) {
-    return Update(span(static_cast<const std::byte*>(data), size));
+  // Update the checksum from a pointer and size.
+  void Update(const void* data, size_t size_bytes) {
+    return Update(span(static_cast<const std::byte*>(data), size_bytes));
   }
 
   // Returns the current state of the checksum algorithm.
   constexpr const span<const std::byte>& state() const { return state_; }
 
-  // Returns the size of the checksum's state.
+  // Returns the size of the checksum state.
   constexpr size_t size_bytes() const { return state_.size(); }
 
-  // Compares a calculated checksum to this checksum's data.
-  Status Verify(span<const std::byte> calculated_checksum) const;
+  // Compares a calculated checksum to this checksum's current state.
+  Status Verify(span<const std::byte> checksum) const;
 
  protected:
-  // Derived class provides a span of its state buffer.
+  // A derived class provides a span of its state buffer.
   constexpr ChecksumAlgorithm(span<const std::byte> state) : state_(state) {}
 
   // Protected destructor prevents deleting ChecksumAlgorithms from the base
diff --git a/pw_kvs/public/pw_kvs/crc16_checksum.h b/pw_kvs/public/pw_kvs/crc16_checksum.h
new file mode 100644
index 0000000..f4e3a9b
--- /dev/null
+++ b/pw_kvs/public/pw_kvs/crc16_checksum.h
@@ -0,0 +1,36 @@
+// Copyright 2020 The Pigweed Authors
+//
+// 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
+//
+//     https://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 "pw_checksum/ccitt_crc16.h"
+#include "pw_kvs/checksum.h"
+#include "pw_span/span.h"
+
+namespace pw::kvs {
+
+class ChecksumCrc16 final : public ChecksumAlgorithm {
+ public:
+  ChecksumCrc16() : ChecksumAlgorithm(as_bytes(span(&crc_, 1))) {}
+
+  void Reset() final { crc_ = checksum::kCcittCrc16DefaultInitialValue; }
+
+  void Update(span<const std::byte> data) final {
+    crc_ = checksum::CcittCrc16(data, crc_);
+  }
+
+ private:
+  uint16_t crc_ = checksum::kCcittCrc16DefaultInitialValue;
+};
+
+}  // namespace pw::kvs