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