/ libi2pd / Ed25519.cpp
Ed25519.cpp
  1  /*
  2  * Copyright (c) 2013-2025, 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  #include <openssl/evp.h>
 10  #include "Log.h"
 11  #include "Crypto.h"
 12  #include "Ed25519.h"
 13  
 14  namespace i2p
 15  {
 16  namespace crypto
 17  {
 18  	Ed25519::Ed25519 ()
 19  	{
 20  		BN_CTX * ctx = BN_CTX_new ();
 21  		BIGNUM * tmp = BN_new ();
 22  
 23  		q = BN_new ();
 24  		// 2^255-19
 25  		BN_set_bit (q, 255); // 2^255
 26  		BN_sub_word (q, 19);
 27  
 28  		l = BN_new ();
 29  		// 2^252 + 27742317777372353535851937790883648493
 30  		BN_set_bit (l, 252);
 31  		two_252_2 = BN_dup (l);
 32  		BN_dec2bn (&tmp, "27742317777372353535851937790883648493");
 33  		BN_add (l, l, tmp);
 34  		BN_sub_word (two_252_2, 2); // 2^252 - 2
 35  
 36  		// -121665*inv(121666)
 37  		d = BN_new ();
 38  		BN_set_word (tmp, 121666);
 39  		BN_mod_inverse (tmp, tmp, q, ctx);
 40  		BN_set_word (d, 121665);
 41  		BN_set_negative (d, 1);
 42  		BN_mod_mul (d, d, tmp, q, ctx);
 43  
 44  		// 2^((q-1)/4)
 45  		I = BN_new ();
 46  		BN_free (tmp);
 47  		tmp = BN_dup (q);
 48  		BN_sub_word (tmp, 1);
 49  		BN_div_word (tmp, 4);
 50  		BN_set_word (I, 2);
 51  		BN_mod_exp (I, I, tmp, q, ctx);
 52  		BN_free (tmp);
 53  
 54  		// 4*inv(5)
 55  		BIGNUM * By = BN_new ();
 56  		BN_set_word (By, 5);
 57  		BN_mod_inverse (By, By, q, ctx);
 58  		BN_mul_word (By, 4);
 59  		BIGNUM * Bx = RecoverX (By, ctx);
 60  		BN_mod (Bx, Bx, q, ctx); // % q
 61  		BN_mod (By, By, q, ctx); // % q
 62  
 63  		// precalculate Bi256 table
 64  		Bi256Carry = { Bx, By }; // B
 65  		for (int i = 0; i < 32; i++)
 66  		{
 67  			Bi256[i][0] = Bi256Carry; // first point
 68  			for (int j = 1; j < 128; j++)
 69  				Bi256[i][j] = Sum (Bi256[i][j-1], Bi256[i][0], ctx); // (256+j+1)^i*B
 70  			Bi256Carry = Bi256[i][127];
 71  			for (int j = 0; j < 128; j++) // add first point 128 more times
 72  				Bi256Carry = Sum (Bi256Carry, Bi256[i][0], ctx);
 73  		}
 74  
 75  		BN_CTX_free (ctx);
 76  	}
 77  
 78  	Ed25519::Ed25519 (const Ed25519& other): q (BN_dup (other.q)), l (BN_dup (other.l)),
 79  		d (BN_dup (other.d)), I (BN_dup (other.I)), two_252_2 (BN_dup (other.two_252_2)),
 80  		Bi256Carry (other.Bi256Carry)
 81  	{
 82  		for (int i = 0; i < 32; i++)
 83  			for (int j = 0; j < 128; j++)
 84  				Bi256[i][j] = other.Bi256[i][j];
 85  	}
 86  
 87  	Ed25519::~Ed25519 ()
 88  	{
 89  		BN_free (q);
 90  		BN_free (l);
 91  		BN_free (d);
 92  		BN_free (I);
 93  		BN_free (two_252_2);
 94  	}
 95  
 96  
 97  	EDDSAPoint Ed25519::GeneratePublicKey (const uint8_t * expandedPrivateKey, BN_CTX * ctx) const
 98  	{
 99  		return MulB (expandedPrivateKey, ctx); // left half of expanded key, considered as Little Endian
100  	}
101  
102  	EDDSAPoint Ed25519::DecodePublicKey (const uint8_t * buf, BN_CTX * ctx) const
103  	{
104  		return DecodePoint (buf, ctx);
105  	}
106  
107  	void Ed25519::EncodePublicKey (const EDDSAPoint& publicKey, uint8_t * buf, BN_CTX * ctx) const
108  	{
109  		EncodePoint (Normalize (publicKey, ctx), buf);
110  	}
111  
112  	bool Ed25519::Verify (const EDDSAPoint& publicKey, const uint8_t * digest, const uint8_t * signature) const
113  	{
114  		BN_CTX * ctx = BN_CTX_new ();
115  		BIGNUM * h = DecodeBN<64> (digest);
116  		// signature 0..31 - R, 32..63 - S
117  		// B*S = R + PK*h => R = B*S - PK*h
118  		// we don't decode R, but encode (B*S - PK*h)
119  		auto Bs = MulB (signature + EDDSA25519_SIGNATURE_LENGTH/2, ctx); // B*S;
120  		BN_mod (h, h, l, ctx); // public key is multiple of B, but B%l = 0
121  		auto PKh = Mul (publicKey, h, ctx); // PK*h
122  		uint8_t diff[32];
123  		EncodePoint (Normalize (Sum (Bs, -PKh, ctx), ctx), diff); // Bs - PKh encoded
124  		bool passed = !memcmp (signature, diff, 32); // R
125  		BN_free (h);
126  		BN_CTX_free (ctx);
127  		if (!passed)
128  			LogPrint (eLogError, "25519 signature verification failed");
129  		return passed;
130  	}
131  
132  	void Ed25519::Sign (const uint8_t * expandedPrivateKey, const uint8_t * publicKeyEncoded,
133  		const uint8_t * buf, size_t len, uint8_t * signature) const
134  	{
135  		BN_CTX * bnCtx = BN_CTX_new ();
136  		// calculate r
137  		EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
138  		EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
139  		EVP_DigestUpdate (ctx, expandedPrivateKey + EDDSA25519_PRIVATE_KEY_LENGTH, EDDSA25519_PRIVATE_KEY_LENGTH); // right half of expanded key
140  		EVP_DigestUpdate (ctx, buf, len); // data
141  		uint8_t digest[64];
142  		unsigned int dl = 64;
143  		EVP_DigestFinal_ex (ctx, digest, &dl);
144  		EVP_MD_CTX_destroy (ctx);
145  		BIGNUM * r = DecodeBN<32> (digest); // DecodeBN<64> (digest); // for test vectors
146  		// calculate R
147  		uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
148  		EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R); // EncodePoint (Mul (B, r, bnCtx), R); // for test vectors
149  		// calculate S
150  		ctx = EVP_MD_CTX_create ();
151  		EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
152  		EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
153  		EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
154  		EVP_DigestUpdate (ctx, buf, len); // data
155  		dl = 64;
156  		EVP_DigestFinal_ex (ctx, digest, &dl);
157  		EVP_MD_CTX_destroy (ctx);
158  		BIGNUM * h = DecodeBN<64> (digest);
159  		// S = (r + h*a) % l
160  		BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (expandedPrivateKey); // left half of expanded key
161  		BN_mod_mul (h, h, a, l, bnCtx); // %l
162  		BN_mod_add (h, h, r, l, bnCtx); // %l
163  		memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
164  		EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
165  		BN_free (r); BN_free (h); BN_free (a);
166  		BN_CTX_free (bnCtx);
167  	}
168  
169  	void Ed25519::SignRedDSA (const uint8_t * privateKey, const uint8_t * publicKeyEncoded,
170  		const uint8_t * buf, size_t len, uint8_t * signature) const
171  	{
172  		BN_CTX * bnCtx = BN_CTX_new ();
173  		// T = 80 random bytes
174  		uint8_t T[80];
175  		RAND_bytes (T, 80);
176  		// calculate r = H*(T || publickey || data)
177  		EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
178  		EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
179  		EVP_DigestUpdate (ctx, T, 80);
180  		EVP_DigestUpdate (ctx, publicKeyEncoded, 32);
181  		EVP_DigestUpdate (ctx, buf, len); // data
182  		uint8_t digest[64];
183  		unsigned int dl = 64;
184  		EVP_DigestFinal_ex (ctx, digest, &dl);
185  		EVP_MD_CTX_destroy (ctx);
186  		BIGNUM * r = DecodeBN<64> (digest);
187  		BN_mod (r, r, l, bnCtx); // % l
188  		EncodeBN (r, digest, 32);
189  		// calculate R
190  		uint8_t R[EDDSA25519_SIGNATURE_LENGTH/2]; // we must use separate buffer because signature might be inside buf
191  		EncodePoint (Normalize (MulB (digest, bnCtx), bnCtx), R);
192  		// calculate S
193  		ctx = EVP_MD_CTX_create ();
194  		EVP_DigestInit_ex (ctx, EVP_sha512(), NULL);
195  		EVP_DigestUpdate (ctx, R, EDDSA25519_SIGNATURE_LENGTH/2); // R
196  		EVP_DigestUpdate (ctx, publicKeyEncoded, EDDSA25519_PUBLIC_KEY_LENGTH); // public key
197  		EVP_DigestUpdate (ctx, buf, len); // data
198  		dl = 64;
199  		EVP_DigestFinal_ex (ctx, digest, &dl);
200  		EVP_MD_CTX_destroy (ctx);
201  		BIGNUM * h = DecodeBN<64> (digest);
202  		// S = (r + h*a) % l
203  		BIGNUM * a = DecodeBN<EDDSA25519_PRIVATE_KEY_LENGTH> (privateKey);
204  		BN_mod_mul (h, h, a, l, bnCtx); // %l
205  		BN_mod_add (h, h, r, l, bnCtx); // %l
206  		memcpy (signature, R, EDDSA25519_SIGNATURE_LENGTH/2);
207  		EncodeBN (h, signature + EDDSA25519_SIGNATURE_LENGTH/2, EDDSA25519_SIGNATURE_LENGTH/2); // S
208  		BN_free (r); BN_free (h); BN_free (a);
209  		BN_CTX_free (bnCtx);
210  	}
211  
212  	EDDSAPoint Ed25519::Sum (const EDDSAPoint& p1, const EDDSAPoint& p2, BN_CTX * ctx) const
213  	{
214  		// x3 = (x1*y2+y1*x2)*(z1*z2-d*t1*t2)
215  		// y3 = (y1*y2+x1*x2)*(z1*z2+d*t1*t2)
216  		// z3 = (z1*z2-d*t1*t2)*(z1*z2+d*t1*t2)
217  		// t3 = (y1*y2+x1*x2)*(x1*y2+y1*x2)
218  		BIGNUM * x3 = BN_new (), * y3 = BN_new (), * z3 = BN_new (), * t3 = BN_new ();
219  
220  		BN_mul (x3, p1.x, p2.x, ctx); // A = x1*x2
221  		BN_mul (y3, p1.y, p2.y, ctx); // B = y1*y2
222  
223  		BN_CTX_start (ctx);
224  		BIGNUM * t1 = p1.t, * t2 = p2.t;
225  		if (!t1) { t1 = BN_CTX_get (ctx); BN_mul (t1, p1.x, p1.y, ctx); }
226  		if (!t2) { t2 = BN_CTX_get (ctx); BN_mul (t2, p2.x, p2.y, ctx); }
227  		BN_mul (t3, t1, t2, ctx);
228  		BN_mul (t3, t3, d, ctx); // C = d*t1*t2
229  
230  		if (p1.z)
231  		{
232  			if (p2.z)
233  				BN_mul (z3, p1.z, p2.z, ctx); // D = z1*z2
234  			else
235  				BN_copy (z3, p1.z); // D = z1
236  		}
237  		else
238  		{
239  			if (p2.z)
240  				BN_copy (z3, p2.z); // D = z2
241  			else
242  				BN_one (z3); // D = 1
243  		}
244  
245  		BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
246  		BN_add (E, p1.x, p1.y);
247  		BN_add (F, p2.x, p2.y);
248  		BN_mul (E, E, F, ctx); // (x1 + y1)*(x2 + y2)
249  		BN_sub (E, E, x3);
250  		BN_sub (E, E, y3); // E = (x1 + y1)*(x2 + y2) - A - B
251  		BN_sub (F, z3, t3); // F = D - C
252  		BN_add (G, z3, t3); // G = D + C
253  		BN_add (H, y3, x3); // H = B + A
254  
255  		BN_mod_mul (x3, E, F, q, ctx); // x3 = E*F
256  		BN_mod_mul (y3, G, H, q, ctx); // y3 = G*H
257  		BN_mod_mul (z3, F, G, q, ctx); // z3 = F*G
258  		BN_mod_mul (t3, E, H, q, ctx); // t3 = E*H
259  
260  		BN_CTX_end (ctx);
261  
262  		return EDDSAPoint {x3, y3, z3, t3};
263  	}
264  
265  	void Ed25519::Double (EDDSAPoint& p, BN_CTX * ctx) const
266  	{
267  		BN_CTX_start (ctx);
268  		BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * z2 = BN_CTX_get (ctx), * t2 = BN_CTX_get (ctx);
269  
270  		BN_sqr (x2, p.x, ctx); // x2 = A = x^2
271  		BN_sqr (y2, p.y, ctx); // y2 = B = y^2
272  		if (p.t)
273  			BN_sqr (t2, p.t, ctx); // t2 = t^2
274  		else
275  		{
276  			BN_mul (t2, p.x, p.y, ctx); // t = x*y
277  			BN_sqr (t2, t2, ctx); // t2 = t^2
278  		}
279  		BN_mul (t2, t2, d, ctx); // t2 = C = d*t^2
280  		if (p.z)
281  			BN_sqr (z2, p.z, ctx); // z2 = D = z^2
282  		else
283  			BN_one (z2); // z2 = 1
284  
285  		BIGNUM * E = BN_CTX_get (ctx), * F = BN_CTX_get (ctx), * G = BN_CTX_get (ctx), * H = BN_CTX_get (ctx);
286  		// E = (x+y)*(x+y)-A-B = x^2+y^2+2xy-A-B = 2xy
287  		BN_mul (E, p.x, p.y, ctx);
288  		BN_lshift1 (E, E);	// E =2*x*y
289  		BN_sub (F, z2, t2); // F = D - C
290  		BN_add (G, z2, t2); // G = D + C
291  		BN_add (H, y2, x2); // H = B + A
292  
293  		BN_mod_mul (p.x, E, F, q, ctx); // x2 = E*F
294  		BN_mod_mul (p.y, G, H, q, ctx); // y2 = G*H
295  		if (!p.z) p.z = BN_new ();
296  		BN_mod_mul (p.z, F, G, q, ctx); // z2 = F*G
297  		if (!p.t) p.t = BN_new ();
298  		BN_mod_mul (p.t, E, H, q, ctx); // t2 = E*H
299  
300  		BN_CTX_end (ctx);
301  	}
302  
303  	EDDSAPoint Ed25519::Mul (const EDDSAPoint& p, const BIGNUM * e, BN_CTX * ctx) const
304  	{
305  		BIGNUM * zero = BN_new (), * one = BN_new ();
306  		BN_zero (zero); BN_one (one);
307  		EDDSAPoint res {zero, one};
308  		if (!BN_is_zero (e))
309  		{
310  			int bitCount = BN_num_bits (e);
311  			for (int i = bitCount - 1; i >= 0; i--)
312  			{
313  				Double (res, ctx);
314  				if (BN_is_bit_set (e, i)) res = Sum (res, p, ctx);
315  			}
316  		}
317  		return res;
318  	}
319  
320  	EDDSAPoint Ed25519::MulB (const uint8_t * e, BN_CTX * ctx) const // B*e, e is 32 bytes Little Endian
321  	{
322  		BIGNUM * zero = BN_new (), * one = BN_new ();
323  		BN_zero (zero); BN_one (one);
324  		EDDSAPoint res {zero, one};
325  		bool carry = false;
326  		for (int i = 0; i < 32; i++)
327  		{
328  			uint8_t x = e[i];
329  			if (carry)
330  			{
331  				if (x < 255)
332  				{
333  					x++;
334  					carry = false;
335  				}
336  				else
337  					x = 0;
338  			}
339  			if (x > 0)
340  			{
341  				if (x <= 128)
342  					res = Sum (res, Bi256[i][x-1], ctx);
343  				else
344  				{
345  					res = Sum (res, -Bi256[i][255-x], ctx); // -Bi[256-x]
346  					carry = true;
347  				}
348  			}
349  		}
350  		if (carry) res = Sum (res, Bi256Carry, ctx);
351  		return res;
352  	}
353  
354  	EDDSAPoint Ed25519::Normalize (const EDDSAPoint& p, BN_CTX * ctx) const
355  	{
356  		if (p.z)
357  		{
358  			BIGNUM * x = BN_new (), * y = BN_new ();
359  			BN_mod_inverse (y, p.z, q, ctx);
360  			BN_mod_mul (x, p.x, y, q, ctx); // x = x/z
361  			BN_mod_mul (y, p.y, y, q, ctx); // y = y/z
362  			return EDDSAPoint{x, y};
363  		}
364  		else
365  			return EDDSAPoint{BN_dup (p.x), BN_dup (p.y)};
366  	}
367  
368  	bool Ed25519::IsOnCurve (const EDDSAPoint& p, BN_CTX * ctx) const
369  	{
370  		BN_CTX_start (ctx);
371  		BIGNUM * x2 = BN_CTX_get (ctx), * y2 = BN_CTX_get (ctx), * tmp = BN_CTX_get (ctx);
372  		BN_sqr (x2, p.x, ctx); // x^2
373  		BN_sqr (y2, p.y, ctx); // y^2
374  		// y^2 - x^2 - 1 - d*x^2*y^2
375  		BN_mul (tmp, d, x2, ctx);
376  		BN_mul (tmp, tmp, y2, ctx);
377  		BN_sub (tmp, y2, tmp);
378  		BN_sub (tmp, tmp, x2);
379  		BN_sub_word (tmp, 1);
380  		BN_mod (tmp, tmp, q, ctx); // % q
381  		bool ret = BN_is_zero (tmp);
382  		BN_CTX_end (ctx);
383  		return ret;
384  	}
385  
386  	BIGNUM * Ed25519::RecoverX (const BIGNUM * y, BN_CTX * ctx) const
387  	{
388  		BN_CTX_start (ctx);
389  		BIGNUM * y2 = BN_CTX_get (ctx), * xx = BN_CTX_get (ctx);
390  		BN_sqr (y2, y, ctx); // y^2
391  		// xx = (y^2 -1)*inv(d*y^2 +1)
392  		BN_mul (xx, d, y2, ctx);
393  		BN_add_word (xx, 1);
394  		BN_mod_inverse (xx, xx, q, ctx);
395  		BN_sub_word (y2, 1);
396  		BN_mul (xx, y2, xx, ctx);
397  		// x = srqt(xx) = xx^(2^252-2)
398  		BIGNUM * x = BN_new ();
399  		BN_mod_exp (x, xx, two_252_2, q, ctx);
400  		// check (x^2 -xx) % q
401  		BN_sqr (y2, x, ctx);
402  		BN_mod_sub (y2, y2, xx, q, ctx);
403  		if (!BN_is_zero (y2))
404  			BN_mod_mul (x, x, I, q, ctx);
405  		if (BN_is_odd (x))
406  			BN_sub (x, q, x);
407  		BN_CTX_end (ctx);
408  		return x;
409  	}
410  
411  	EDDSAPoint Ed25519::DecodePoint (const uint8_t * buf, BN_CTX * ctx) const
412  	{
413  		// buf is 32 bytes Little Endian, convert it to Big Endian
414  		uint8_t buf1[EDDSA25519_PUBLIC_KEY_LENGTH];
415  		for (size_t i = 0; i < EDDSA25519_PUBLIC_KEY_LENGTH/2; i++) // invert bytes
416  		{
417  			buf1[i] = buf[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i];
418  			buf1[EDDSA25519_PUBLIC_KEY_LENGTH -1 - i] = buf[i];
419  		}
420  		bool isHighestBitSet = buf1[0] & 0x80;
421  		if (isHighestBitSet)
422  			buf1[0] &= 0x7f; // clear highest bit
423  		BIGNUM * y = BN_new ();
424  		BN_bin2bn (buf1, EDDSA25519_PUBLIC_KEY_LENGTH, y);
425  		BIGNUM * x = RecoverX (y, ctx);
426  		if ((bool)BN_is_bit_set (x, 0) != isHighestBitSet)
427  			BN_sub (x, q, x); // x = q - x
428  		BIGNUM * z = BN_new (), * t = BN_new ();
429  		BN_one (z); BN_mod_mul (t, x, y, q, ctx); // pre-calculate t
430  		EDDSAPoint p {x, y, z, t};
431  		if (!IsOnCurve (p, ctx))
432  			LogPrint (eLogError, "Decoded point is not on 25519");
433  		return p;
434  	}
435  
436  	void Ed25519::EncodePoint (const EDDSAPoint& p, uint8_t * buf) const
437  	{
438  		EncodeBN (p.y, buf,EDDSA25519_PUBLIC_KEY_LENGTH);
439  		if (BN_is_bit_set (p.x, 0)) // highest bit
440  			buf[EDDSA25519_PUBLIC_KEY_LENGTH - 1] |= 0x80; // set highest bit
441  	}
442  
443  	template<int len>
444  	BIGNUM * Ed25519::DecodeBN (const uint8_t * buf) const
445  	{
446  		// buf is Little Endian convert it to Big Endian
447  		uint8_t buf1[len];
448  		for (size_t i = 0; i < len/2; i++) // invert bytes
449  		{
450  			buf1[i] = buf[len -1 - i];
451  			buf1[len -1 - i] = buf[i];
452  		}
453  		BIGNUM * res = BN_new ();
454  		BN_bin2bn (buf1, len, res);
455  		return res;
456  	}
457  
458  	void Ed25519::EncodeBN (const BIGNUM * bn, uint8_t * buf, size_t len) const
459  	{
460  		bn2buf (bn, buf, len);
461  		// To Little Endian
462  		for (size_t i = 0; i < len/2; i++) // invert bytes
463  		{
464  			uint8_t tmp = buf[i];
465  			buf[i] = buf[len -1 - i];
466  			buf[len -1 - i] = tmp;
467  		}
468  	}
469  
470  	void Ed25519::BlindPublicKey (const uint8_t * pub, const uint8_t * seed, uint8_t * blinded)
471  	{
472  		BN_CTX * ctx = BN_CTX_new ();
473  		// calculate alpha = seed mod l
474  		BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian
475  		BN_mod (alpha, alpha, l, ctx); // % l
476  		uint8_t priv[32];
477  		EncodeBN (alpha, priv, 32); // back to Little Endian
478  		BN_free (alpha);
479  		// A' = BLIND_PUBKEY(A, alpha) = A + DERIVE_PUBLIC(alpha)
480  		auto A1 = Sum (DecodePublicKey (pub, ctx), MulB (priv, ctx), ctx); // pub + B*alpha
481  		EncodePublicKey (A1, blinded, ctx);
482  		BN_CTX_free (ctx);
483  	}
484  
485  	void Ed25519::BlindPrivateKey (const uint8_t * priv, const uint8_t * seed, uint8_t * blindedPriv, uint8_t * blindedPub)
486  	{
487  		BN_CTX * ctx = BN_CTX_new ();
488  		// calculate alpha = seed mod l
489  		BIGNUM * alpha = DecodeBN<64> (seed); // seed is in Little Endian
490  		BN_mod (alpha, alpha, l, ctx); // % l
491  		BIGNUM * p = DecodeBN<32> (priv); // priv is in Little Endian
492  		BN_add (alpha, alpha, p); // alpha = alpha + priv
493  		// a' = BLIND_PRIVKEY(a, alpha) = (a + alpha) mod L
494  		BN_mod (alpha, alpha, l, ctx); // % l
495  		EncodeBN (alpha, blindedPriv, 32);
496  		// A' = DERIVE_PUBLIC(a')
497  		auto A1 = MulB (blindedPriv, ctx);
498  		EncodePublicKey (A1, blindedPub, ctx);
499  		BN_free (alpha); BN_free (p);
500  		BN_CTX_free (ctx);
501  	}
502  
503  	void Ed25519::ExpandPrivateKey (const uint8_t * key, uint8_t * expandedKey)
504  	{
505  		SHA512 (key, EDDSA25519_PRIVATE_KEY_LENGTH, expandedKey);
506  		expandedKey[0] &= 0xF8; // drop last 3 bits
507  		expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] &= 0x3F; // drop first 2 bits
508  		expandedKey[EDDSA25519_PRIVATE_KEY_LENGTH - 1] |= 0x40; // set second bit
509  	}
510  
511  	void Ed25519::CreateRedDSAPrivateKey (uint8_t * priv)
512  	{
513  		uint8_t seed[32];
514  		RAND_bytes (seed, 32);
515  		BIGNUM * p = DecodeBN<32> (seed);
516  		BN_CTX * ctx = BN_CTX_new ();
517  		BN_mod (p, p, l, ctx); // % l
518  		EncodeBN (p, priv, 32);
519  		BN_CTX_free (ctx);
520  		BN_free (p);
521  	}
522  
523  	static std::unique_ptr<Ed25519> g_Ed25519;
524  	std::unique_ptr<Ed25519>& GetEd25519 ()
525  	{
526  		if (!g_Ed25519)
527  		{
528  			auto c = new Ed25519();
529  			if (!g_Ed25519) // make sure it was not created already
530  				g_Ed25519.reset (c);
531  			else
532  				delete c;
533  		}
534  		return g_Ed25519;
535  	}
536  }
537  }