1
+ // Copyright (c) 2021 MIT Digital Currency Initiative,
2
+ // Federal Reserve Bank of Boston
3
+ // Distributed under the MIT software license, see the accompanying
4
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
+
6
+ #include " uhs/transaction/transaction.hpp"
7
+ #include " uhs/twophase/locking_shard/locking_shard.hpp"
8
+ #include " util/common/hash.hpp"
9
+ #include " util/common/hashmap.hpp"
10
+ #include " util/common/keys.hpp"
11
+ #include " util/common/config.hpp"
12
+ #include " util/common/random_source.hpp"
13
+ #include " util/common/snapshot_map.hpp"
14
+
15
+ #include < secp256k1_bppp.h>
16
+ #include < benchmark/benchmark.h>
17
+ #include < gtest/gtest.h>
18
+ #include < unordered_map>
19
+ #include < random>
20
+ #include < unordered_set>
21
+
22
+ #define SWEEP_MAX 100000
23
+ #define EPOCH 1000
24
+
25
+ using namespace cbdc ;
26
+ using secp256k1_context_destroy_type = void (*)(secp256k1_context*);
27
+ using uhs_element = locking_shard::locking_shard::uhs_element;
28
+
29
+ struct GensDeleter {
30
+ explicit GensDeleter (secp256k1_context* ctx) : m_ctx(ctx) {}
31
+
32
+ void operator ()(secp256k1_bppp_generators* gens) const {
33
+ secp256k1_bppp_generators_destroy (m_ctx, gens);
34
+ }
35
+
36
+ secp256k1_context* m_ctx;
37
+ };
38
+
39
+ static std::default_random_engine m_shuffle;
40
+
41
+ static const inline auto rnd
42
+ = std::make_unique<random_source>(config::random_source);
43
+
44
+ static std::unique_ptr<secp256k1_context, secp256k1_context_destroy_type>
45
+ secp{secp256k1_context_create (SECP256K1_CONTEXT_NONE),
46
+ &secp256k1_context_destroy};
47
+
48
+ // / should be set to exactly `floor(log_base(value)) + 1`
49
+ // /
50
+ // / We use n_bits = 64, base = 16, so this should always be 24.
51
+ static const inline auto generator_count = 16 + 8 ;
52
+
53
+ static std::unique_ptr<secp256k1_bppp_generators, GensDeleter>
54
+ generators{
55
+ secp256k1_bppp_generators_create (secp.get (),
56
+ generator_count),
57
+ GensDeleter (secp.get ())};
58
+
59
+ static auto gen_map (uint64_t map_size, bool deleted = false ) -> snapshot_map<hash_t, uhs_element> {
60
+ std::uniform_int_distribution<uint64_t > dist (EPOCH - 100 , EPOCH + 100 );
61
+ auto uhs = snapshot_map<hash_t , uhs_element>();
62
+
63
+ auto comm = commit (secp.get (), 10 , hash_t {}).value ();
64
+ auto rng
65
+ = transaction::prove (secp.get (),
66
+ generators.get (),
67
+ *rnd,
68
+ {hash_t {}, 10 },
69
+ &comm);
70
+ auto commitment = serialize_commitment (secp.get (), comm);
71
+
72
+ for (uint64_t i = 1 ; i <= map_size; i++) {
73
+ transaction::compact_output out{commitment, rng, rnd->random_hash ()};
74
+ auto del = deleted ? std::optional<uint64_t >{dist (m_shuffle)} : std::nullopt;
75
+ uhs_element el0{out, 0 , del};
76
+ auto key = transaction::calculate_uhs_id (out);
77
+ uhs.emplace (key, el0);
78
+ }
79
+ return uhs;
80
+ }
81
+
82
+ static auto audit (snapshot_map<hash_t , uhs_element>& uhs,
83
+ snapshot_map<hash_t , uhs_element>& locked,
84
+ snapshot_map<hash_t , uhs_element>& spent)
85
+ -> std::optional<commitment_t> {
86
+
87
+ {
88
+ uhs.snapshot ();
89
+ locked.snapshot ();
90
+ spent.snapshot ();
91
+ }
92
+
93
+ bool failed = false ;
94
+ uint64_t epoch = EPOCH;
95
+
96
+ static constexpr auto scratch_size = 8192UL * 1024UL ;
97
+ [[maybe_unused]] secp256k1_scratch_space* scratch
98
+ = secp256k1_scratch_space_create (secp.get (), scratch_size);
99
+
100
+ static constexpr size_t threshold = 100000 ;
101
+ size_t cursor = 0 ;
102
+ std::vector<commitment_t > comms{};
103
+ auto * range_batch = secp256k1_bppp_rangeproof_batch_create (secp.get (), 34 * (threshold + 1 ));
104
+ auto summarize
105
+ = [&](const snapshot_map<hash_t , uhs_element>& m) {
106
+ for (const auto & [id, elem] : m) {
107
+ if (failed) {
108
+ break ;
109
+ }
110
+ if (elem.m_creation_epoch <= epoch
111
+ && (!elem.m_deletion_epoch .has_value ()
112
+ || (elem.m_deletion_epoch .value () > epoch))) {
113
+
114
+ auto uhs_id
115
+ = transaction::calculate_uhs_id (elem.m_out );
116
+ if (uhs_id != id) {
117
+ failed = true ;
118
+ }
119
+ auto comm = elem.m_out .m_value_commitment ;
120
+ auto c = deserialize_commitment (secp.get (), comm).value ();
121
+ auto r = transaction::validation::range_batch_add (
122
+ *range_batch,
123
+ scratch,
124
+ elem.m_out .m_range ,
125
+ c
126
+ );
127
+ if (!r.has_value ()) {
128
+ ++cursor;
129
+ }
130
+ comms.push_back (comm);
131
+ }
132
+ if (cursor >= threshold) {
133
+ failed = transaction::validation::check_range_batch (*range_batch).has_value ();
134
+ [[maybe_unused]] auto res = secp256k1_bppp_rangeproof_batch_clear (secp.get (), range_batch);
135
+ cursor = 0 ;
136
+ }
137
+ }
138
+ if (cursor > 0 ) {
139
+ failed = transaction::validation::check_range_batch (*range_batch).has_value ();
140
+ [[maybe_unused]] auto res = secp256k1_bppp_rangeproof_batch_clear (secp.get (), range_batch);
141
+ cursor = 0 ;
142
+ }
143
+ };
144
+
145
+ summarize (uhs);
146
+ summarize (locked);
147
+ summarize (spent);
148
+ [[maybe_unused]] auto res = secp256k1_bppp_rangeproof_batch_destroy (secp.get (), range_batch);
149
+ free (range_batch);
150
+
151
+ secp256k1_scratch_space_destroy (secp.get (), scratch);
152
+
153
+ // std::vector<commitment_t> comms{};
154
+ // comms.reserve(pool.size());
155
+ //
156
+ // for(auto& f : pool) {
157
+ // auto c = f.get();
158
+ // failed = !c.has_value();
159
+ // if(failed) {
160
+ // break;
161
+ // }
162
+ // comms.emplace_back(std::move(c.value()));
163
+ // k }
164
+
165
+ {
166
+ uhs.release_snapshot ();
167
+ locked.release_snapshot ();
168
+ spent.release_snapshot ();
169
+ }
170
+
171
+ if (failed) {
172
+ return std::nullopt;
173
+ }
174
+
175
+ return sum_commitments (secp.get (), comms);
176
+ }
177
+
178
+ static void audit_routine (benchmark::State& state) {
179
+ auto key_count = state.range (0 );
180
+
181
+ auto seed = std::chrono::high_resolution_clock::now ()
182
+ .time_since_epoch ()
183
+ .count ();
184
+ seed %= std::numeric_limits<uint32_t >::max ();
185
+ m_shuffle.seed (static_cast <uint32_t >(seed));
186
+
187
+ uint32_t locked_sz{};
188
+ uint32_t spent_sz{};
189
+ {
190
+ std::uniform_int_distribution<uint32_t > locked (0 , key_count);
191
+ locked_sz = locked (m_shuffle);
192
+ std::uniform_int_distribution<uint32_t > spent (0 , key_count - locked_sz);
193
+ spent_sz = spent (m_shuffle);
194
+ }
195
+
196
+ snapshot_map<hash_t , uhs_element> uhs = gen_map (key_count - (locked_sz + spent_sz));
197
+ snapshot_map<hash_t , uhs_element> locked = gen_map (locked_sz);
198
+ snapshot_map<hash_t , uhs_element> spent = gen_map (spent_sz, true );
199
+ for (auto _ : state) {
200
+ auto res = audit (uhs, locked, spent);
201
+ ASSERT_NE (res, std::nullopt);
202
+ }
203
+ }
204
+
205
+ BENCHMARK (audit_routine)
206
+ ->RangeMultiplier(10 )
207
+ ->Range(10 , SWEEP_MAX)
208
+ ->Complexity(benchmark::oAuto);
209
+
210
+ BENCHMARK_MAIN ();
0 commit comments