1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . IO ;
4+ using System . Linq ;
5+ using System . Numerics ;
6+ using System . Security . Cryptography ;
7+
8+ namespace Cryptographic
9+ {
10+ /* Ported and refactored from Java to C# by Hans Wolff, 10/10/2013
11+ * Released to the public domain
12+ * /
13+
14+ /* Java code written by k3d3
15+ * Source: https://github.com/k3d3/ed25519-java/blob/master/ed25519.java
16+ * Released to the public domain
17+ */
18+
19+ public class Ed25519
20+ {
21+ private static byte [ ] ComputeHash ( byte [ ] m )
22+ {
23+ using ( var sha512 = SHA512 . Create ( ) ) // System.Security.Cryptography
24+ {
25+ return sha512 . ComputeHash ( m ) ;
26+ }
27+ }
28+
29+ private static BigInteger ExpMod ( BigInteger number , BigInteger exponent , BigInteger modulo )
30+ {
31+ BigInteger result = BigInteger . One ;
32+ BigInteger baseVal = number . Mod ( modulo ) ;
33+
34+ while ( exponent > 0 )
35+ {
36+ if ( ! exponent . IsEven )
37+ {
38+ result = ( result * baseVal ) . Mod ( modulo ) ;
39+ }
40+ baseVal = ( baseVal * baseVal ) . Mod ( modulo ) ;
41+ exponent /= 2 ;
42+ }
43+
44+ return result ;
45+ }
46+
47+
48+ private static readonly Dictionary < BigInteger , BigInteger > InverseCache = new Dictionary < BigInteger , BigInteger > ( ) ;
49+
50+ private static BigInteger Inv ( BigInteger x )
51+ {
52+ if ( ! InverseCache . ContainsKey ( x ) )
53+ {
54+ InverseCache [ x ] = ExpMod ( x , Qm2 , Q ) ;
55+ }
56+ return InverseCache [ x ] ;
57+ }
58+
59+ private static BigInteger RecoverX ( BigInteger y )
60+ {
61+ BigInteger y2 = y * y ;
62+ BigInteger xx = ( y2 - 1 ) * Inv ( D * y2 + 1 ) ;
63+ BigInteger x = ExpMod ( xx , Qp3 / Eight , Q ) ;
64+ if ( ! ( x * x - xx ) . Mod ( Q ) . Equals ( BigInteger . Zero ) )
65+ {
66+ x = ( x * I ) . Mod ( Q ) ;
67+ }
68+ if ( ! x . IsEven )
69+ {
70+ x = Q - x ;
71+ }
72+ return x ;
73+ }
74+
75+ private static Tuple < BigInteger , BigInteger > Edwards ( BigInteger px , BigInteger py , BigInteger qx , BigInteger qy )
76+ {
77+ BigInteger xx12 = px * qx ;
78+ BigInteger yy12 = py * qy ;
79+ BigInteger dtemp = D * xx12 * yy12 ;
80+ BigInteger x3 = ( px * qy + qx * py ) * ( Inv ( 1 + dtemp ) ) ;
81+ BigInteger y3 = ( py * qy + xx12 ) * ( Inv ( 1 - dtemp ) ) ;
82+ return new Tuple < BigInteger , BigInteger > ( x3 . Mod ( Q ) , y3 . Mod ( Q ) ) ;
83+ }
84+
85+ private static Tuple < BigInteger , BigInteger > EdwardsSquare ( BigInteger x , BigInteger y )
86+ {
87+ BigInteger xx = x * x ;
88+ BigInteger yy = y * y ;
89+ BigInteger dtemp = D * xx * yy ;
90+ BigInteger x3 = ( 2 * x * y ) * ( Inv ( 1 + dtemp ) ) ;
91+ BigInteger y3 = ( yy + xx ) * ( Inv ( 1 - dtemp ) ) ;
92+ return new Tuple < BigInteger , BigInteger > ( x3 . Mod ( Q ) , y3 . Mod ( Q ) ) ;
93+ }
94+ private static Tuple < BigInteger , BigInteger > ScalarMul ( Tuple < BigInteger , BigInteger > point , BigInteger scalar )
95+ {
96+ var result = new Tuple < BigInteger , BigInteger > ( BigInteger . Zero , BigInteger . One ) ; // Neutral element
97+ var basePoint = point ;
98+
99+ while ( scalar > 0 )
100+ {
101+ if ( ! scalar . IsEven ) // If the current bit is set, add the base point to the result
102+ {
103+ result = Edwards ( result . Item1 , result . Item2 , basePoint . Item1 , basePoint . Item2 ) ;
104+ }
105+
106+ basePoint = EdwardsSquare ( basePoint . Item1 , basePoint . Item2 ) ; // Double the point
107+ scalar >>= 1 ; // Move to the next bit in the scalar
108+ }
109+
110+ return result ;
111+ }
112+
113+ public static byte [ ] EncodeInt ( BigInteger y )
114+ {
115+ byte [ ] nin = y . ToByteArray ( ) ;
116+ var nout = new byte [ Math . Max ( nin . Length , 32 ) ] ;
117+ Array . Copy ( nin , nout , nin . Length ) ;
118+ return nout ;
119+ }
120+
121+ public static byte [ ] EncodePoint ( BigInteger x , BigInteger y )
122+ {
123+ byte [ ] nout = EncodeInt ( y ) ;
124+ nout [ nout . Length - 1 ] |= ( x . IsEven ? ( byte ) 0 : ( byte ) 0x80 ) ;
125+ return nout ;
126+ }
127+
128+ private static int GetBit ( byte [ ] h , int i )
129+ {
130+ return h [ i / 8 ] >> ( i % 8 ) & 1 ;
131+ }
132+
133+ public static byte [ ] PublicKey ( byte [ ] signingKey )
134+ {
135+ byte [ ] h = ComputeHash ( signingKey ) ;
136+ BigInteger a = TwoPowBitLengthMinusTwo ;
137+ for ( int i = 3 ; i < ( BitLength - 2 ) ; i ++ )
138+ {
139+ var bit = GetBit ( h , i ) ;
140+ if ( bit != 0 )
141+ {
142+ a += TwoPowCache [ i ] ;
143+ }
144+ }
145+ var bigA = ScalarMul ( B , a ) ;
146+ return EncodePoint ( bigA . Item1 , bigA . Item2 ) ;
147+ }
148+
149+ private static BigInteger HashInt ( byte [ ] m )
150+ {
151+ byte [ ] h = ComputeHash ( m ) ;
152+ BigInteger hsum = BigInteger . Zero ;
153+ for ( int i = 0 ; i < 2 * BitLength ; i ++ )
154+ {
155+ var bit = GetBit ( h , i ) ;
156+ if ( bit != 0 )
157+ {
158+ hsum += TwoPowCache [ i ] ;
159+ }
160+ }
161+ return hsum ;
162+ }
163+
164+ public static byte [ ] Signature ( byte [ ] message , byte [ ] signingKey , byte [ ] publicKey )
165+ {
166+ byte [ ] h = ComputeHash ( signingKey ) ;
167+ BigInteger a = TwoPowBitLengthMinusTwo ;
168+ for ( int i = 3 ; i < ( BitLength - 2 ) ; i ++ )
169+ {
170+ var bit = GetBit ( h , i ) ;
171+ if ( bit != 0 )
172+ {
173+ a += TwoPowCache [ i ] ;
174+ }
175+ }
176+
177+ BigInteger r ;
178+ using ( var rsub = new MemoryStream ( ( BitLength / 8 ) + message . Length ) )
179+ {
180+ rsub . Write ( h , BitLength / 8 , BitLength / 4 - BitLength / 8 ) ;
181+ rsub . Write ( message , 0 , message . Length ) ;
182+ r = HashInt ( rsub . ToArray ( ) ) ;
183+ }
184+ var bigR = ScalarMul ( B , r ) ;
185+ BigInteger s ;
186+ var encodedBigR = EncodePoint ( bigR . Item1 , bigR . Item2 ) ;
187+ using ( var stemp = new MemoryStream ( 32 + publicKey . Length + message . Length ) )
188+ {
189+ stemp . Write ( encodedBigR , 0 , encodedBigR . Length ) ;
190+ stemp . Write ( publicKey , 0 , publicKey . Length ) ;
191+ stemp . Write ( message , 0 , message . Length ) ;
192+ s = ( r + HashInt ( stemp . ToArray ( ) ) * a ) . Mod ( L ) ;
193+ }
194+
195+ using ( var nout = new MemoryStream ( 64 ) )
196+ {
197+ nout . Write ( encodedBigR , 0 , encodedBigR . Length ) ;
198+ var encodeInt = EncodeInt ( s ) ;
199+ nout . Write ( encodeInt , 0 , encodeInt . Length ) ;
200+ return nout . ToArray ( ) ;
201+ }
202+ }
203+
204+ private static bool IsOnCurve ( BigInteger x , BigInteger y )
205+ {
206+ BigInteger xx = x * x ;
207+ BigInteger yy = y * y ;
208+ BigInteger dxxyy = D * yy * xx ;
209+ return ( yy - xx - dxxyy - 1 ) . Mod ( Q ) . Equals ( BigInteger . Zero ) ;
210+ }
211+
212+ private static BigInteger DecodeInt ( byte [ ] s )
213+ {
214+ return new BigInteger ( s ) & Un ;
215+ }
216+
217+ private static Tuple < BigInteger , BigInteger > DecodePoint ( byte [ ] pointBytes )
218+ {
219+ BigInteger y = new BigInteger ( pointBytes ) & Un ;
220+ BigInteger x = RecoverX ( y ) ;
221+ if ( ( x . IsEven ? 0 : 1 ) != GetBit ( pointBytes , BitLength - 1 ) )
222+ {
223+ x = Q - x ;
224+ }
225+ var point = new Tuple < BigInteger , BigInteger > ( x , y ) ;
226+ if ( ! IsOnCurve ( x , y ) ) throw new ArgumentException ( "Decoding point that is not on curve" ) ;
227+ return point ;
228+ }
229+
230+ public static bool CheckValid ( byte [ ] signature , byte [ ] message , byte [ ] publicKey )
231+ {
232+ Console . Write ( "." ) ; // ... dots in console
233+ if ( signature . Length != BitLength / 4 ) throw new ArgumentException ( "Signature length is wrong" ) ;
234+ if ( publicKey . Length != BitLength / 8 ) throw new ArgumentException ( "Public key length is wrong" ) ;
235+
236+ byte [ ] rByte = Arrays . CopyOfRange ( signature , 0 , BitLength / 8 ) ;
237+
238+ var r = DecodePoint ( rByte ) ;
239+ var a = DecodePoint ( publicKey ) ;
240+
241+ byte [ ] sByte = Arrays . CopyOfRange ( signature , BitLength / 8 , BitLength / 4 ) ;
242+
243+ BigInteger s = DecodeInt ( sByte ) ;
244+ BigInteger h ;
245+
246+ using ( var stemp = new MemoryStream ( 32 + publicKey . Length + message . Length ) )
247+ {
248+ var encodePoint = EncodePoint ( r . Item1 , r . Item2 ) ;
249+ stemp . Write ( encodePoint , 0 , encodePoint . Length ) ;
250+ stemp . Write ( publicKey , 0 , publicKey . Length ) ;
251+ stemp . Write ( message , 0 , message . Length ) ;
252+ h = HashInt ( stemp . ToArray ( ) ) ;
253+ }
254+
255+ Console . Write ( "." ) ; // ... dots in console
256+ var ra = ScalarMul ( B , s ) ;
257+ Console . Write ( "." ) ; // ... dots in console
258+ var ah = ScalarMul ( a , h ) ;
259+ var rb = Edwards ( r . Item1 , r . Item2 , ah . Item1 , ah . Item2 ) ;
260+ if ( ! ra . Item1 . Equals ( rb . Item1 ) || ! ra . Item2 . Equals ( rb . Item2 ) )
261+ return false ;
262+ return true ;
263+ }
264+
265+ private const int BitLength = 256 ;
266+
267+ private static readonly BigInteger TwoPowBitLengthMinusTwo = BigInteger . Pow ( 2 , BitLength - 2 ) ;
268+ private static readonly BigInteger [ ] TwoPowCache = Enumerable . Range ( 0 , 2 * BitLength ) . Select ( i => BigInteger . Pow ( 2 , i ) ) . ToArray ( ) ;
269+
270+ private static readonly BigInteger Q =
271+ BigInteger . Parse ( "57896044618658097711785492504343953926634992332820282019728792003956564819949" ) ;
272+
273+ private static readonly BigInteger Qm2 =
274+ BigInteger . Parse ( "57896044618658097711785492504343953926634992332820282019728792003956564819947" ) ;
275+
276+ private static readonly BigInteger Qp3 =
277+ BigInteger . Parse ( "57896044618658097711785492504343953926634992332820282019728792003956564819952" ) ;
278+
279+ private static readonly BigInteger L =
280+ BigInteger . Parse ( "7237005577332262213973186563042994240857116359379907606001950938285454250989" ) ;
281+
282+ private static readonly BigInteger D =
283+ BigInteger . Parse ( "-4513249062541557337682894930092624173785641285191125241628941591882900924598840740" ) ;
284+
285+ private static readonly BigInteger I =
286+ BigInteger . Parse ( "19681161376707505956807079304988542015446066515923890162744021073123829784752" ) ;
287+
288+ private static readonly BigInteger By =
289+ BigInteger . Parse ( "46316835694926478169428394003475163141307993866256225615783033603165251855960" ) ;
290+
291+ private static readonly BigInteger Bx =
292+ BigInteger . Parse ( "15112221349535400772501151409588531511454012693041857206046113283949847762202" ) ;
293+
294+ private static readonly Tuple < BigInteger , BigInteger > B = new Tuple < BigInteger , BigInteger > ( Bx . Mod ( Q ) , By . Mod ( Q ) ) ;
295+
296+ private static readonly BigInteger Un =
297+ BigInteger . Parse ( "57896044618658097711785492504343953926634992332820282019728792003956564819967" ) ;
298+
299+ private static readonly BigInteger Two = new BigInteger ( 2 ) ;
300+ private static readonly BigInteger Eight = new BigInteger ( 8 ) ;
301+ }
302+
303+ internal static class Arrays
304+ {
305+ public static byte [ ] CopyOfRange ( byte [ ] original , int from , int to )
306+ {
307+ int length = to - from ;
308+ var result = new byte [ length ] ;
309+ Array . Copy ( original , from , result , 0 , length ) ;
310+ return result ;
311+ }
312+ }
313+
314+ internal static class BigIntegerHelpers
315+ {
316+ public static BigInteger Mod ( this BigInteger num , BigInteger modulo )
317+ {
318+ var result = num % modulo ;
319+ return result < 0 ? result + modulo : result ;
320+ }
321+ }
322+ }
0 commit comments