Crypto++ 8.9
Free C++ class library of cryptographic schemes
hmqv.h
Go to the documentation of this file.
1// hmqv.h - written and placed in the public domain by Uri Blumenthal
2// Shamelessly based upon Wei Dai's MQV source files
3
4#ifndef CRYPTOPP_HMQV_H
5#define CRYPTOPP_HMQV_H
6
7/// \file hmqv.h
8/// \brief Classes for Hashed Menezes-Qu-Vanstone key agreement in GF(p)
9/// \since Crypto++ 5.6.4
10
11#include "gfpcrypt.h"
12#include "algebra.h"
13#include "sha.h"
14
15NAMESPACE_BEGIN(CryptoPP)
16
17/// \brief Hashed Menezes-Qu-Vanstone in GF(p)
18/// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
19/// Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
20/// \sa MQV, HMQV, FHMQV, and AuthenticatedKeyAgreementDomain
21/// \since Crypto++ 5.6.4
22template <class GROUP_PARAMETERS, class COFACTOR_OPTION = typename GROUP_PARAMETERS::DefaultCofactorOption, class HASH = SHA512>
24{
25public:
26 typedef GROUP_PARAMETERS GroupParameters;
27 typedef typename GroupParameters::Element Element;
29
30 virtual ~HMQV_Domain() {}
31
32 /// \brief Construct a HMQV domain
33 /// \param clientRole flag indicating initiator or recipient
34 /// \details <tt>clientRole = true</tt> indicates initiator, and
35 /// <tt>clientRole = false</tt> indicates recipient or server.
36 HMQV_Domain(bool clientRole = true)
37 : m_role(clientRole ? RoleClient : RoleServer) {}
38
39 /// \brief Construct a HMQV domain
40 /// \param params group parameters and options
41 /// \param clientRole flag indicating initiator or recipient
42 /// \details <tt>clientRole = true</tt> indicates initiator, and
43 /// <tt>clientRole = false</tt> indicates recipient or server.
44 HMQV_Domain(const GroupParameters &params, bool clientRole = true)
45 : m_role(clientRole ? RoleClient : RoleServer), m_groupParameters(params) {}
46
47 /// \brief Construct a HMQV domain
48 /// \param bt BufferedTransformation with group parameters and options
49 /// \param clientRole flag indicating initiator or recipient
50 /// \details <tt>clientRole = true</tt> indicates initiator, and
51 /// <tt>clientRole = false</tt> indicates recipient or server.
52 HMQV_Domain(BufferedTransformation &bt, bool clientRole = true)
53 : m_role(clientRole ? RoleClient : RoleServer)
54 {m_groupParameters.BERDecode(bt);}
55
56 /// \brief Construct a HMQV domain
57 /// \tparam T1 template parameter used as a constructor parameter
58 /// \param v1 first parameter
59 /// \param clientRole flag indicating initiator or recipient
60 /// \details v1 is passed directly to the GROUP_PARAMETERS object.
61 /// \details <tt>clientRole = true</tt> indicates initiator, and
62 /// <tt>clientRole = false</tt> indicates recipient or server.
63 template <class T1>
64 HMQV_Domain(T1 v1, bool clientRole = true)
65 : m_role(clientRole ? RoleClient : RoleServer)
66 {m_groupParameters.Initialize(v1);}
67
68 /// \brief Construct a HMQV domain
69 /// \tparam T1 template parameter used as a constructor parameter
70 /// \tparam T2 template parameter used as a constructor parameter
71 /// \param v1 first parameter
72 /// \param v2 second parameter
73 /// \param clientRole flag indicating initiator or recipient
74 /// \details v1 and v2 are passed directly to the GROUP_PARAMETERS object.
75 /// \details <tt>clientRole = true</tt> indicates initiator, and
76 /// <tt>clientRole = false</tt> indicates recipient or server.
77 template <class T1, class T2>
78 HMQV_Domain(T1 v1, T2 v2, bool clientRole = true)
79 : m_role(clientRole ? RoleClient : RoleServer)
80 {m_groupParameters.Initialize(v1, v2);}
81
82 /// \brief Construct a HMQV domain
83 /// \tparam T1 template parameter used as a constructor parameter
84 /// \tparam T2 template parameter used as a constructor parameter
85 /// \tparam T3 template parameter used as a constructor parameter
86 /// \param v1 first parameter
87 /// \param v2 second parameter
88 /// \param v3 third parameter
89 /// \param clientRole flag indicating initiator or recipient
90 /// \details v1, v2 and v3 are passed directly to the GROUP_PARAMETERS object.
91 /// \details <tt>clientRole = true</tt> indicates initiator, and
92 /// <tt>clientRole = false</tt> indicates recipient or server.
93 template <class T1, class T2, class T3>
94 HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole = true)
95 : m_role(clientRole ? RoleClient : RoleServer)
96 {m_groupParameters.Initialize(v1, v2, v3);}
97
98 /// \brief Construct a HMQV domain
99 /// \tparam T1 template parameter used as a constructor parameter
100 /// \tparam T2 template parameter used as a constructor parameter
101 /// \tparam T3 template parameter used as a constructor parameter
102 /// \tparam T4 template parameter used as a constructor parameter
103 /// \param v1 first parameter
104 /// \param v2 second parameter
105 /// \param v3 third parameter
106 /// \param v4 third parameter
107 /// \param clientRole flag indicating initiator or recipient
108 /// \details v1, v2, v3 and v4 are passed directly to the GROUP_PARAMETERS object.
109 /// \details <tt>clientRole = true</tt> indicates initiator, and
110 /// <tt>clientRole = false</tt> indicates recipient or server.
111 template <class T1, class T2, class T3, class T4>
112 HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole = true)
113 : m_role(clientRole ? RoleClient : RoleServer)
114 {m_groupParameters.Initialize(v1, v2, v3, v4);}
115
116public:
117
118 /// \brief Retrieves the group parameters for this domain
119 /// \return the group parameters for this domain as a const reference
120 const GroupParameters & GetGroupParameters() const {return m_groupParameters;}
121
122 /// \brief Retrieves the group parameters for this domain
123 /// \return the group parameters for this domain as a non-const reference
124 GroupParameters & AccessGroupParameters() {return m_groupParameters;}
125
126 /// \brief Retrieves the crypto parameters for this domain
127 /// \return the crypto parameters for this domain as a non-const reference
128 CryptoParameters & AccessCryptoParameters() {return AccessAbstractGroupParameters();}
129
130 /// \brief Provides the size of the agreed value
131 /// \return size of agreed value produced in this domain
132 /// \details The length is calculated using <tt>GetEncodedElementSize(false)</tt>,
133 /// which means the element is encoded in a non-reversible format. A
134 /// non-reversible format means its a raw byte array, and it lacks presentation
135 /// format like an ASN.1 BIT_STRING or OCTET_STRING.
136 unsigned int AgreedValueLength() const
137 {return GetAbstractGroupParameters().GetEncodedElementSize(false);}
138
139 /// \brief Provides the size of the static private key
140 /// \return size of static private keys in this domain
141 /// \details The length is calculated using the byte count of the subgroup order.
142 unsigned int StaticPrivateKeyLength() const
143 {return GetAbstractGroupParameters().GetSubgroupOrder().ByteCount();}
144
145 /// \brief Provides the size of the static public key
146 /// \return size of static public keys in this domain
147 /// \details The length is calculated using <tt>GetEncodedElementSize(true)</tt>,
148 /// which means the element is encoded in a reversible format. A reversible
149 /// format means it has a presentation format, and its an ANS.1 encoded element
150 /// or point.
151 unsigned int StaticPublicKeyLength() const
152 {return GetAbstractGroupParameters().GetEncodedElementSize(true);}
153
154 /// \brief Generate static private key in this domain
155 /// \param rng a RandomNumberGenerator derived class
156 /// \param privateKey a byte buffer for the generated private key in this domain
157 /// \details The private key is a random scalar used as an exponent in the range
158 /// <tt>[1,MaxExponent()]</tt>.
159 /// \pre <tt>COUNTOF(privateKey) == PrivateStaticKeyLength()</tt>
160 void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
161 {
162 Integer x(rng, Integer::One(), GetAbstractGroupParameters().GetMaxExponent());
163 x.Encode(privateKey, StaticPrivateKeyLength());
164 }
165
166 /// \brief Generate a static public key from a private key in this domain
167 /// \param rng a RandomNumberGenerator derived class
168 /// \param privateKey a byte buffer with the previously generated private key
169 /// \param publicKey a byte buffer for the generated public key in this domain
170 /// \details The public key is an element or point on the curve, and its stored
171 /// in a revrsible format. A reversible format means it has a presentation
172 /// format, and its an ANS.1 encoded element or point.
173 /// \pre <tt>COUNTOF(publicKey) == PublicStaticKeyLength()</tt>
174 void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
175 {
176 CRYPTOPP_UNUSED(rng);
177 const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
178 Integer x(privateKey, StaticPrivateKeyLength());
179 Element y = params.ExponentiateBase(x);
180 params.EncodeElement(true, y, publicKey);
181 }
182
183 /// \brief Provides the size of the ephemeral private key
184 /// \return size of ephemeral private keys in this domain
185 /// \details An ephemeral private key is a private key and public key.
186 /// The serialized size is different than a static private key.
188
189 /// \brief Provides the size of the ephemeral public key
190 /// \return size of ephemeral public keys in this domain
191 /// \details An ephemeral public key is a public key.
192 /// The serialized size is the same as a static public key.
193 unsigned int EphemeralPublicKeyLength() const{return StaticPublicKeyLength();}
194
195 /// \brief Generate ephemeral private key in this domain
196 /// \param rng a RandomNumberGenerator derived class
197 /// \param privateKey a byte buffer for the generated private key in this domain
198 /// \pre <tt>COUNTOF(privateKey) == EphemeralPrivateKeyLength()</tt>
199 void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
200 {
201 const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
202 Integer x(rng, Integer::One(), params.GetMaxExponent());
203 x.Encode(privateKey, StaticPrivateKeyLength());
204 Element y = params.ExponentiateBase(x);
205 params.EncodeElement(true, y, privateKey+StaticPrivateKeyLength());
206 }
207
208 /// \brief Generate ephemeral public key from a private key in this domain
209 /// \param rng a RandomNumberGenerator derived class
210 /// \param privateKey a byte buffer with the previously generated private key
211 /// \param publicKey a byte buffer for the generated public key in this domain
212 /// \pre <tt>COUNTOF(publicKey) == EphemeralPublicKeyLength()</tt>
213 void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
214 {
215 CRYPTOPP_UNUSED(rng);
216 std::memcpy(publicKey, privateKey+StaticPrivateKeyLength(), EphemeralPublicKeyLength());
217 }
218
219 /// \brief Derive agreed value or shared secret
220 /// \param agreedValue the shared secret
221 /// \param staticPrivateKey your long term private key
222 /// \param ephemeralPrivateKey your ephemeral private key
223 /// \param staticOtherPublicKey couterparty's long term public key
224 /// \param ephemeralOtherPublicKey couterparty's ephemeral public key
225 /// \param validateStaticOtherPublicKey flag indicating validation
226 /// \return true upon success, false in case of failure
227 /// \details Agree() performs the authenticated key agreement. Agree()
228 /// derives a shared secret from your private keys and couterparty's
229 /// public keys. Each instance or run of the protocol should use a new
230 /// ephemeral key pair.
231 /// \details The other's ephemeral public key will always be validated at
232 /// Level 1 to ensure it is a point on the curve.
233 /// <tt>validateStaticOtherPublicKey</tt> determines how thoroughly other's
234 /// static public key is validated. If you have previously validated the
235 /// couterparty's static public key, then use
236 /// <tt>validateStaticOtherPublicKey=false</tt> to save time.
237 /// \pre <tt>COUNTOF(agreedValue) == AgreedValueLength()</tt>
238 /// \pre <tt>COUNTOF(staticPrivateKey) == StaticPrivateKeyLength()</tt>
239 /// \pre <tt>COUNTOF(ephemeralPrivateKey) == EphemeralPrivateKeyLength()</tt>
240 /// \pre <tt>COUNTOF(staticOtherPublicKey) == StaticPublicKeyLength()</tt>
241 /// \pre <tt>COUNTOF(ephemeralOtherPublicKey) == EphemeralPublicKeyLength()</tt>
242 bool Agree(byte *agreedValue,
243 const byte *staticPrivateKey, const byte *ephemeralPrivateKey,
244 const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey,
245 bool validateStaticOtherPublicKey=true) const
246 {
247 const byte *XX = NULLPTR, *YY = NULLPTR, *AA = NULLPTR, *BB = NULLPTR;
248 size_t xxs = 0, yys = 0, aas = 0, bbs = 0;
249
250 // Depending on the role, this will hold either A's or B's static
251 // (long term) public key. AA or BB will then point into tt.
253
254 try
255 {
256 this->GetMaterial().DoQuickSanityCheck();
257 const DL_GroupParameters<Element> &params = GetAbstractGroupParameters();
258
259 if(m_role == RoleServer)
260 {
261 Integer b(staticPrivateKey, StaticPrivateKeyLength());
262 Element B = params.ExponentiateBase(b);
263 params.EncodeElement(true, B, tt);
264
265 XX = ephemeralOtherPublicKey;
267 YY = ephemeralPrivateKey + StaticPrivateKeyLength();
269 AA = staticOtherPublicKey;
270 aas = StaticPublicKeyLength();
271 BB = tt.BytePtr();
272 bbs = tt.SizeInBytes();
273 }
274 else
275 {
276 Integer a(staticPrivateKey, StaticPrivateKeyLength());
277 Element A = params.ExponentiateBase(a);
278 params.EncodeElement(true, A, tt);
279
280 XX = ephemeralPrivateKey + StaticPrivateKeyLength();
282 YY = ephemeralOtherPublicKey;
284 AA = tt.BytePtr();
285 aas = tt.SizeInBytes();
286 BB = staticOtherPublicKey;
287 bbs = StaticPublicKeyLength();
288 }
289
290 Element VV1 = params.DecodeElement(staticOtherPublicKey, validateStaticOtherPublicKey);
291 Element VV2 = params.DecodeElement(ephemeralOtherPublicKey, true);
292
293 const Integer& q = params.GetSubgroupOrder();
294 const unsigned int len /*bytes*/ = (((q.BitCount()+1)/2 +7)/8);
295 SecByteBlock dd(len), ee(len);
296
297 // Compute $d = \hat{H}(X, \hat{B})$
298 Hash(NULLPTR, XX, xxs, BB, bbs, dd.BytePtr(), dd.SizeInBytes());
299 Integer d(dd.BytePtr(), dd.SizeInBytes());
300
301 // Compute $e = \hat{H}(Y, \hat{A})$
302 Hash(NULLPTR, YY, yys, AA, aas, ee.BytePtr(), ee.SizeInBytes());
303 Integer e(ee.BytePtr(), ee.SizeInBytes());
304
305 Element sigma;
306 if(m_role == RoleServer)
307 {
308 Integer y(ephemeralPrivateKey, StaticPrivateKeyLength());
309 Integer b(staticPrivateKey, StaticPrivateKeyLength());
310 Integer s_B = (y + e * b) % q;
311
312 Element A = params.DecodeElement(AA, false);
313 Element X = params.DecodeElement(XX, false);
314
315 Element t1 = params.ExponentiateElement(A, d);
316 Element t2 = m_groupParameters.MultiplyElements(X, t1);
317
318 // $\sigma_B}=(X \cdot A^{d})^{s_B}
319 sigma = params.ExponentiateElement(t2, s_B);
320 }
321 else
322 {
323 Integer x(ephemeralPrivateKey, StaticPrivateKeyLength());
324 Integer a(staticPrivateKey, StaticPrivateKeyLength());
325 Integer s_A = (x + d * a) % q;
326
327 Element B = params.DecodeElement(BB, false);
328 Element Y = params.DecodeElement(YY, false);
329
330 Element t3 = params.ExponentiateElement(B, e);
331 Element t4 = m_groupParameters.MultiplyElements(Y, t3);
332
333 // $\sigma_A}=(Y \cdot B^{e})^{s_A}
334 sigma = params.ExponentiateElement(t4, s_A);
335 }
336 Hash(&sigma, NULLPTR, 0, NULLPTR, 0, agreedValue, AgreedValueLength());
337 }
338 catch (DL_BadElement &)
339 {
341 return false;
342 }
343 return true;
344 }
345
346protected:
347 // Hash invocation by client and server differ only in what keys
348 // each provides.
349
350 inline void Hash(const Element* sigma,
351 const byte* e1, size_t e1len, // Ephemeral key and key length
352 const byte* s1, size_t s1len, // Static key and key length
353 byte* digest, size_t dlen) const
354 {
355 HASH hash;
356 size_t idx = 0, req = dlen;
357 size_t blk = STDMIN(dlen, (size_t)HASH::DIGESTSIZE);
358
359 if(sigma)
360 {
361 if (e1len != 0 || s1len != 0) {
363 }
364 //Integer x = GetAbstractGroupParameters().ConvertElementToInteger(*sigma);
365 //SecByteBlock sbb(x.MinEncodedSize());
366 //x.Encode(sbb.BytePtr(), sbb.SizeInBytes());
367 SecByteBlock sbb(GetAbstractGroupParameters().GetEncodedElementSize(false));
368 GetAbstractGroupParameters().EncodeElement(false, *sigma, sbb);
369 hash.Update(sbb.BytePtr(), sbb.SizeInBytes());
370 } else {
371 if (e1len == 0 || s1len == 0) {
373 }
374 hash.Update(e1, e1len);
375 hash.Update(s1, s1len);
376 }
377
378 hash.TruncatedFinal(digest, blk);
379 req -= blk;
380
381 // All this to catch tail bytes for large curves and small hashes
382 while(req != 0)
383 {
384 hash.Update(&digest[idx], (size_t)HASH::DIGESTSIZE);
385
386 idx += (size_t)HASH::DIGESTSIZE;
387 blk = STDMIN(req, (size_t)HASH::DIGESTSIZE);
388 hash.TruncatedFinal(&digest[idx], blk);
389
390 req -= blk;
391 }
392 }
393
394private:
395
396 // The paper uses Initiator and Recipient - make it classical.
397 enum KeyAgreementRole { RoleServer = 1, RoleClient };
398
399 DL_GroupParameters<Element> & AccessAbstractGroupParameters()
400 {return m_groupParameters;}
401 const DL_GroupParameters<Element> & GetAbstractGroupParameters() const
402 {return m_groupParameters;}
403
404 GroupParameters m_groupParameters;
405 KeyAgreementRole m_role;
406};
407
408/// \brief Hashed Menezes-Qu-Vanstone in GF(p)
409/// \details This implementation follows Hugo Krawczyk's <a href="http://eprint.iacr.org/2005/176">HMQV: A High-Performance
410/// Secure Diffie-Hellman Protocol</a>. Note: this implements HMQV only. HMQV-C with Key Confirmation is not provided.
411/// \sa HMQV, HMQV_Domain, FHMQV_Domain, AuthenticatedKeyAgreementDomain
412/// \since Crypto++ 5.6.4
414
415NAMESPACE_END
416
417#endif
Classes for performing mathematics over different fields.
Interface for domains of authenticated key agreement protocols.
Definition cryptlib.h:3077
Interface for buffered transformations.
Definition cryptlib.h:1657
Interface for crypto parameters.
Definition cryptlib.h:2551
Exception thrown when an invalid group element is encountered.
Definition pubkey.h:772
Interface for Discrete Log (DL) group parameters.
Definition pubkey.h:782
virtual Element ExponentiateElement(const Element &base, const Integer &exponent) const
Exponentiates an element.
Definition pubkey.h:879
virtual void EncodeElement(bool reversible, const Element &element, byte *encoded) const =0
Encodes the element.
virtual Integer GetMaxExponent() const =0
Retrieves the maximum exponent for the group.
virtual const Integer & GetSubgroupOrder() const =0
Retrieves the subgroup order.
virtual Element ExponentiateBase(const Integer &exponent) const
Exponentiates the base.
Definition pubkey.h:869
virtual Element DecodeElement(const byte *encoded, bool checkForGroupMembership) const =0
Decodes the element.
Hashed Menezes-Qu-Vanstone in GF(p)
Definition hmqv.h:24
CryptoParameters & AccessCryptoParameters()
Retrieves the crypto parameters for this domain.
Definition hmqv.h:128
const GroupParameters & GetGroupParameters() const
Retrieves the group parameters for this domain.
Definition hmqv.h:120
void GenerateEphemeralPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
Generate ephemeral private key in this domain.
Definition hmqv.h:199
void GenerateStaticPrivateKey(RandomNumberGenerator &rng, byte *privateKey) const
Generate static private key in this domain.
Definition hmqv.h:160
HMQV_Domain(T1 v1, bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:64
void GenerateEphemeralPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
Generate ephemeral public key from a private key in this domain.
Definition hmqv.h:213
GroupParameters & AccessGroupParameters()
Retrieves the group parameters for this domain.
Definition hmqv.h:124
HMQV_Domain(BufferedTransformation &bt, bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:52
HMQV_Domain(bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:36
HMQV_Domain(T1 v1, T2 v2, T3 v3, bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:94
unsigned int StaticPrivateKeyLength() const
Provides the size of the static private key.
Definition hmqv.h:142
bool Agree(byte *agreedValue, const byte *staticPrivateKey, const byte *ephemeralPrivateKey, const byte *staticOtherPublicKey, const byte *ephemeralOtherPublicKey, bool validateStaticOtherPublicKey=true) const
Derive agreed value or shared secret.
Definition hmqv.h:242
unsigned int AgreedValueLength() const
Provides the size of the agreed value.
Definition hmqv.h:136
HMQV_Domain(T1 v1, T2 v2, bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:78
unsigned int EphemeralPrivateKeyLength() const
Provides the size of the ephemeral private key.
Definition hmqv.h:187
void GenerateStaticPublicKey(RandomNumberGenerator &rng, const byte *privateKey, byte *publicKey) const
Generate a static public key from a private key in this domain.
Definition hmqv.h:174
unsigned int StaticPublicKeyLength() const
Provides the size of the static public key.
Definition hmqv.h:151
unsigned int EphemeralPublicKeyLength() const
Provides the size of the ephemeral public key.
Definition hmqv.h:193
HMQV_Domain(const GroupParameters &params, bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:44
HMQV_Domain(T1 v1, T2 v2, T3 v3, T4 v4, bool clientRole=true)
Construct a HMQV domain.
Definition hmqv.h:112
Multiple precision integer with arithmetic operations.
Definition integer.h:50
unsigned int BitCount() const
Determines the number of bits required to represent the Integer.
static const Integer & One()
Integer representing 1.
const CryptoMaterial & GetMaterial() const
Retrieves a reference to Crypto Parameters.
Definition cryptlib.h:2652
Interface for random number generators.
Definition cryptlib.h:1440
size_type SizeInBytes() const
Provides the number of bytes in the SecBlock.
Definition secblock.h:885
byte * BytePtr()
Provides a byte pointer to the first element in the memory block.
Definition secblock.h:876
SecBlock typedef.
Definition secblock.h:1226
Classes and functions for schemes based on Discrete Logs (DL) over GF(p)
HMQV_Domain< DL_GroupParameters_GFP_DefaultSafePrime > HMQV
Hashed Menezes-Qu-Vanstone in GF(p)
Definition hmqv.h:413
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition misc.h:657
Crypto++ library namespace.
Classes for SHA-1 and SHA-2 family of message digests.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition trap.h:68