<commit_before>#include <memory>
#include "Log.h"
#include "Signature.h"

namespace i2p
{
namespace crypto
{
	class Ed25519
	{
		public:

			Ed25519 ()
			{
				BN_CTX * ctx = BN_CTX_new ();
				BIGNUM * two = BN_new (), * tmp = BN_new ();
				BN_set_word (two, 2);

				q = BN_new ();
				// 2^255-19				
				BN_set_word (tmp, 255);
				BN_exp (q, two, tmp, ctx);
				BN_sub_word (q, 19);
				
				l = BN_new ();
				// 2^252 + 27742317777372353535851937790883648493
				BN_set_word (tmp, 252);
				BN_exp (l, two, tmp, ctx);
				two_252_2 = BN_dup (l);
				BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
				BN_add (l, l, tmp);		
				BN_sub_word (two_252_2, 2); // 2^252 - 2		

				 // -121665*inv(121666)
				d = BN_new ();
				BN_set_word (tmp, 121666);
				BN_mod_inverse (tmp, tmp, q, ctx);	
				BN_set_word (d, 121665);
				BN_set_negative (d, 1);							
				BN_mul (d, d, tmp, ctx);

				// 2^((q-1)/4)
				I = BN_new ();
				BN_free (tmp);
				tmp = BN_dup (q);
				BN_sub_word (tmp, 1);
				BN_div_word (tmp, 4);	
				BN_mod_exp (I, two, tmp, q, ctx);

				BN_free (two);
				BN_free (tmp);	
				
				// 4*inv(5)	
				BIGNUM * By = BN_new ();		
				BN_set_word (By, 5);
				BN_mod_inverse (By, By, q, ctx);	
				BN_mul_word (By, 4);
				BIGNUM * Bx = RecoverX (By, ctx);	
				BN_mod (Bx, Bx, q, ctx); // % q
				BN_mod (By, By, q, ctx); // % q										
			
				// precalculate Bi16 table
				Bi16[0][0] = { Bx, By };  // B
				for (int i = 0; i < 64; i++)
				{
					if (i) Bi16[i][0] = Sum (Bi16[i-1][14], Bi16[i-1][0], ctx); 
					for (int j = 1; j < 15; j++)
						Bi16[i][j] = Sum (Bi16[i][j-1], Bi16[i][0], ctx); // (16+j+1)^i*B
				}

				BN_CTX_free (ctx);
			}

			~Ed25519 ()
			{
				BN_free (q);
				BN_free (l);
				BN_free (d);
				BN_free (I);
				BN_free (two_252_2);
			}


			EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const
			{
				return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian
			}

			EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const
			{
				return DecodePoint (buf, ctx);
			}

			void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const
			{
				EncodePoint (Normalize (publicKey, ctx), buf);
			}

			bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature, BN_CTX * ctx) const
			{
				BIGNUM * h = DecodeBN<64> (digest);
				// signature 0..31 - R, 32..63 - S 
				// B*S = R + PK*h => R = B*S - PK*h
				// we don't decode R, but encode (B*S - PK*h)
				auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S;
				BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0
				auto PKh = Mul (publicKey, h, ctx); // PK*h
				uint8_t diff[32];
				EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
				bool passed = !memcmp (signature, diff, 32); // R
				BN_free (h); 
				if (!passed)
					LogPrint (eLogError, "25519 signature verification failed");
				return passed; 
			}

			void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, 
				uint8_t * signature, BN_CTX * bnCtx) const
			{
				// calculate r
				SHA512_CTX ctx;
				SHA512_Init (&ctx);
				SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
				SHA512_Update (&ctx, buf, len); // data
				uint8_t digest[64];
				SHA512_Final (digest, &ctx);
				BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
				// calculate R
				uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
				EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors 
				// calculate S
				SHA512_Init (&ctx);
				SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
				SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
				SHA512_Update (&ctx, buf, len); // data
				SHA512_Final (digest, &ctx);
				BIGNUM * h = DecodeBN<64> (digest);			
				// S = (r + h*a) % l
				BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
				BN_mod_mul (h, h, a, l, bnCtx); // %l
				BN_mod_add (h, h, r, l, bnCtx); // %l
				memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
				EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
				BN_free (r); BN_free (h); BN_free (a);
			}

		private:		

			EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
			{
				// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
				// y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2)
				// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
				// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
				BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
				BIGNUM * z1 = p1.z, * t1 = p1.t;
				if (!z1) { z1 = BN_new (); BN_one (z1); }
				if (!t1) { t1 = BN_new (); BN_mul (t1, p1.x, p1.y, ctx); }
				
				BIGNUM * z2 = p2.z, * t2 = p2.t;
				if (!z2) { z2 = BN_new (); BN_one (z2); }
				if (!t2) { t2 = BN_new (); BN_mul (t2, p2.x, p2.y, ctx); }
				
				BIGNUM * A = BN_new (), * B = BN_new (), * C = BN_new (), * D = BN_new ();
				BN_mul (A, p1.x, p2.x, ctx); // A = x1*x2		
				BN_mul (B, p1.y, p2.y, ctx); // B = y1*y2	
				BN_mul (C, t1, t2, ctx);
				BN_mul (C, C, d, ctx);  // C = d*t1*t2
				BN_mul (D, z1, z2, ctx); // D = z1*z2	

				BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
				BN_add (x3, p1.x, p1.y);				
				BN_add (y3, p2.x, p2.y);
				BN_mul (E, x3, y3, ctx); // (x1 + y1)*(x2 + y2)
				BN_sub (E, E, A);
				BN_sub (E, E, B); // E = (x1 + y1)*(x2 + y2) - A - B
				BN_sub (F, D, C); // F = D - C
				BN_add (G, D, C); // G = D + C
				BN_add (H, B, A); // H = B + A

				BN_free (A); BN_free (B); BN_free (C); BN_free (D);	
				if (!p1.z) BN_free (z1);
				if (!p1.t) BN_free (t1);
				if (!p2.z) BN_free (z2);
				if (!p2.t) BN_free (t2);<commit_msg>reduce number of transient BIGNUM allocations<commit_after>#include <memory>
#include "Log.h"
#include "Signature.h"

namespace i2p
{
namespace crypto
{
	class Ed25519
	{
		public:

			Ed25519 ()
			{
				BN_CTX * ctx = BN_CTX_new ();
				BIGNUM * two = BN_new (), * tmp = BN_new ();
				BN_set_word (two, 2);

				q = BN_new ();
				// 2^255-19				
				BN_set_word (tmp, 255);
				BN_exp (q, two, tmp, ctx);
				BN_sub_word (q, 19);
				
				l = BN_new ();
				// 2^252 + 27742317777372353535851937790883648493
				BN_set_word (tmp, 252);
				BN_exp (l, two, tmp, ctx);
				two_252_2 = BN_dup (l);
				BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
				BN_add (l, l, tmp);		
				BN_sub_word (two_252_2, 2); // 2^252 - 2		

				 // -121665*inv(121666)
				d = BN_new ();
				BN_set_word (tmp, 121666);
				BN_mod_inverse (tmp, tmp, q, ctx);	
				BN_set_word (d, 121665);
				BN_set_negative (d, 1);							
				BN_mul (d, d, tmp, ctx);

				// 2^((q-1)/4)
				I = BN_new ();
				BN_free (tmp);
				tmp = BN_dup (q);
				BN_sub_word (tmp, 1);
				BN_div_word (tmp, 4);	
				BN_mod_exp (I, two, tmp, q, ctx);

				BN_free (two);
				BN_free (tmp);	
				
				// 4*inv(5)	
				BIGNUM * By = BN_new ();		
				BN_set_word (By, 5);
				BN_mod_inverse (By, By, q, ctx);	
				BN_mul_word (By, 4);
				BIGNUM * Bx = RecoverX (By, ctx);	
				BN_mod (Bx, Bx, q, ctx); // % q
				BN_mod (By, By, q, ctx); // % q										
			
				// precalculate Bi16 table
				Bi16[0][0] = { Bx, By };  // B
				for (int i = 0; i < 64; i++)
				{
					if (i) Bi16[i][0] = Sum (Bi16[i-1][14], Bi16[i-1][0], ctx); 
					for (int j = 1; j < 15; j++)
						Bi16[i][j] = Sum (Bi16[i][j-1], Bi16[i][0], ctx); // (16+j+1)^i*B
				}

				BN_CTX_free (ctx);
			}

			~Ed25519 ()
			{
				BN_free (q);
				BN_free (l);
				BN_free (d);
				BN_free (I);
				BN_free (two_252_2);
			}


			EDDSAPoint GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const
			{
				return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian
			}

			EDDSAPoint DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const
			{
				return DecodePoint (buf, ctx);
			}

			void EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const
			{
				EncodePoint (Normalize (publicKey, ctx), buf);
			}

			bool Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature, BN_CTX * ctx) const
			{
				BIGNUM * h = DecodeBN<64> (digest);
				// signature 0..31 - R, 32..63 - S 
				// B*S = R + PK*h => R = B*S - PK*h
				// we don't decode R, but encode (B*S - PK*h)
				auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S;
				BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0
				auto PKh = Mul (publicKey, h, ctx); // PK*h
				uint8_t diff[32];
				EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
				bool passed = !memcmp (signature, diff, 32); // R
				BN_free (h); 
				if (!passed)
					LogPrint (eLogError, "25519 signature verification failed");
				return passed; 
			}

			void Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded, const uint8_t * buf, size_t len, 
				uint8_t * signature, BN_CTX * bnCtx) const
			{
				// calculate r
				SHA512_CTX ctx;
				SHA512_Init (&ctx);
				SHA512_Update (&ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
				SHA512_Update (&ctx, buf, len); // data
				uint8_t digest[64];
				SHA512_Final (digest, &ctx);
				BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
				// calculate R
				uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
				EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors 
				// calculate S
				SHA512_Init (&ctx);
				SHA512_Update (&ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
				SHA512_Update (&ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
				SHA512_Update (&ctx, buf, len); // data
				SHA512_Final (digest, &ctx);
				BIGNUM * h = DecodeBN<64> (digest);			
				// S = (r + h*a) % l
				BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
				BN_mod_mul (h, h, a, l, bnCtx); // %l
				BN_mod_add (h, h, r, l, bnCtx); // %l
				memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
				EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
				BN_free (r); BN_free (h); BN_free (a);
			}

		private:		

			EDDSAPoint Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
			{
				// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
				// y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2)
				// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
				// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
				BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
				BIGNUM * z1 = p1.z, * t1 = p1.t;
				if (!z1) { z1 = BN_new (); BN_one (z1); }
				if (!t1) { t1 = BN_new (); BN_mul (t1, p1.x, p1.y, ctx); }
				
				BIGNUM * z2 = p2.z, * t2 = p2.t;
				if (!z2) { z2 = BN_new (); BN_one (z2); }
				if (!t2) { t2 = BN_new (); BN_mul (t2, p2.x, p2.y, ctx); }
				
				BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2		
				BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2	
				BN_mul (t3, t1, t2, ctx);
				BN_mul (t3, t3, d, ctx);  // C = d*t1*t2
				BN_mul (z3, z1, z2, ctx); // D = z1*z2	

				BIGNUM * E = BN_new (), * F = BN_new (), * G = BN_new (), * H = BN_new ();
				BN_add (E, p1.x, p1.y);				
				BN_add (F, p2.x, p2.y);
				BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
				BN_sub (E, E, x3);
				BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
				BN_sub (F, z3, t3); // F = D - C
				BN_add (G, z3, t3); // G = D + C
				BN_add (H, y3, x3); // H = B + A

				if (!p1.z) BN_free (z1);
				if (!p1.t) BN_free (t1);
				if (!p2.z) BN_free (z2);
				if (!p2.t) BN_free (t2);
{'fraction_non_alphanumeric': 0.17205009887936717, 'fraction_numerical': 0.07168754119973632, 'mean_word_length': 2.479644495412844, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2168025', 'n_tokens_mistral': 6790, 'n_tokens_neox': 5316, 'n_words': 1357}