Electroneum
Loading...
Searching...
No Matches
crypto.h
Go to the documentation of this file.
1// Copyrights(c) 2017-2021, The Electroneum Project
2// Copyrights(c) 2014-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29//
30// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
31
32#pragma once
33
34#include <cstddef>
35#include <iostream>
36#include <boost/optional.hpp>
37#include <type_traits>
38#include <boost/thread/mutex.hpp>
39#include <boost/thread/lock_guard.hpp>
40#include <boost/archive/iterators/binary_from_base64.hpp>
41#include <boost/archive/iterators/base64_from_binary.hpp>
42#include <boost/archive/iterators/transform_width.hpp>
43#include <boost/algorithm/string.hpp>
44#include <boost/algorithm/hex.hpp>
45#include <vector>
46#include <random>
47
49
50#include "common/pod-class.h"
51#include "memwipe.h"
52#include "mlocker.h"
53#include "generic-ops.h"
54#include "hex.h"
55#include "span.h"
56#include "hash.h"
57#include "warnings.h"
58
59extern "C" {
60#include "crypto-ops.h"
61}
62
63namespace crypto {
64
65 extern "C" {
66#include "random.h"
67 }
68
69#pragma pack(push, 1)
71 char data[32];
72 };
73
75 char data[32];
76 };
77
79 friend class crypto_ops;
80 };
81
83
85 std::vector<public_key> keys;
86 int rows;
87 };
88
90 std::vector<secret_key> keys;
91 int rows;
92 };
93
95 int cols;
96 int rows;
97 std::vector<secret_keyV> column_vectors;
98 };
99
101 friend class crypto_ops;
102 };
103
105 friend class crypto_ops;
106 };
107
109 ec_scalar c, r;
110 friend class crypto_ops;
111 };
112
113#pragma pack(pop)
114
115 void hash_to_scalar(const void *data, size_t length, ec_scalar &res);
116 void random32_unbiased(unsigned char *bytes);
118 size_t rs_comm_size(size_t pubs_count);
123 };
124 struct rs_comm {
127 };
129
130 void hash_to_ec(const public_key &key, ge_p3 &res);
131 void hash_to_ec(const hash& h, ge_p3 &res);
133
134
135 static_assert(sizeof(ec_point) == 32 && sizeof(ec_scalar) == 32 &&
136 sizeof(public_key) == 32 && sizeof(secret_key) == 32 &&
137 sizeof(key_derivation) == 32 && sizeof(key_image) == 32 &&
138 sizeof(signature) == 64, "Invalid structure size");
139
140 class crypto_ops {
141 crypto_ops();
142 crypto_ops(const crypto_ops &);
143 void operator=(const crypto_ops &);
144 ~crypto_ops();
145
146 static secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false);
147 friend secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key, bool recover);
148 static bool check_key(const public_key &);
149 friend bool check_key(const public_key &);
150 static bool secret_key_to_public_key(const secret_key &, public_key &);
151 friend bool secret_key_to_public_key(const secret_key &, public_key &);
152 static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
153 friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
154 static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res);
155 friend void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res);
156 static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
157 friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
158 static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
159 friend void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
160 static bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
161 friend bool derive_subaddress_public_key(const public_key &, const key_derivation &, std::size_t, public_key &);
162 static void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
163 friend void generate_signature(const hash &, const public_key &, const secret_key &, signature &);
164 static bool check_signature(const hash &, const public_key &, const signature &);
165 friend bool check_signature(const hash &, const public_key &, const signature &);
166 static void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
167 friend void generate_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const secret_key &, signature &);
168 static bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
169 friend bool check_tx_proof(const hash &, const public_key &, const public_key &, const boost::optional<public_key> &, const public_key &, const signature &);
170 static void generate_key_image(const public_key &, const secret_key &, key_image &);
171 friend void generate_key_image(const public_key &, const secret_key &, key_image &);
172 static void generate_input_signature(const hash prefix_hash, const uint32_t input_index, const secret_key sec_view, const secret_key sec_spend, signature &sig);
173 friend void generate_input_signature(const hash prefix_hash, const uint32_t input_index, const secret_key sec_view, const secret_key sec_spend, signature &sig);
174 static bool verify_input_signature(const hash &prefix_hash,const uint32_t input_index, const public_key pub_view, const public_key pub_spend, signature sig);
175 friend bool verify_input_signature(const hash &prefix_hash,const uint32_t input_index, const public_key pub_view, const public_key pub_spend, signature sig);
176 static public_key addKeys(const public_key &A, const public_key &B);
177 friend public_key addKeys(const public_key &A, const public_key &B);
178 static secret_key addSecretKeys(const secret_key &A, const secret_key &B);
180 static void generate_ring_signature(const hash &, const key_image &,
181 const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
182 friend void generate_ring_signature(const hash &, const key_image &,
183 const public_key *const *, std::size_t, const secret_key &, std::size_t, signature *);
184 static bool check_ring_signature(const hash &, const key_image &,
185 const public_key *const *, std::size_t, const signature *);
186 friend bool check_ring_signature(const hash &, const key_image &,
187 const public_key *const *, std::size_t, const signature *);
188
189 static std::string sign_message(const std::string &message, const std::string &privateKey);
190 friend std::string sign_message(const std::string &message, const std::string &privateKey);
191 static bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature);
192 friend bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature);
193 static bool verify_signature(const std::string &message, std::vector<std::string> publicKey, const std::string &signature);
194 friend bool verify_signature(const std::string &message, std::vector<std::string> publicKey, const std::string &signature);
195
196 static std::vector<std::string> create_ed25519_keypair();
197 friend std::vector<std::string> create_ed25519_keypair();
198
199 static std::string base64_decode(std::string val);
200 friend std::string base64_decode(std::string val);
201 static std::string base64_encode(std::string val);
202 friend std::string base64_encode(std::string val);
203 };
204
205 void generate_random_bytes_thread_safe(size_t N, uint8_t *bytes);
206
207 /* Generate N random bytes
208 */
209 inline void rand(size_t N, uint8_t *bytes) {
211 }
212
213 /* Generate a value filled with random bytes.
214 */
215 template<typename T>
216 typename std::enable_if<std::is_pod<T>::value, T>::type rand() {
217 typename std::remove_cv<T>::type res;
219 return res;
220 }
221
222 /* UniformRandomBitGenerator using crypto::rand<uint64_t>()
223 */
225 {
227 static constexpr result_type min() { return 0; }
228 static constexpr result_type max() { return result_type(-1); }
230 };
231
232 /* Generate a random value between range_min and range_max
233 */
234 template<typename T>
235 typename std::enable_if<std::is_integral<T>::value, T>::type rand_range(T range_min, T range_max) {
237 std::uniform_int_distribution<T> dis(range_min, range_max);
238 return dis(rd);
239 }
240
241 /* Generate a random index between 0 and sz-1
242 */
243 template<typename T>
244 typename std::enable_if<std::is_unsigned<T>::value, T>::type rand_idx(T sz) {
245 return crypto::rand_range<T>(0, sz-1);
246 }
247
248 /* Generate a new key pair
249 */
250 inline secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key& recovery_key = secret_key(), bool recover = false) {
251 return crypto_ops::generate_keys(pub, sec, recovery_key, recover);
252 }
253
254 /* Check a public key. Returns true if it is valid, false otherwise.
255 */
256 inline bool check_key(const public_key &key) {
257 return crypto_ops::check_key(key);
258 }
259
260 /* Checks a private key and computes the corresponding public key.
261 */
262 inline bool secret_key_to_public_key(const secret_key &sec, public_key &pub) {
263 return crypto_ops::secret_key_to_public_key(sec, pub);
264 }
265
266 /* To generate an ephemeral key used to send etn to:
267 * * The sender generates a new key pair, which becomes the transaction key. The public transaction key is included in "extra" field.
268 * * Both the sender and the receiver generate key derivation from the transaction key, the receivers' "view" key and the output index.
269 * * The sender uses key derivation and the receivers' "spend" key to derive an ephemeral public key.
270 * * The receiver can either derive the public key (to check that the transaction is addressed to him) or the private key (to spend the etn).
271 */
272 inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
273 return crypto_ops::generate_key_derivation(key1, key2, derivation);
274 }
275 inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index,
276 const public_key &base, public_key &derived_key) {
277 return crypto_ops::derive_public_key(derivation, output_index, base, derived_key);
278 }
279 inline void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) {
280 return crypto_ops::derivation_to_scalar(derivation, output_index, res);
281 }
282 inline void derive_secret_key(const key_derivation &derivation, std::size_t output_index,
283 const secret_key &base, secret_key &derived_key) {
284 crypto_ops::derive_secret_key(derivation, output_index, base, derived_key);
285 }
286 inline bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &result) {
287 return crypto_ops::derive_subaddress_public_key(out_key, derivation, output_index, result);
288 }
289
290 /* Generation and checking of a standard signature.
291 */
292 inline void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig) {
293 crypto_ops::generate_signature(prefix_hash, pub, sec, sig);
294 }
295 inline bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
296 return crypto_ops::check_signature(prefix_hash, pub, sig);
297 }
298
299 inline void generate_input_signature(const hash prefix_hash, const uint32_t input_index, const secret_key sec_view, const secret_key sec_spend, signature &sig){
300 return crypto_ops::generate_input_signature(prefix_hash, input_index, sec_view, sec_spend, sig);
301 }
302
303 inline bool verify_input_signature(const hash &prefix_hash,const uint32_t input_index, const public_key pub_view, const public_key pub_spend, signature sig) {
304 return crypto_ops::verify_input_signature(prefix_hash, input_index, pub_view, pub_spend, sig);
305 }
306
307 /* Generation and checking of a tx proof; given a tx pubkey R, the recipient's view pubkey A, and the key
308 * derivation D, the signature proves the knowledge of the tx secret key r such that R=r*G and D=r*A
309 * When the recipient's address is a subaddress, the tx pubkey R is defined as R=r*B where B is the recipient's spend pubkey
310 */
311 inline void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const secret_key &r, signature &sig) {
312 crypto_ops::generate_tx_proof(prefix_hash, R, A, B, D, r, sig);
313 }
314 inline bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional<public_key> &B, const public_key &D, const signature &sig) {
315 return crypto_ops::check_tx_proof(prefix_hash, R, A, B, D, sig);
316 }
317
318 /* To send etn to a key:
319 * * The sender generates an ephemeral key and includes it in transaction output.
320 * * To spend the etn, the receiver generates a key image from it.
321 * * Then he selects a bunch of outputs, including the one he spends, and uses them to generate a ring signature.
322 * To check the signature, it is necessary to collect all the keys that were used to generate it. To detect double spends, it is necessary to check that each key image is used at most once.
323 */
324 inline void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image) {
325 crypto_ops::generate_key_image(pub, sec, image);
326 }
327 inline void generate_ring_signature(const hash &prefix_hash, const key_image &image,
328 const public_key *const *pubs, std::size_t pubs_count,
329 const secret_key &sec, std::size_t sec_index,
330 signature *sig) {
331 crypto_ops::generate_ring_signature(prefix_hash, image, pubs, pubs_count, sec, sec_index, sig);
332 }
333 inline bool check_ring_signature(const hash &prefix_hash, const key_image &image,
334 const public_key *const *pubs, std::size_t pubs_count,
335 const signature *sig) {
336 return crypto_ops::check_ring_signature(prefix_hash, image, pubs, pubs_count, sig);
337 }
338
339 inline public_key addKeys(const public_key &A, const public_key &B) {
340 return crypto_ops::addKeys(A, B);
341 }
342
343 /* Variants with vector<const public_key *> parameters.
344 */
345 inline void generate_ring_signature(const hash &prefix_hash, const key_image &image,
346 const std::vector<const public_key *> &pubs,
347 const secret_key &sec, std::size_t sec_index,
348 signature *sig) {
349 generate_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sec, sec_index, sig);
350 }
351 inline bool check_ring_signature(const hash &prefix_hash, const key_image &image,
352 const std::vector<const public_key *> &pubs,
353 const signature *sig) {
354 return check_ring_signature(prefix_hash, image, pubs.data(), pubs.size(), sig);
355 }
356
357 inline std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) {
359 }
360 inline std::ostream &operator <<(std::ostream &o, const crypto::secret_key &v) {
362 }
363 inline std::ostream &operator <<(std::ostream &o, const crypto::key_derivation &v) {
365 }
366 inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) {
368 }
369 inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) {
371 }
372
373 const extern crypto::public_key null_pkey;
374 const extern crypto::secret_key null_skey;
375
376 inline std::string sign_message(const std::string &message, const std::string &privateKey) {
377 return crypto_ops::sign_message(message, privateKey);
378 }
379
380 inline bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature) {
381 return crypto_ops::verify_signature(message, publicKey, signature);
382 }
383
384 inline bool verify_signature(const std::string &message, std::vector<std::string> publicKey, const std::string &signature) {
385 return crypto_ops::verify_signature(message, publicKey, signature);
386 }
387
388 inline std::vector<std::string> create_ed25519_keypair() {
390 }
391
392 inline std::string base64_decode(const std::string &val) {
393 using namespace boost::archive::iterators;
394 using It = transform_width<binary_from_base64<std::string::const_iterator>, 8, 6>;
395 return boost::algorithm::trim_right_copy_if(std::string(It(std::begin(val)), It(std::end(val))), [](char c) {
396 return c == '\0';
397 });
398 }
399
400 inline std::string base64_encode(const std::string &val) {
401 using namespace boost::archive::iterators;
402 using It = base64_from_binary<transform_width<std::string::const_iterator, 6, 8>>;
403 auto tmp = std::string(It(std::begin(val)), It(std::end(val)));
404 return tmp.append((3 - val.size() % 3) % 3, '=');
405 }
406}
407
408CRYPTO_MAKE_HASHABLE(public_key)
410CRYPTO_MAKE_HASHABLE(key_image)
411CRYPTO_MAKE_COMPARABLE(signature)
friend std::vector< std::string > create_ed25519_keypair()
Definition crypto.h:388
friend std::string base64_decode(std::string val)
friend secret_key addSecretKeys(const secret_key &A, const secret_key &B)
friend std::string base64_encode(std::string val)
std::string publicKey
std::string privateKey
std::string message("Message requiring signing")
#define CRYPTO_MAKE_HASHABLE_CONSTANT_TIME(type)
Definition generic-ops.h:80
#define CRYPTO_MAKE_COMPARABLE(type)
Definition generic-ops.h:39
#define CRYPTO_MAKE_HASHABLE(type)
Definition generic-ops.h:76
const char * res
const char * key
crypto namespace.
Definition crypto.cpp:58
POD_CLASS secret_keyV
Definition crypto.h:89
const crypto::public_key null_pkey
Definition crypto.cpp:72
void generate_signature(const hash &prefix_hash, const public_key &pub, const secret_key &sec, signature &sig)
Definition crypto.h:292
POD_CLASS public_keyM
Definition crypto.h:94
bool verify_signature(const std::string &message, const std::string &publicKey, const std::string &signature)
Definition crypto.h:380
bool check_key(const public_key &key)
Definition crypto.h:256
bool verify_input_signature(const hash &prefix_hash, const uint32_t input_index, const public_key pub_view, const public_key pub_spend, signature sig)
Definition crypto.h:303
public_key addKeys(const public_key &A, const public_key &B)
Definition crypto.h:339
void generate_random_bytes_thread_safe(size_t N, uint8_t *bytes)
Definition crypto.cpp:91
std::enable_if< std::is_pod< T >::value, T >::type rand()
Definition crypto.h:216
POD_CLASS ec_point
Definition crypto.h:70
void hash_to_ec(const public_key &key, ge_p3 &res)
Definition crypto.cpp:479
void generate_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional< public_key > &B, const public_key &D, const secret_key &r, signature &sig)
Definition crypto.h:311
POD_CLASS signature
Definition crypto.h:108
const crypto::secret_key null_skey
Definition crypto.cpp:73
epee::mlocked< tools::scrubbed< ec_scalar > > secret_key
Definition crypto.h:82
std::enable_if< std::is_integral< T >::value, T >::type rand_range(T range_min, T range_max)
Definition crypto.h:235
unsigned char uint8_t
Definition hash.h:125
void generate_input_signature(const hash prefix_hash, const uint32_t input_index, const secret_key sec_view, const secret_key sec_spend, signature &sig)
Definition crypto.h:299
POD_CLASS public_keyV
Definition crypto.h:84
friend class crypto_ops
Definition crypto.h:110
bool derive_subaddress_public_key(const public_key &out_key, const key_derivation &derivation, std::size_t output_index, public_key &result)
Definition crypto.h:286
size_t rs_comm_size(size_t pubs_count)
Definition crypto.cpp:511
POD_CLASS key_derivation
Definition crypto.h:101
secret_key generate_keys(public_key &pub, secret_key &sec, const secret_key &recovery_key=secret_key(), bool recover=false)
Definition crypto.h:250
void derive_secret_key(const key_derivation &derivation, std::size_t output_index, const secret_key &base, secret_key &derived_key)
Definition crypto.h:282
std::vector< secret_keyV > column_vectors
Definition crypto.h:97
unsigned __int64 uint64_t
Definition hash.h:137
bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation)
Definition crypto.h:272
void generate_ring_signature(const hash &prefix_hash, const key_image &image, const public_key *const *pubs, std::size_t pubs_count, const secret_key &sec, std::size_t sec_index, signature *sig)
Definition crypto.h:327
POD_CLASS public_key
Definition crypto.h:79
void random32_unbiased(unsigned char *bytes)
Definition crypto.cpp:110
bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key)
Definition crypto.h:275
void hash_to_point(const crypto::hash &h, crypto::ec_point &res)
Definition crypto.cpp:496
std::ostream & operator<<(std::ostream &o, const crypto::public_key &v)
Definition crypto.h:357
std::string base64_encode(const std::string &val)
Definition crypto.h:400
POD_CLASS key_image
Definition crypto.h:105
bool check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig)
Definition crypto.h:295
unsigned int uint32_t
Definition hash.h:127
POD_CLASS ec_scalar
Definition crypto.h:74
std::string base64_decode(const std::string &val)
Definition crypto.h:392
bool secret_key_to_public_key(const secret_key &sec, public_key &pub)
Definition crypto.h:262
std::enable_if< std::is_unsigned< T >::value, T >::type rand_idx(T sz)
Definition crypto.h:244
bool check_tx_proof(const hash &prefix_hash, const public_key &R, const public_key &A, const boost::optional< public_key > &B, const public_key &D, const signature &sig)
Definition crypto.h:314
void hash_to_scalar(const void *data, size_t length, ec_scalar &res)
Definition crypto.cpp:126
int rows
Definition crypto.h:86
POD_CLASS hash
Definition hash.h:50
void random_scalar(ec_scalar &res)
Definition crypto.cpp:122
void generate_key_image(const public_key &pub, const secret_key &sec, key_image &image)
Definition crypto.h:324
std::string sign_message(const std::string &message, const std::string &privateKey)
Definition crypto.h:376
void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res)
Definition crypto.h:279
bool check_ring_signature(const hash &prefix_hash, const key_image &image, const public_key *const *pubs, std::size_t pubs_count, const signature *sig)
Definition crypto.h:333
std::vector< std::string > create_ed25519_keypair()
Definition crypto.h:388
span< const std::uint8_t > as_byte_span(const T &src) noexcept
Definition span.h:153
#define POD_CLASS
Definition pod-class.h:44
static constexpr result_type min()
Definition crypto.h:227
result_type operator()() const
Definition crypto.h:229
uint64_t result_type
Definition crypto.h:226
static constexpr result_type max()
Definition crypto.h:228
struct ec_point_pair ab[]
Definition crypto.h:126
static void formatted(std::ostream &out, const span< const std::uint8_t > src)
Append < + src + > as hex to out.
Definition hex.cpp:76
#define DISABLE_VS_WARNINGS(w)
Definition warnings.h:18
#define POP_WARNINGS
Definition warnings.h:17
#define PUSH_WARNINGS
Definition warnings.h:16
#define T(x)