1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "ModelArchHasher"
18
19 #include "ModelArchHasher.h"
20
21 #include <android-base/logging.h>
22 #include <nnapi/Types.h>
23 #include <openssl/sha.h>
24
25 namespace android::nn {
26
27 namespace {
28
update(SHA256_CTX * hasher,const void * bytes,size_t length)29 bool update(SHA256_CTX* hasher, const void* bytes, size_t length) {
30 return SHA256_Update(hasher, bytes, length) != 0;
31 }
32
updateSubgraph(SHA256_CTX * hasher,const Model::Subgraph & subgraph)33 bool updateSubgraph(SHA256_CTX* hasher, const Model::Subgraph& subgraph) {
34 bool success = true;
35 for (auto& operand : subgraph.operands) {
36 success &= update(hasher, static_cast<const void*>(&operand.type), sizeof(operand.type));
37 success &= update(
38 hasher, static_cast<const void*>(operand.dimensions.data()),
39 sizeof(decltype(operand.dimensions)::value_type) * operand.dimensions.size());
40 success &= update(hasher, static_cast<const void*>(&operand.scale), sizeof(operand.scale));
41 success &= update(hasher, static_cast<const void*>(&operand.zeroPoint),
42 sizeof(operand.zeroPoint));
43 success &= update(hasher, static_cast<const void*>(&operand.lifetime),
44 sizeof(operand.lifetime));
45 success &= update(hasher, static_cast<const void*>(&operand.extraParams),
46 sizeof(operand.extraParams));
47 }
48
49 for (auto& operation : subgraph.operations) {
50 success &=
51 update(hasher, static_cast<const void*>(&operation.type), sizeof(operation.type));
52 success &= update(hasher, static_cast<const void*>(operation.inputs.data()),
53 sizeof(decltype(operation.inputs)::value_type) * operation.inputs.size());
54 success &=
55 update(hasher, static_cast<const void*>(operation.outputs.data()),
56 sizeof(decltype(operation.outputs)::value_type) * operation.outputs.size());
57 }
58
59 success &= update(
60 hasher, static_cast<const void*>(subgraph.inputIndexes.data()),
61 sizeof(decltype(subgraph.inputIndexes)::value_type) * subgraph.inputIndexes.size());
62 success &= update(
63 hasher, static_cast<const void*>(subgraph.outputIndexes.data()),
64 sizeof(decltype(subgraph.outputIndexes)::value_type) * subgraph.outputIndexes.size());
65 return success;
66 }
67
68 } // namespace
69
calcModelArchHash(const Model & model,uint8_t * data)70 bool calcModelArchHash(const Model& model, uint8_t* data) {
71 SHA256_CTX mHasher;
72 if (SHA256_Init(&mHasher) == 0) {
73 return false;
74 }
75
76 bool success = true;
77 success &= updateSubgraph(&mHasher, model.main);
78 for (auto& subgraph : model.referenced) {
79 success &= updateSubgraph(&mHasher, subgraph);
80 }
81 if (!success) {
82 return false;
83 }
84
85 if (SHA256_Final(data, &mHasher) == 0) {
86 return false;
87 }
88 return true;
89 }
90
91 } // namespace android::nn
92