1 // Copyright 2020 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstddef> 17 #include <span> 18 19 #include "pw_kvs/alignment.h" 20 #include "pw_status/status.h" 21 22 namespace pw { 23 namespace kvs { 24 25 class ChecksumAlgorithm { 26 public: 27 // Resets the checksum to its initial state. 28 virtual void Reset() = 0; 29 30 // Updates the checksum with the provided data. 31 virtual void Update(std::span<const std::byte> data) = 0; 32 33 // Updates the checksum from a pointer and size. Update(const void * data,size_t size_bytes)34 void Update(const void* data, size_t size_bytes) { 35 return Update(std::span<const std::byte>( 36 static_cast<const std::byte*>(data), size_bytes)); 37 } 38 39 // Returns the final result of the checksum. Update() can no longer be called 40 // after this. The returned std::span is valid until a call to Reset(). 41 // 42 // Finish MUST be called before calling Verify. Finish()43 std::span<const std::byte> Finish() { 44 Finalize(); // Implemented by derived classes, if required. 45 return state(); 46 } 47 48 // Returns the size of the checksum state. size_bytes()49 constexpr size_t size_bytes() const { return state_.size(); } 50 51 // Compares a calculated checksum to this checksum's state. The checksum must 52 // be at least as large as size_bytes(). If it is larger, bytes beyond 53 // size_bytes() are ignored. 54 // 55 // Finish MUST be called before calling Verify. 56 Status Verify(std::span<const std::byte> checksum) const; 57 58 protected: 59 // A derived class provides a std::span of its state buffer. ChecksumAlgorithm(std::span<const std::byte> state)60 constexpr ChecksumAlgorithm(std::span<const std::byte> state) 61 : state_(state) {} 62 63 // Protected destructor prevents deleting ChecksumAlgorithms from the base 64 // class, so that it is safe to have a non-virtual destructor. 65 ~ChecksumAlgorithm() = default; 66 67 // Returns the current checksum state. state()68 constexpr std::span<const std::byte> state() const { return state_; } 69 70 private: 71 // Checksums that require finalizing operations may override this method. Finalize()72 virtual void Finalize() {} 73 74 std::span<const std::byte> state_; 75 }; 76 77 // A checksum algorithm for which Verify always passes. This can be used to 78 // disable checksum verification for a particular entry format. 79 class IgnoreChecksum final : public ChecksumAlgorithm { 80 public: IgnoreChecksum()81 constexpr IgnoreChecksum() : ChecksumAlgorithm({}) {} 82 Reset()83 void Reset() override {} Update(std::span<const std::byte>)84 void Update(std::span<const std::byte>) override {} 85 }; 86 87 // Calculates a checksum in kAlignmentBytes chunks. Checksum classes can inherit 88 // from this and implement UpdateAligned and FinalizeAligned instead of Update 89 // and Finalize. 90 template <size_t kAlignmentBytes, size_t kBufferSize = kAlignmentBytes> 91 class AlignedChecksum : public ChecksumAlgorithm { 92 public: Update(std::span<const std::byte> data)93 void Update(std::span<const std::byte> data) final { writer_.Write(data); } 94 95 protected: AlignedChecksum(std::span<const std::byte> state)96 constexpr AlignedChecksum(std::span<const std::byte> state) 97 : ChecksumAlgorithm(state), 98 output_(*this), 99 writer_(kAlignmentBytes, output_) {} 100 101 ~AlignedChecksum() = default; 102 103 private: 104 static_assert(kBufferSize >= kAlignmentBytes); 105 Finalize()106 void Finalize() final { 107 writer_.Flush(); 108 FinalizeAligned(); 109 } 110 111 virtual void UpdateAligned(std::span<const std::byte> data) = 0; 112 113 virtual void FinalizeAligned() = 0; 114 115 class CallUpdateAligned final : public Output { 116 public: CallUpdateAligned(AlignedChecksum & object)117 constexpr CallUpdateAligned(AlignedChecksum& object) : object_(object) {} 118 119 private: DoWrite(std::span<const std::byte> data)120 StatusWithSize DoWrite(std::span<const std::byte> data) override { 121 object_.UpdateAligned(data); 122 return StatusWithSize(data.size()); 123 } 124 125 AlignedChecksum& object_; 126 }; 127 128 CallUpdateAligned output_; 129 AlignedWriterBuffer<kBufferSize> writer_; 130 }; 131 132 } // namespace kvs 133 } // namespace pw 134