/* * Copyright (C) 2020 The Android Open Source Project * * 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. */ #define LOG_TAG "ModelArchHasher" #include "ModelArchHasher.h" #include #include #include namespace android::nn { namespace { bool update(SHA256_CTX* hasher, const void* bytes, size_t length) { return SHA256_Update(hasher, bytes, length) != 0; } bool updateSubgraph(SHA256_CTX* hasher, const Model::Subgraph& subgraph) { bool success = true; for (auto& operand : subgraph.operands) { success &= update(hasher, static_cast(&operand.type), sizeof(operand.type)); success &= update( hasher, static_cast(operand.dimensions.data()), sizeof(decltype(operand.dimensions)::value_type) * operand.dimensions.size()); success &= update(hasher, static_cast(&operand.scale), sizeof(operand.scale)); success &= update(hasher, static_cast(&operand.zeroPoint), sizeof(operand.zeroPoint)); success &= update(hasher, static_cast(&operand.lifetime), sizeof(operand.lifetime)); success &= update(hasher, static_cast(&operand.extraParams), sizeof(operand.extraParams)); } for (auto& operation : subgraph.operations) { success &= update(hasher, static_cast(&operation.type), sizeof(operation.type)); success &= update(hasher, static_cast(operation.inputs.data()), sizeof(decltype(operation.inputs)::value_type) * operation.inputs.size()); success &= update(hasher, static_cast(operation.outputs.data()), sizeof(decltype(operation.outputs)::value_type) * operation.outputs.size()); } success &= update( hasher, static_cast(subgraph.inputIndexes.data()), sizeof(decltype(subgraph.inputIndexes)::value_type) * subgraph.inputIndexes.size()); success &= update( hasher, static_cast(subgraph.outputIndexes.data()), sizeof(decltype(subgraph.outputIndexes)::value_type) * subgraph.outputIndexes.size()); return success; } } // namespace bool calcModelArchHash(const Model& model, uint8_t* data) { SHA256_CTX mHasher; if (SHA256_Init(&mHasher) == 0) { return false; } bool success = true; success &= updateSubgraph(&mHasher, model.main); for (auto& subgraph : model.referenced) { success &= updateSubgraph(&mHasher, subgraph); } if (!success) { return false; } if (SHA256_Final(data, &mHasher) == 0) { return false; } return true; } } // namespace android::nn