1 /* 2 * Copyright (c) 2013-2021, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #ifndef SIGNATURE_H__ 10 #define SIGNATURE_H__ 11 12 #include <inttypes.h> 13 #include <string.h> 14 #include <openssl/dsa.h> 15 #include <openssl/ec.h> 16 #include <openssl/ecdsa.h> 17 #include <openssl/evp.h> 18 #include "Crypto.h" 19 #include "Ed25519.h" 20 #include "Gost.h" 21 22 namespace i2p 23 { 24 namespace crypto 25 { 26 class Verifier 27 { 28 public: 29 ~Verifier()30 virtual ~Verifier () {}; 31 virtual bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const = 0; 32 virtual size_t GetPublicKeyLen () const = 0; 33 virtual size_t GetSignatureLen () const = 0; GetPrivateKeyLen()34 virtual size_t GetPrivateKeyLen () const { return GetSignatureLen ()/2; }; 35 virtual void SetPublicKey (const uint8_t * signingKey) = 0; 36 }; 37 38 class Signer 39 { 40 public: 41 ~Signer()42 virtual ~Signer () {}; 43 virtual void Sign (const uint8_t * buf, int len, uint8_t * signature) const = 0; 44 }; 45 46 const size_t DSA_PUBLIC_KEY_LENGTH = 128; 47 const size_t DSA_SIGNATURE_LENGTH = 40; 48 const size_t DSA_PRIVATE_KEY_LENGTH = DSA_SIGNATURE_LENGTH/2; 49 class DSAVerifier: public Verifier 50 { 51 public: 52 DSAVerifier()53 DSAVerifier () 54 { 55 m_PublicKey = CreateDSA (); 56 } 57 SetPublicKey(const uint8_t * signingKey)58 void SetPublicKey (const uint8_t * signingKey) 59 { 60 DSA_set0_key (m_PublicKey, BN_bin2bn (signingKey, DSA_PUBLIC_KEY_LENGTH, NULL), NULL); 61 } 62 ~DSAVerifier()63 ~DSAVerifier () 64 { 65 DSA_free (m_PublicKey); 66 } 67 Verify(const uint8_t * buf,size_t len,const uint8_t * signature)68 bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const 69 { 70 // calculate SHA1 digest 71 uint8_t digest[20]; 72 SHA1 (buf, len, digest); 73 // signature 74 DSA_SIG * sig = DSA_SIG_new(); 75 DSA_SIG_set0 (sig, BN_bin2bn (signature, DSA_SIGNATURE_LENGTH/2, NULL), BN_bin2bn (signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2, NULL)); 76 // DSA verification 77 int ret = DSA_do_verify (digest, 20, sig, m_PublicKey); 78 DSA_SIG_free(sig); 79 return ret; 80 } 81 GetPublicKeyLen()82 size_t GetPublicKeyLen () const { return DSA_PUBLIC_KEY_LENGTH; }; GetSignatureLen()83 size_t GetSignatureLen () const { return DSA_SIGNATURE_LENGTH; }; 84 85 private: 86 87 DSA * m_PublicKey; 88 }; 89 90 class DSASigner: public Signer 91 { 92 public: 93 DSASigner(const uint8_t * signingPrivateKey,const uint8_t * signingPublicKey)94 DSASigner (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey) 95 // openssl 1.1 always requires DSA public key even for signing 96 { 97 m_PrivateKey = CreateDSA (); 98 DSA_set0_key (m_PrivateKey, BN_bin2bn (signingPublicKey, DSA_PUBLIC_KEY_LENGTH, NULL), BN_bin2bn (signingPrivateKey, DSA_PRIVATE_KEY_LENGTH, NULL)); 99 } 100 ~DSASigner()101 ~DSASigner () 102 { 103 DSA_free (m_PrivateKey); 104 } 105 Sign(const uint8_t * buf,int len,uint8_t * signature)106 void Sign (const uint8_t * buf, int len, uint8_t * signature) const 107 { 108 uint8_t digest[20]; 109 SHA1 (buf, len, digest); 110 DSA_SIG * sig = DSA_do_sign (digest, 20, m_PrivateKey); 111 const BIGNUM * r, * s; 112 DSA_SIG_get0 (sig, &r, &s); 113 bn2buf (r, signature, DSA_SIGNATURE_LENGTH/2); 114 bn2buf (s, signature + DSA_SIGNATURE_LENGTH/2, DSA_SIGNATURE_LENGTH/2); 115 DSA_SIG_free(sig); 116 } 117 118 private: 119 120 DSA * m_PrivateKey; 121 }; 122 CreateDSARandomKeys(uint8_t * signingPrivateKey,uint8_t * signingPublicKey)123 inline void CreateDSARandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 124 { 125 DSA * dsa = CreateDSA (); 126 DSA_generate_key (dsa); 127 const BIGNUM * pub_key, * priv_key; 128 DSA_get0_key(dsa, &pub_key, &priv_key); 129 bn2buf (priv_key, signingPrivateKey, DSA_PRIVATE_KEY_LENGTH); 130 bn2buf (pub_key, signingPublicKey, DSA_PUBLIC_KEY_LENGTH); 131 DSA_free (dsa); 132 } 133 134 struct SHA256Hash 135 { CalculateHashSHA256Hash136 static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) 137 { 138 SHA256 (buf, len, digest); 139 } 140 141 enum { hashLen = 32 }; 142 }; 143 144 struct SHA384Hash 145 { CalculateHashSHA384Hash146 static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) 147 { 148 SHA384 (buf, len, digest); 149 } 150 151 enum { hashLen = 48 }; 152 }; 153 154 struct SHA512Hash 155 { CalculateHashSHA512Hash156 static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) 157 { 158 SHA512 (buf, len, digest); 159 } 160 161 enum { hashLen = 64 }; 162 }; 163 164 // EcDSA 165 template<typename Hash, int curve, size_t keyLen> 166 class ECDSAVerifier: public Verifier 167 { 168 public: 169 ECDSAVerifier()170 ECDSAVerifier () 171 { 172 m_PublicKey = EC_KEY_new_by_curve_name (curve); 173 } 174 SetPublicKey(const uint8_t * signingKey)175 void SetPublicKey (const uint8_t * signingKey) 176 { 177 BIGNUM * x = BN_bin2bn (signingKey, keyLen/2, NULL); 178 BIGNUM * y = BN_bin2bn (signingKey + keyLen/2, keyLen/2, NULL); 179 EC_KEY_set_public_key_affine_coordinates (m_PublicKey, x, y); 180 BN_free (x); BN_free (y); 181 } 182 ~ECDSAVerifier()183 ~ECDSAVerifier () 184 { 185 EC_KEY_free (m_PublicKey); 186 } 187 Verify(const uint8_t * buf,size_t len,const uint8_t * signature)188 bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const 189 { 190 uint8_t digest[Hash::hashLen]; 191 Hash::CalculateHash (buf, len, digest); 192 ECDSA_SIG * sig = ECDSA_SIG_new(); 193 auto r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL); 194 auto s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); 195 ECDSA_SIG_set0(sig, r, s); 196 // ECDSA verification 197 int ret = ECDSA_do_verify (digest, Hash::hashLen, sig, m_PublicKey); 198 ECDSA_SIG_free(sig); 199 return ret; 200 } 201 GetPublicKeyLen()202 size_t GetPublicKeyLen () const { return keyLen; }; GetSignatureLen()203 size_t GetSignatureLen () const { return keyLen; }; // signature length = key length 204 205 206 private: 207 208 EC_KEY * m_PublicKey; 209 }; 210 211 template<typename Hash, int curve, size_t keyLen> 212 class ECDSASigner: public Signer 213 { 214 public: 215 ECDSASigner(const uint8_t * signingPrivateKey)216 ECDSASigner (const uint8_t * signingPrivateKey) 217 { 218 m_PrivateKey = EC_KEY_new_by_curve_name (curve); 219 EC_KEY_set_private_key (m_PrivateKey, BN_bin2bn (signingPrivateKey, keyLen/2, NULL)); 220 } 221 ~ECDSASigner()222 ~ECDSASigner () 223 { 224 EC_KEY_free (m_PrivateKey); 225 } 226 Sign(const uint8_t * buf,int len,uint8_t * signature)227 void Sign (const uint8_t * buf, int len, uint8_t * signature) const 228 { 229 uint8_t digest[Hash::hashLen]; 230 Hash::CalculateHash (buf, len, digest); 231 ECDSA_SIG * sig = ECDSA_do_sign (digest, Hash::hashLen, m_PrivateKey); 232 const BIGNUM * r, * s; 233 ECDSA_SIG_get0 (sig, &r, &s); 234 // signatureLen = keyLen 235 bn2buf (r, signature, keyLen/2); 236 bn2buf (s, signature + keyLen/2, keyLen/2); 237 ECDSA_SIG_free(sig); 238 } 239 240 private: 241 242 EC_KEY * m_PrivateKey; 243 }; 244 CreateECDSARandomKeys(int curve,size_t keyLen,uint8_t * signingPrivateKey,uint8_t * signingPublicKey)245 inline void CreateECDSARandomKeys (int curve, size_t keyLen, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 246 { 247 EC_KEY * signingKey = EC_KEY_new_by_curve_name (curve); 248 EC_KEY_generate_key (signingKey); 249 bn2buf (EC_KEY_get0_private_key (signingKey), signingPrivateKey, keyLen/2); 250 BIGNUM * x = BN_new(), * y = BN_new(); 251 EC_POINT_get_affine_coordinates_GFp (EC_KEY_get0_group(signingKey), 252 EC_KEY_get0_public_key (signingKey), x, y, NULL); 253 bn2buf (x, signingPublicKey, keyLen/2); 254 bn2buf (y, signingPublicKey + keyLen/2, keyLen/2); 255 BN_free (x); BN_free (y); 256 EC_KEY_free (signingKey); 257 } 258 259 // ECDSA_SHA256_P256 260 const size_t ECDSAP256_KEY_LENGTH = 64; 261 typedef ECDSAVerifier<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Verifier; 262 typedef ECDSASigner<SHA256Hash, NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH> ECDSAP256Signer; 263 CreateECDSAP256RandomKeys(uint8_t * signingPrivateKey,uint8_t * signingPublicKey)264 inline void CreateECDSAP256RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 265 { 266 CreateECDSARandomKeys (NID_X9_62_prime256v1, ECDSAP256_KEY_LENGTH, signingPrivateKey, signingPublicKey); 267 } 268 269 // ECDSA_SHA384_P384 270 const size_t ECDSAP384_KEY_LENGTH = 96; 271 typedef ECDSAVerifier<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Verifier; 272 typedef ECDSASigner<SHA384Hash, NID_secp384r1, ECDSAP384_KEY_LENGTH> ECDSAP384Signer; 273 CreateECDSAP384RandomKeys(uint8_t * signingPrivateKey,uint8_t * signingPublicKey)274 inline void CreateECDSAP384RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 275 { 276 CreateECDSARandomKeys (NID_secp384r1, ECDSAP384_KEY_LENGTH, signingPrivateKey, signingPublicKey); 277 } 278 279 // ECDSA_SHA512_P521 280 const size_t ECDSAP521_KEY_LENGTH = 132; 281 typedef ECDSAVerifier<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Verifier; 282 typedef ECDSASigner<SHA512Hash, NID_secp521r1, ECDSAP521_KEY_LENGTH> ECDSAP521Signer; 283 CreateECDSAP521RandomKeys(uint8_t * signingPrivateKey,uint8_t * signingPublicKey)284 inline void CreateECDSAP521RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 285 { 286 CreateECDSARandomKeys (NID_secp521r1, ECDSAP521_KEY_LENGTH, signingPrivateKey, signingPublicKey); 287 } 288 289 290 // EdDSA 291 class EDDSA25519Verifier: public Verifier 292 { 293 public: 294 295 EDDSA25519Verifier (); 296 void SetPublicKey (const uint8_t * signingKey); 297 ~EDDSA25519Verifier (); 298 299 bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const; 300 GetPublicKeyLen()301 size_t GetPublicKeyLen () const { return EDDSA25519_PUBLIC_KEY_LENGTH; }; GetSignatureLen()302 size_t GetSignatureLen () const { return EDDSA25519_SIGNATURE_LENGTH; }; 303 304 private: 305 306 #if OPENSSL_EDDSA 307 EVP_MD_CTX * m_MDCtx; 308 #else 309 EDDSAPoint m_PublicKey; 310 uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; 311 #endif 312 }; 313 314 class EDDSA25519SignerCompat: public Signer 315 { 316 public: 317 318 EDDSA25519SignerCompat (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr); 319 // we pass signingPublicKey to check if it matches private key 320 ~EDDSA25519SignerCompat (); 321 322 void Sign (const uint8_t * buf, int len, uint8_t * signature) const; GetPublicKey()323 const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation 324 325 private: 326 327 uint8_t m_ExpandedPrivateKey[64]; 328 uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; 329 }; 330 331 #if OPENSSL_EDDSA 332 class EDDSA25519Signer: public Signer 333 { 334 public: 335 336 EDDSA25519Signer (const uint8_t * signingPrivateKey, const uint8_t * signingPublicKey = nullptr); 337 // we pass signingPublicKey to check if it matches private key 338 ~EDDSA25519Signer (); 339 340 void Sign (const uint8_t * buf, int len, uint8_t * signature) const; 341 342 private: 343 344 EVP_MD_CTX * m_MDCtx; 345 EDDSA25519SignerCompat * m_Fallback; 346 }; 347 #else 348 349 typedef EDDSA25519SignerCompat EDDSA25519Signer; 350 351 #endif 352 CreateEDDSA25519RandomKeys(uint8_t * signingPrivateKey,uint8_t * signingPublicKey)353 inline void CreateEDDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 354 { 355 #if OPENSSL_EDDSA 356 EVP_PKEY *pkey = NULL; 357 EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id (EVP_PKEY_ED25519, NULL); 358 EVP_PKEY_keygen_init (pctx); 359 EVP_PKEY_keygen (pctx, &pkey); 360 EVP_PKEY_CTX_free (pctx); 361 size_t len = EDDSA25519_PUBLIC_KEY_LENGTH; 362 EVP_PKEY_get_raw_public_key (pkey, signingPublicKey, &len); 363 len = EDDSA25519_PRIVATE_KEY_LENGTH; 364 EVP_PKEY_get_raw_private_key (pkey, signingPrivateKey, &len); 365 EVP_PKEY_free (pkey); 366 #else 367 RAND_bytes (signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); 368 EDDSA25519Signer signer (signingPrivateKey); 369 memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); 370 #endif 371 } 372 373 374 // ГОСТ Р 34.11 375 struct GOSTR3411_256_Hash 376 { CalculateHashGOSTR3411_256_Hash377 static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) 378 { 379 GOSTR3411_2012_256 (buf, len, digest); 380 } 381 382 enum { hashLen = 32 }; 383 }; 384 385 struct GOSTR3411_512_Hash 386 { CalculateHashGOSTR3411_512_Hash387 static void CalculateHash (const uint8_t * buf, size_t len, uint8_t * digest) 388 { 389 GOSTR3411_2012_512 (buf, len, digest); 390 } 391 392 enum { hashLen = 64 }; 393 }; 394 395 // ГОСТ Р 34.10 396 const size_t GOSTR3410_256_PUBLIC_KEY_LENGTH = 64; 397 const size_t GOSTR3410_512_PUBLIC_KEY_LENGTH = 128; 398 399 template<typename Hash> 400 class GOSTR3410Verifier: public Verifier 401 { 402 public: 403 404 enum { keyLen = Hash::hashLen }; 405 GOSTR3410Verifier(GOSTR3410ParamSet paramSet)406 GOSTR3410Verifier (GOSTR3410ParamSet paramSet): 407 m_ParamSet (paramSet), m_PublicKey (nullptr) 408 { 409 } 410 SetPublicKey(const uint8_t * signingKey)411 void SetPublicKey (const uint8_t * signingKey) 412 { 413 BIGNUM * x = BN_bin2bn (signingKey, GetPublicKeyLen ()/2, NULL); 414 BIGNUM * y = BN_bin2bn (signingKey + GetPublicKeyLen ()/2, GetPublicKeyLen ()/2, NULL); 415 m_PublicKey = GetGOSTR3410Curve (m_ParamSet)->CreatePoint (x, y); 416 BN_free (x); BN_free (y); 417 } ~GOSTR3410Verifier()418 ~GOSTR3410Verifier () 419 { 420 if (m_PublicKey) EC_POINT_free (m_PublicKey); 421 } 422 Verify(const uint8_t * buf,size_t len,const uint8_t * signature)423 bool Verify (const uint8_t * buf, size_t len, const uint8_t * signature) const 424 { 425 uint8_t digest[Hash::hashLen]; 426 Hash::CalculateHash (buf, len, digest); 427 BIGNUM * d = BN_bin2bn (digest, Hash::hashLen, nullptr); 428 BIGNUM * r = BN_bin2bn (signature, GetSignatureLen ()/2, NULL); 429 BIGNUM * s = BN_bin2bn (signature + GetSignatureLen ()/2, GetSignatureLen ()/2, NULL); 430 bool ret = GetGOSTR3410Curve (m_ParamSet)->Verify (m_PublicKey, d, r, s); 431 BN_free (d); BN_free (r); BN_free (s); 432 return ret; 433 } 434 GetPublicKeyLen()435 size_t GetPublicKeyLen () const { return keyLen*2; } GetSignatureLen()436 size_t GetSignatureLen () const { return keyLen*2; } 437 438 private: 439 440 GOSTR3410ParamSet m_ParamSet; 441 EC_POINT * m_PublicKey; 442 }; 443 444 template<typename Hash> 445 class GOSTR3410Signer: public Signer 446 { 447 public: 448 449 enum { keyLen = Hash::hashLen }; 450 GOSTR3410Signer(GOSTR3410ParamSet paramSet,const uint8_t * signingPrivateKey)451 GOSTR3410Signer (GOSTR3410ParamSet paramSet, const uint8_t * signingPrivateKey): 452 m_ParamSet (paramSet) 453 { 454 m_PrivateKey = BN_bin2bn (signingPrivateKey, keyLen, nullptr); 455 } ~GOSTR3410Signer()456 ~GOSTR3410Signer () { BN_free (m_PrivateKey); } 457 Sign(const uint8_t * buf,int len,uint8_t * signature)458 void Sign (const uint8_t * buf, int len, uint8_t * signature) const 459 { 460 uint8_t digest[Hash::hashLen]; 461 Hash::CalculateHash (buf, len, digest); 462 BIGNUM * d = BN_bin2bn (digest, Hash::hashLen, nullptr); 463 BIGNUM * r = BN_new (), * s = BN_new (); 464 GetGOSTR3410Curve (m_ParamSet)->Sign (m_PrivateKey, d, r, s); 465 bn2buf (r, signature, keyLen); 466 bn2buf (s, signature + keyLen, keyLen); 467 BN_free (d); BN_free (r); BN_free (s); 468 } 469 470 private: 471 472 GOSTR3410ParamSet m_ParamSet; 473 BIGNUM * m_PrivateKey; 474 }; 475 CreateGOSTR3410RandomKeys(GOSTR3410ParamSet paramSet,uint8_t * signingPrivateKey,uint8_t * signingPublicKey)476 inline void CreateGOSTR3410RandomKeys (GOSTR3410ParamSet paramSet, uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 477 { 478 const auto& curve = GetGOSTR3410Curve (paramSet); 479 auto keyLen = curve->GetKeyLen (); 480 RAND_bytes (signingPrivateKey, keyLen); 481 BIGNUM * priv = BN_bin2bn (signingPrivateKey, keyLen, nullptr); 482 483 auto pub = curve->MulP (priv); 484 BN_free (priv); 485 BIGNUM * x = BN_new (), * y = BN_new (); 486 curve->GetXY (pub, x, y); 487 EC_POINT_free (pub); 488 bn2buf (x, signingPublicKey, keyLen); 489 bn2buf (y, signingPublicKey + keyLen, keyLen); 490 BN_free (x); BN_free (y); 491 } 492 493 typedef GOSTR3410Verifier<GOSTR3411_256_Hash> GOSTR3410_256_Verifier; 494 typedef GOSTR3410Signer<GOSTR3411_256_Hash> GOSTR3410_256_Signer; 495 typedef GOSTR3410Verifier<GOSTR3411_512_Hash> GOSTR3410_512_Verifier; 496 typedef GOSTR3410Signer<GOSTR3411_512_Hash> GOSTR3410_512_Signer; 497 498 // RedDSA 499 typedef EDDSA25519Verifier RedDSA25519Verifier; 500 class RedDSA25519Signer: public Signer 501 { 502 public: 503 RedDSA25519Signer(const uint8_t * signingPrivateKey)504 RedDSA25519Signer (const uint8_t * signingPrivateKey) 505 { 506 memcpy (m_PrivateKey, signingPrivateKey, EDDSA25519_PRIVATE_KEY_LENGTH); 507 BN_CTX * ctx = BN_CTX_new (); 508 auto publicKey = GetEd25519 ()->GeneratePublicKey (m_PrivateKey, ctx); 509 GetEd25519 ()->EncodePublicKey (publicKey, m_PublicKeyEncoded, ctx); 510 BN_CTX_free (ctx); 511 } ~RedDSA25519Signer()512 ~RedDSA25519Signer () {}; 513 Sign(const uint8_t * buf,int len,uint8_t * signature)514 void Sign (const uint8_t * buf, int len, uint8_t * signature) const 515 { 516 GetEd25519 ()->SignRedDSA (m_PrivateKey, m_PublicKeyEncoded, buf, len, signature); 517 } 518 GetPublicKey()519 const uint8_t * GetPublicKey () const { return m_PublicKeyEncoded; }; // for keys creation 520 521 private: 522 523 uint8_t m_PrivateKey[EDDSA25519_PRIVATE_KEY_LENGTH]; 524 uint8_t m_PublicKeyEncoded[EDDSA25519_PUBLIC_KEY_LENGTH]; 525 }; 526 CreateRedDSA25519RandomKeys(uint8_t * signingPrivateKey,uint8_t * signingPublicKey)527 inline void CreateRedDSA25519RandomKeys (uint8_t * signingPrivateKey, uint8_t * signingPublicKey) 528 { 529 GetEd25519 ()->CreateRedDSAPrivateKey (signingPrivateKey); 530 RedDSA25519Signer signer (signingPrivateKey); 531 memcpy (signingPublicKey, signer.GetPublicKey (), EDDSA25519_PUBLIC_KEY_LENGTH); 532 } 533 } 534 } 535 536 #endif 537