134 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.IO;
 | |
| using System.Numerics;
 | |
| using System.Security.Cryptography;
 | |
| using System.Text;
 | |
| 
 | |
| namespace Ed25519
 | |
| {
 | |
|     public static class Extensions
 | |
|     {
 | |
|         internal static ReadOnlySpan<byte> ComputeHash(this ReadOnlySpan<byte> data)
 | |
|         {
 | |
|             using var sha512 = SHA512.Create();
 | |
|             return sha512.ComputeHash(data.ToArray());
 | |
|         }
 | |
| 
 | |
|         internal static ReadOnlySpan<byte> ComputeHash(this Stream inputStream)
 | |
|         {
 | |
|             inputStream.Seek(0, SeekOrigin.Begin);
 | |
| 
 | |
|             using var sha512 = SHA512.Create();
 | |
|             return sha512.ComputeHash(inputStream);
 | |
|         }
 | |
| 
 | |
|         internal static BigInteger Mod(this BigInteger number, BigInteger modulo)
 | |
|         {
 | |
|             var result = number % modulo;
 | |
|             return result < 0 ? result + modulo : result;
 | |
|         }
 | |
| 
 | |
|         internal static BigInteger Inv(this BigInteger number)
 | |
|         {
 | |
|             return number.ExpMod(Constants.QM2, Constants.Q);
 | |
|         }
 | |
| 
 | |
|         internal static BigInteger RecoverX(this BigInteger y)
 | |
|         {
 | |
|             var y2 = y * y;
 | |
|             var xx = (y2 - 1) * (Constants.D * y2 + 1).Inv();
 | |
|             var x = xx.ExpMod(Constants.RECOVER_X_EXP, Constants.Q);
 | |
| 
 | |
|             if (!(x * x - xx).Mod(Constants.Q).Equals(BigInteger.Zero))
 | |
|             {
 | |
|                 x = (x * Constants.I).Mod(Constants.Q);
 | |
|             }
 | |
| 
 | |
|             if (!x.IsEven)
 | |
|             {
 | |
|                 x = Constants.Q - x;
 | |
|             }
 | |
| 
 | |
|             return x;
 | |
|         }
 | |
| 
 | |
|         internal static BigInteger ExpMod(this BigInteger number, BigInteger exponent, BigInteger modulo)
 | |
|         {
 | |
|             if (exponent.Equals(BigInteger.Zero))
 | |
|             {
 | |
|                 return BigInteger.One;
 | |
|             }
 | |
| 
 | |
|             var result = BigInteger.Pow(number.ExpMod(exponent / Constants.TWO, modulo), 2).Mod(modulo);
 | |
|             
 | |
|             if (exponent.IsEven)
 | |
|                 return result;
 | |
| 
 | |
|             result *= number;
 | |
|             result = result.Mod(modulo);
 | |
|             return result;
 | |
|         }
 | |
| 
 | |
|         internal static Span<byte> EncodeInt(this BigInteger number)
 | |
|         {
 | |
|             var nin = number.ToByteArray();
 | |
|             var nout = new byte[Math.Max(nin.Length, 32)];
 | |
|             
 | |
|             Array.Copy(nin, nout, nin.Length);
 | |
|             return nout;
 | |
|         }
 | |
| 
 | |
|         internal static BigInteger DecodeInt(this ReadOnlySpan<byte> data)
 | |
|         {
 | |
|             return new BigInteger(data) & Constants.U_N;
 | |
|         }
 | |
| 
 | |
|         internal static BigInteger HashInt(this MemoryStream data)
 | |
|         {
 | |
|             data.Seek(0, SeekOrigin.Begin);
 | |
| 
 | |
|             var hash = data.ComputeHash();
 | |
|             var hashSum = BigInteger.Zero;
 | |
| 
 | |
|             for (var i = 0; i < 2 * Constants.BIT_LENGTH; i++)
 | |
|             {
 | |
|                 var bit = hash.GetBit(i);
 | |
|                 if (bit != 0)
 | |
|                 {
 | |
|                     hashSum += Constants.TWO_POW_CACHE[i];
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return hashSum;
 | |
|         }
 | |
| 
 | |
|         internal static int GetBit(this ReadOnlySpan<byte> data, int index)
 | |
|         {
 | |
|             return data[index / 8] >> (index % 8) & 1;
 | |
|         }
 | |
| 
 | |
|         public static ReadOnlySpan<byte> ExtractPublicKey(this ReadOnlySpan<byte> privateKey)
 | |
|         {
 | |
|             var hash = privateKey.ComputeHash();
 | |
|             var a = Constants.TWO_POW_BIT_LENGTH_MINUS_TWO;
 | |
|             for (var i = 3; i < Constants.BIT_LENGTH - 2; i++)
 | |
|             {
 | |
|                 var bit = hash.GetBit(i);
 | |
|                 if (bit != 0)
 | |
|                 {
 | |
|                     a += Constants.TWO_POW_CACHE[i];
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             var bigA = Constants.B.ScalarMul(a);
 | |
|             return bigA.EncodePoint();
 | |
|         }
 | |
| 
 | |
|         public static ReadOnlySpan<byte> ExtractPublicKey(this Span<byte> privateKey)
 | |
|         {
 | |
|             return new ReadOnlySpan<byte>(privateKey.ToArray()).ExtractPublicKey();
 | |
|         }
 | |
|     }
 | |
| }
 |