blob: e579c992ea83ddefd155603330c464d308e07318 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#include "src/lib/digest/node-digest.h"
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <zircon/assert.h>
#include <zircon/types.h>
#include <algorithm>
#include <fbl/algorithm.h>
namespace digest {
zx_status_t NodeDigest::SetNodeSize(size_t node_size) {
if (!IsValidNodeSize(node_size)) {
return ZX_ERR_INVALID_ARGS;
}
node_size_ = node_size;
return ZX_OK;
}
zx_status_t NodeDigest::Reset(size_t data_off, size_t data_len) {
if (data_len < data_off || !IsAligned(data_off)) {
return ZX_ERR_INVALID_ARGS;
}
to_append_ = std::min(data_len - data_off, node_size_);
pad_len_ = node_size_ - to_append_;
digest_.Init();
uint64_t locality = id_ ^ data_off;
digest_.Update(&locality, sizeof(locality));
uint32_t length = static_cast<uint32_t>(to_append_);
digest_.Update(&length, sizeof(length));
// Handle special zero-length case immediately.
if (length == 0) {
digest_.Final();
}
return ZX_OK;
}
size_t NodeDigest::Append(const void* buf, size_t buf_len) {
size_t len = std::min(buf_len, to_append_);
if (len == 0) {
return 0;
}
digest_.Update(buf, len);
to_append_ -= len;
if (to_append_ == 0) {
if (pad_len_ > 0) {
PadWithZeros();
} else {
digest_.Final();
}
}
return len;
}
void NodeDigest::PadWithZeros() {
static const uint8_t kZeroes[64] = {0};
size_t padding = to_append_ + pad_len_;
if (padding == 0) {
return;
}
while (padding > sizeof(kZeroes)) {
digest_.Update(kZeroes, sizeof(kZeroes));
padding -= sizeof(kZeroes);
}
digest_.Update(kZeroes, padding);
digest_.Final();
to_append_ = 0;
pad_len_ = 0;
}
} // namespace digest