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