今すぐに何か本格的なことをするつもりで始めたわけではないけれど、ずっと気になってたヤツ。
Python for .NET の薄っぺらい紹介に続く話ではあるんだけれど、今回はそこまでいかない。
それよりも こっち。これは PowerShell がダイレクトに C# 「ソースコード」を使えてしまう、という驚異的な話だった。コンパイル済みライブラリなら全然びっくりなんかしないのさ、ソースコードのまま使えるんだもん、すげーよ。
ただせっかく Python for .NET 入れたんだから、こういったものも Python から呼び出せたら嬉しいこともあるだろうなぁ、と。この動機は これに書いた通りで、「C# コードでしか答えが見つからないような、何かオモロイこと」をそのまま直接活用したり、あるいは「pure な python への移植を、「動く正解付きで」出来ろ」みたいなことね。動機はそうだけど、さすがに Python for .NET から「C# ソースコードをダイレクトに」使う手段はなかろう、あるわけなかろうと今のところ思ってる。ちゃんとビルドしてライブラリにしないと使えないであろう、と。
リンク先の元ネタを書いた際は、それこそほんとに Python 2.7 に耐えるだけの C/C++ 環境、しかなかったので、ほんとに C# プロジェクトをビルド出来る見込みはなかった、「のだと思っている」。なんで断言しないかっつーと、「実はひっそり知らずに持ってた」パターンてありがちだからね。
でも今は明らかにあの時とはワタシの持ってる環境が違ってて。そもそも Microsoft Build Tools for Visual Studio 2017 は Microsoft Visual C++ Compiler for Python 2.7 なんぞよりずっと遥かに太っ腹で、ほんとに「IDE がない」ことしか「苦でない」のね。この中には気付かずに持ってたものも結構ある。
Microsoft Build Tools がとりわけ太っ腹なのが、「MSBuild」が同根されていることだったりする。ワタシは Visual Stutio 6.0 からの VC ユーザなのだが、これは会社で買った製品版だったわけだ。けれどその後「個人で」となると、そうそう毎度購入してまで、とはしなかった。となれば Visual Stutio Xxx Express Edition シリーズを選んできたわけなのだが、その「安価もしくは無償なかわりに使えないものたち」の代表的なものが「コマンドラインからのビルドツール(当時は DEVENV とか)だったのだ。Microsoft Visual C++ Compiler for Python 2.7 もこの流れを完全に踏襲していて、Microsoft Visual C++ Compiler for Python 2.7 からは IDE すらないわけだから、ほんとに「素のコンパイラたちだけ」でちまちま頑張るしかなかったわけなのだ。
で。その MSBuild.exe 同根、なことについては当然日頃からありがたがっているんだけれど、さすがに C# コンパイラも同梱されてたことには気付いてなかった。superuser のこの記事 を読んで、「ん?」と思って確認したら、ちゃんと入っておった…、そうかそうだったのか。(とかいいつつインストール時に自分で選んでたりするのかもしらんけど、だとしてもちゃんと「無償で」入手できていることには違いはない。):
1 [me@host: ~]$ type -p MSBuild.exe
2 /c/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/MSBuild/15.0/bin/MSBuild.exe
3 [me@host: ~]$ type -p csc.exe
4 /c/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/MSBuild/15.0/bin/Roslyn/csc.exe
5 [me@host: ~]$ csc -? | head
6 Microsoft (R) Visual C# Compiler バージョン 2.2.0.61624
7 Copyright (C) Microsoft Corporation. All rights reserved.
8
9
10 Visual C# Compiler のオプション
11
12 - 出力ファイル -
13 /out:<file> 出力ファイル名を指定します (既定: メイン クラス
14 のあるファイルまたは最初のファイルのベース名)
15 /target:exe コンソール実行可能ファイルをビルドします (既定) (短い形式:
ちぅわけで MSBuild.exe で「C# プロジェクト」をビルド出来る! んだけれど…、ただこれは C#、.NET を日常にしてないなら簡単じゃない。色んな依存物との格闘になるから。特に NuGet だと思う。既存のプロジェクトを適当に拾ってきて試してみる、というのはあんまり気軽じゃない。
となれば「ちまっと小さな C# コードを作ってビルドしたい」と考えたいけれど、太っ腹な BuildTools にも当然「無償がゆえに欠けているもの」があって、「プロジェクトビルダがない」(新規ソリューションを作る術がない)、「と思う」。(これも気付いてないだけの可能性はないではないんだけれど。) だとすりゃぁ、「csc は持ってるんだもん、cl とおんなじノリで、マニュアルビルドしちまうかぁ」、、、て話、今回の話は。
なげー前置きですまんな。つーか記事のほとんどが前置きである。
これで例にした C# コードを一応再掲:
1 using System;
2 using System.Security.Cryptography;
3 using System.Drawing;
4
5 public class Rand : System.Random
6 {
7 RandomNumberGenerator rng = new RNGCryptoServiceProvider();
8 byte[] b = new byte[4];
9
10 protected override double Sample()
11 {
12 rng.GetBytes(b);
13 uint u = BitConverter.ToUInt32(b, 0);
14 return u / (uint.MaxValue + 1.0);
15 }
16 }
17
18 public class ConsoleApp
19 {
20 static Rand rand = new Rand();
21
22 [STAThread]
23 public static void Main(string[] args)
24 {
25 HashFunction hf = new SBoxHash();
26 AvalancheTest(hf);
27 BitCorrelationTest(hf);
28 BucketTest(hf);
29 Console.Write("\r\n>");
30 Console.ReadLine();
31 }
32
33 private static void GenerateSBox()
34 {
35 byte[] b = new byte[4];
36 for (int i = 0; i < 256; i++)
37 {
38 rand.NextBytes(b);
39 uint s = BitConverter.ToUInt32(b, 0);
40 Console.Write("0x{0:X8}, ", s);
41 if (i % 4 == 3)
42 Console.WriteLine();
43 }
44 }
45
46 static void BitCorrelationTest(HashFunction hf)
47 {
48 int[,] H = new int[32, 32];
49 for (int i=0; i<10000; i++)
50 {
51 byte[] key = null;
52 switch (rand.Next(3))
53 {
54 case 0:
55 key = HashFunction.GetUniformKey();
56 break;
57 case 1:
58 key = HashFunction.GetTextKey();
59 break;
60 case 2:
61 key = HashFunction.GetSparseKey();
62 break;
63 }
64 uint hash = hf.ComputeHash(key);
65 for (int j=0; j<32; j++)
66 for (int k=0; k<32; k++)
67 {
68 if (((hash & (1U << j)) != 0) == ((hash & (1U << k)) != 0))
69 H[j, k]++;
70 else
71 H[j, k]--;
72 }
73 }
74
75 using (Bitmap bmp = new Bitmap(255, 255))
76 using (Graphics g = Graphics.FromImage(bmp))
77 {
78 g.DrawLine(Pens.Black, 63, 0, 63, 255);
79 g.DrawLine(Pens.Black, 127, 0, 127, 255);
80 g.DrawLine(Pens.Black, 191, 0, 191, 255);
81 g.DrawLine(Pens.Black, 0, 63, 255, 63);
82 g.DrawLine(Pens.Black, 0, 127, 255, 127);
83 g.DrawLine(Pens.Black, 0, 191, 255, 191);
84 for (int j=0; j<32; j++)
85 for (int k=0; k<32; k++)
86 {
87 Brush br;
88 if (H[j,k]<-233)
89 br = Brushes.Red;
90 else if (H[j,k]<-199)
91 br = Brushes.Orange;
92 else if (H[j,k]<199)
93 br = Brushes.LightGray;
94 else if (H[j,k]>233)
95 br = Brushes.GreenYellow;
96 else
97 br = Brushes.YellowGreen;
98 g.FillRectangle(br, 8*j + 1, 8*k + 1, 5, 5);
99 }
100 bmp.Save(hf.ToString() + "-bits.gif");
101 }
102 }
103
104 static int[,] matrix;
105
106 static void InitMatrix(int width)
107 {
108 matrix = new int[width, 32];
109 }
110
111 static void Tally(HashFunction hf, byte[] key)
112 {
113 uint h0 = hf.ComputeHash(key);
114 if (key.Length <= 6)
115 {
116 for (int i=0; i<key.Length; i++)
117 for (int j=0; j<8; j++)
118 {
119 key[i] ^= (byte) (1 << j);
120 uint h1 = hf.ComputeHash(key) ^ h0;
121 key[i] ^= (byte) (1 << j);
122 int x = i*8 + j;
123 for (int y=0; y<32; y++)
124 {
125 if ((h1 & 1) != 0)
126 matrix[x, y]++;
127 h1 >>= 1;
128 }
129 }
130 }
131 else
132 {
133 for (int j=0; j<8; j++)
134 {
135 key[0] ^= (byte) (1 << j);
136 uint h1 = hf.ComputeHash(key) ^ h0;
137 key[0] ^= (byte) (1 << j);
138 for (int y=0; y<32; y++)
139 {
140 if ((h1 & 1) != 0)
141 matrix[j, y]++;
142 h1 >>= 1;
143 }
144 key[key.Length - 1] ^= (byte) (1 << j);
145 h1 = hf.ComputeHash(key) ^ h0;
146 key[key.Length - 1] ^= (byte) (1 << j);
147 for (int y=0; y<32; y++)
148 {
149 if ((h1 & 1) != 0)
150 matrix[j + 8, y]++;
151 h1 >>= 1;
152 }
153 }
154 }
155 }
156
157 static void RenderMatrix(Graphics g, uint trials)
158 {
159 int sc = 8;
160 uint o3 = trials / 3;
161 uint t3 = trials * 2 / 3;
162 for (int x=0; x<matrix.GetLength(0); x++)
163 for (int y=0; y<matrix.GetLength(1); y++)
164 {
165 Brush br;
166 if (matrix[x, y] == 0 || matrix[x, y] == trials)
167 br = Brushes.Red;
168 else if (matrix[x, y] < o3 || matrix[x, y] > t3)
169 br = Brushes.Orange;
170 else
171 br = Brushes.Green;
172 g.FillRectangle(br, sc * (matrix.GetLength(1) - 1 - y) + 1, sc * x + 1, sc - 3, sc - 3);
173 }
174 }
175
176 static void AvalancheTest(HashFunction hf)
177 {
178 int sc = 8;
179
180 Console.WriteLine("\r\n{0}", hf);
181
182 Console.WriteLine("\r\nTwo-octet keys");
183 using (Bitmap bmp = new Bitmap(32 * sc - 1, 16 * sc - 1))
184 using (Graphics g = Graphics.FromImage(bmp))
185 {
186 g.DrawLine(Pens.Black, 8*sc-1, 0, 8*sc-1, 16*sc-1);
187 g.DrawLine(Pens.Black, 16*sc-1, 0, 16*sc-1, 16*sc-1);
188 g.DrawLine(Pens.Black, 24*sc-1, 0, 24*sc-1, 16*sc-1);
189 InitMatrix(16);
190 byte[] key = new byte[2];
191 for (int i=0; i<65536; i++)
192 {
193 key[0] = (byte) (i & 0xFF);
194 key[1] = (byte) (i >> 8);
195 Tally(hf, key);
196 }
197 RenderMatrix(g, 65536);
198 bmp.Save(hf.ToString() + "-2.gif");
199 }
200
201 RandomNumberGenerator rng = new RNGCryptoServiceProvider();
202 Console.WriteLine("Four-octet keys");
203 using (Bitmap bmp = new Bitmap(32 * sc - 1, 32 * sc - 1))
204 using (Graphics g = Graphics.FromImage(bmp))
205 {
206 g.DrawLine(Pens.Black, 8 * sc - 1, 0, 8 * sc - 1, 32 * sc - 1);
207 g.DrawLine(Pens.Black, 16 * sc - 1, 0, 16 * sc - 1, 32 * sc - 1);
208 g.DrawLine(Pens.Black, 24 * sc - 1, 0, 24 * sc - 1, 32 * sc - 1);
209 InitMatrix(32);
210 byte[] key = new byte[4];
211 uint trials = 32768;
212 for (int i = 0; i < trials; i++)
213 {
214 rng.GetBytes(key);
215 Tally(hf, key);
216 }
217 RenderMatrix(g, trials);
218 bmp.Save(hf.ToString() + "-4.gif");
219 }
220
221 Console.WriteLine("Five-octet keys");
222 using (Bitmap bmp = new Bitmap(32 * sc - 1, 40 * sc - 1))
223 using (Graphics g = Graphics.FromImage(bmp))
224 {
225 g.DrawLine(Pens.Black, 8 * sc - 1, 0, 8 * sc - 1, 40 * sc - 1);
226 g.DrawLine(Pens.Black, 16 * sc - 1, 0, 16 * sc - 1, 40 * sc - 1);
227 g.DrawLine(Pens.Black, 24 * sc - 1, 0, 24 * sc - 1, 40 * sc - 1);
228 InitMatrix(40);
229 byte[] key = new byte[5];
230 uint trials = 32768;
231 for (int i = 0; i < trials; i++)
232 {
233 rng.GetBytes(key);
234 Tally(hf, key);
235 }
236 RenderMatrix(g, trials);
237 bmp.Save(hf.ToString() + "-5.gif");
238 }
239
240 Console.WriteLine("Three-octet keys");
241 using (Bitmap bmp = new Bitmap(32 * sc - 1, 24 * sc - 1))
242 using (Graphics g = Graphics.FromImage(bmp))
243 {
244 g.DrawLine(Pens.Black, 8 * sc - 1, 0, 8 * sc - 1, 24 * sc - 1);
245 g.DrawLine(Pens.Black, 16 * sc - 1, 0, 16 * sc - 1, 24 * sc - 1);
246 g.DrawLine(Pens.Black, 24 * sc - 1, 0, 24 * sc - 1, 24 * sc - 1);
247 InitMatrix(40);
248 byte[] key = new byte[3];
249 uint trials = 32768;
250 for (int i = 0; i < trials; i++)
251 {
252 rng.GetBytes(key);
253 Tally(hf, key);
254 }
255 RenderMatrix(g, trials);
256 bmp.Save(hf.ToString() + "-3.gif");
257 }
258
259 rng = new RNGCryptoServiceProvider();
260 Console.WriteLine("256-octet keys");
261 using (Bitmap bmp = new Bitmap(32 * sc - 1, 16 * sc - 1))
262 using (Graphics g = Graphics.FromImage(bmp))
263 {
264 g.DrawLine(Pens.Black, 8*sc-1, 0, 8*sc-1, 16*sc-1);
265 g.DrawLine(Pens.Black, 16*sc-1, 0, 16*sc-1, 16*sc-1);
266 g.DrawLine(Pens.Black, 24*sc-1, 0, 24*sc-1, 16*sc-1);
267 InitMatrix(16);
268 byte[] key = new byte[256];
269 uint trials = 32768;
270 for (int i=0; i<trials; i++)
271 {
272 rng.GetBytes(key);
273 Tally(hf, key);
274 }
275 RenderMatrix(g, trials);
276 bmp.Save(hf.ToString() + "-256.gif");
277 }
278 }
279
280 static void BucketTest(HashFunction hf)
281 {
282 GetRandomKey[] keyfunc = {
283 new GetRandomKey(HashFunction.GetUniformKey),
284 new GetRandomKey(HashFunction.GetTextKey),
285 new GetRandomKey(HashFunction.GetSparseKey),
286 };
287
288 Console.WriteLine("\r\n{0}", hf);
289 Console.WriteLine("\r\n Uniform keys Text keys Sparse keys");
290 Console.WriteLine("\r\nBits Lower Upper Lower Upper Lower Upper");
291 for (int bits=1; bits<=16; bits++)
292 {
293 Console.Write("{0,2} ", bits);
294 foreach (GetRandomKey getKey in keyfunc)
295 {
296 Console.Write(" ");
297 uint mask = (1U << bits) - 1U;
298 int E = 100;
299 for (int lsb=0; lsb<32; lsb += 32-bits)
300 {
301 if (hf is FNV)
302 {
303 if (lsb == 0)
304 hf = new FNV(bits);
305 else
306 hf = new FNV();
307 }
308 int[] buckets = new int[1 << bits];
309 int n = E * buckets.Length;
310 for (int i=0; i<n; i++)
311 {
312 byte[] key = getKey();
313 uint hash = hf.ComputeHash(key);
314 uint bucket = (hash >> lsb) & mask;
315 buckets[bucket]++;
316 }
317 double X = 0.0;
318 double p;
319 for (int i=0; i<buckets.Length; i++)
320 {
321 double err = buckets[i] - E;
322 X += err * err / E;
323 p = buckets[i] / (double)n;
324 }
325 p = ChiSq(X, buckets.Length - 1);
326 Console.Write(" {0:0.000}", p);
327 }
328 }
329 Console.WriteLine();
330 }
331 }
332
333 static double ChiSq(double x, int n)
334 {
335 double q, t, p;
336 int k, a;
337
338 if (n == 1 && x > 1000)
339 return 0.0;
340
341 if (x > 1000 || n > 1000)
342 {
343 q = ChiSq((x - n) * (x - n) / (2 * n), 1) / 2;
344 if (x > n)
345 return q;
346 else
347 return 1 - q;
348 }
349
350 p = Math.Exp(-0.5 * x);
351 if ((n % 2) == 1)
352 {
353 p *= Math.Sqrt(2 * x / Math.PI);
354 }
355
356 k = n;
357 while (k >= 2)
358 {
359 p *= x / k;
360 k -= 2;
361 }
362
363 t = p;
364 q = -1;
365 a = n;
366 while (q != p)
367 {
368 a += 2;
369 t *= x /a;
370 q = p;
371 p += t;
372 }
373 if (p > 1)
374 p = 1;
375
376 return 1 - p;
377 }
378 }
379
380 public delegate byte[] GetRandomKey();
381
382 public abstract class HashFunction
383 {
384 static RandomNumberGenerator rng = new RNGCryptoServiceProvider();
385 static byte[] b = new byte[4];
386
387 public abstract uint ComputeHash(byte[] data);
388
389 private static int GetRandomLength()
390 {
391 rng.GetBytes(b);
392 uint s = BitConverter.ToUInt32(b, 0);
393 double x = 1 - s / (uint.MaxValue + 1.0);
394 return (int) Math.Floor(Math.Sqrt(-800.0 * Math.Log(x)));
395 }
396
397 public static byte[] GetUniformKey()
398 {
399 // with 8 bits/byte we need at least two octets
400 int length = GetRandomLength() + 2;
401 byte[] key = new byte[length];
402 rng.GetBytes(key);
403 return key;
404 }
405
406 public static byte[] GetTextKey()
407 {
408 // with 4.34 bits/byte we need at least 4 octets
409 int length = GetRandomLength() + 4;
410 byte[] key = new byte[length];
411 rng.GetBytes(key);
412 for (int i=0; i<length; i++)
413 key[i] = (byte) (65 + (key[i] * key[i] * 26) / 65026);
414 return key;
415 }
416
417 public static byte[] GetSparseKey()
418 {
419 // with 3 bits/byte we need at least 6 octets
420 int length = GetRandomLength() + 6;
421 byte[] key = new byte[length];
422 rng.GetBytes(key);
423 for (int i=0; i<length; i++)
424 key[i] = (byte)(1 << (key[i] & 7));
425 return key;
426 }
427 }
428
429 public class SimpleHash : HashFunction
430 {
431 public override uint ComputeHash(byte[] data)
432 {
433 uint hash = 1;
434 foreach (byte b in data)
435 hash = (hash + b) * 0x50003;
436 return hash;
437 }
438 }
439
440 public class FakeHash : HashFunction
441 {
442 RandomNumberGenerator rng = new RNGCryptoServiceProvider();
443 byte[] b = new byte[4];
444
445 public override uint ComputeHash(byte[] data)
446 {
447 rng.GetBytes(b);
448 return (uint) (b[0] + 256U * b[1] + 65536U * b[2] + 16777216U * b[3]);
449 }
450 }
451
452 public class FNV : HashFunction
453 {
454 int shift;
455 uint mask;
456
457 public FNV()
458 {
459 shift = 0;
460 mask = 0xFFFFFFFF;
461 }
462
463 public FNV(int bits)
464 {
465 shift = 32 - bits;
466 mask = (1U << shift) - 1U;
467 }
468
469 public override uint ComputeHash(byte[] data)
470 {
471 uint hash = 2166136261;
472 foreach (byte b in data)
473 hash = (hash * 16777619) ^ b;
474 if (shift == 0)
475 return hash;
476 else
477 return (hash ^ (hash >> shift)) & mask;
478 }
479 }
480
481 public class ModifiedFNV : HashFunction
482 {
483 public override uint ComputeHash(byte[] data)
484 {
485 const uint p = 16777619;
486 uint hash = 2166136261;
487 foreach (byte b in data)
488 hash = (hash ^ b) * p;
489 hash += hash << 13;
490 hash ^= hash >> 7;
491 hash += hash << 3;
492 hash ^= hash >> 17;
493 hash += hash << 5;
494 return hash;
495 }
496 }
497
498 public class Jenkins96 : HashFunction
499 {
500 uint a, b, c;
501
502 void Mix()
503 {
504 a -= b; a -= c; a ^= (c>>13);
505 b -= c; b -= a; b ^= (a<<8);
506 c -= a; c -= b; c ^= (b>>13);
507 a -= b; a -= c; a ^= (c>>12);
508 b -= c; b -= a; b ^= (a<<16);
509 c -= a; c -= b; c ^= (b>>5);
510 a -= b; a -= c; a ^= (c>>3);
511 b -= c; b -= a; b ^= (a<<10);
512 c -= a; c -= b; c ^= (b>>15);
513 }
514
515 public override uint ComputeHash(byte[] data)
516 {
517 int len = data.Length;
518 a = b = 0x9e3779b9;
519 c = 0;
520 int i = 0;
521 while (i + 12 <= len)
522 {
523 a += (uint)data[i++] |
524 ((uint)data[i++] << 8) |
525 ((uint)data[i++] << 16) |
526 ((uint)data[i++] << 24);
527 b += (uint)data[i++] |
528 ((uint)data[i++] << 8) |
529 ((uint)data[i++] << 16) |
530 ((uint)data[i++] << 24);
531 c += (uint)data[i++] |
532 ((uint)data[i++] << 8) |
533 ((uint)data[i++] << 16) |
534 ((uint)data[i++] << 24);
535 Mix();
536 }
537 c += (uint) len;
538 if (i < len)
539 a += data[i++];
540 if (i < len)
541 a += (uint)data[i++] << 8;
542 if (i < len)
543 a += (uint)data[i++] << 16;
544 if (i < len)
545 a += (uint)data[i++] << 24;
546 if (i < len)
547 b += (uint)data[i++];
548 if (i < len)
549 b += (uint)data[i++] << 8;
550 if (i < len)
551 b += (uint)data[i++] << 16;
552 if (i < len)
553 b += (uint)data[i++] << 24;
554 if (i < len)
555 c += (uint)data[i++] << 8;
556 if (i < len)
557 c += (uint)data[i++] << 16;
558 if (i < len)
559 c += (uint)data[i++] << 24;
560 Mix();
561 return c;
562 }
563 }
564
565 public class Jenkins32 : HashFunction
566 {
567 uint key;
568
569 void Mix()
570 {
571 key += (key << 12);
572 key ^= (key >> 22);
573 key += (key << 4);
574 key ^= (key >> 9);
575 key += (key << 10);
576 key ^= (key >> 2);
577 key += (key << 7);
578 key ^= (key >> 12);
579 }
580
581 public override uint ComputeHash(byte[] data)
582 {
583 key = 1;
584 foreach (byte b in data)
585 {
586 key += b;
587 Mix();
588 }
589 return key;
590 }
591 }
592
593 public class SHA1Hash : HashFunction
594 {
595 SHA1 sha = SHA1.Create();
596
597 public override uint ComputeHash(byte[] data)
598 {
599 byte[] hash = sha.ComputeHash(data);
600 return BitConverter.ToUInt32(hash, 0);
601 }
602 }
603
604
605 public class MD : HashFunction
606 {
607 MD5 md5 = MD5.Create();
608
609 public override uint ComputeHash(byte[] data)
610 {
611 byte[] hash = md5.ComputeHash(data);
612 return BitConverter.ToUInt32(hash, 0);
613 }
614 }
615
616 public class Cheater : HashFunction
617 {
618 public override uint ComputeHash(byte[] data)
619 {
620 byte[] b = new byte[4];
621 int i = 0;
622 while (i < 4 && i < data.Length)
623 {
624 b[i] ^= data[i];
625 i++;
626 }
627 while (i < 4)
628 {
629 b[i] ^= data[i % data.Length];
630 i++;
631 }
632 return BitConverter.ToUInt32(b, 0);
633 }
634 }
635
636 public class JenkinsOneAtATime : HashFunction
637 {
638 public override uint ComputeHash(byte[] data)
639 {
640 uint hash = 0;
641 foreach (byte b in data)
642 {
643 hash += b;
644 hash += (hash << 10); // 10
645 hash ^= (hash >> 6); // 6
646 }
647 hash += (hash << 3); // 3
648 hash ^= (hash >> 11); // 11
649 hash += (hash << 15); // 15
650 return hash;
651 }
652 }
653
654 public class FletcherChecksum : HashFunction
655 {
656 public override uint ComputeHash(byte[] data)
657 {
658 uint hash = 0;
659 uint sum = 0;
660 foreach (byte b in data)
661 {
662 sum += b;
663 hash += sum;
664 }
665 return hash;
666 }
667 }
668
669 public class CRC32 : HashFunction
670 {
671 uint[] tab;
672
673 public CRC32()
674 {
675 Init(0x04c11db7);
676 }
677
678 public CRC32(uint poly)
679 {
680 Init(poly);
681 }
682
683 void Init(uint poly)
684 {
685 tab = new uint[256];
686 for (uint i=0; i<256; i++)
687 {
688 uint t = i;
689 for (int j=0; j<8; j++)
690 if ((t & 1) == 0)
691 t >>= 1;
692 else
693 t = (t >> 1) ^ poly;
694 tab[i] = t;
695 }
696 }
697
698 public override uint ComputeHash(byte[] data)
699 {
700 uint hash = 0xFFFFFFFF;
701 foreach (byte b in data)
702 hash = (hash << 8) ^ tab[b ^ (hash >> 24)];
703 return ~hash;
704 }
705 }
706
707 public class SBoxHash : HashFunction
708 {
709 uint[] sbox = new uint[] {
710 0xF53E1837, 0x5F14C86B, 0x9EE3964C, 0xFA796D53,
711 0x32223FC3, 0x4D82BC98, 0xA0C7FA62, 0x63E2C982,
712 0x24994A5B, 0x1ECE7BEE, 0x292B38EF, 0xD5CD4E56,
713 0x514F4303, 0x7BE12B83, 0x7192F195, 0x82DC7300,
714 0x084380B4, 0x480B55D3, 0x5F430471, 0x13F75991,
715 0x3F9CF22C, 0x2FE0907A, 0xFD8E1E69, 0x7B1D5DE8,
716 0xD575A85C, 0xAD01C50A, 0x7EE00737, 0x3CE981E8,
717 0x0E447EFA, 0x23089DD6, 0xB59F149F, 0x13600EC7,
718 0xE802C8E6, 0x670921E4, 0x7207EFF0, 0xE74761B0,
719 0x69035234, 0xBFA40F19, 0xF63651A0, 0x29E64C26,
720 0x1F98CCA7, 0xD957007E, 0xE71DDC75, 0x3E729595,
721 0x7580B7CC, 0xD7FAF60B, 0x92484323, 0xA44113EB,
722 0xE4CBDE08, 0x346827C9, 0x3CF32AFA, 0x0B29BCF1,
723 0x6E29F7DF, 0xB01E71CB, 0x3BFBC0D1, 0x62EDC5B8,
724 0xB7DE789A, 0xA4748EC9, 0xE17A4C4F, 0x67E5BD03,
725 0xF3B33D1A, 0x97D8D3E9, 0x09121BC0, 0x347B2D2C,
726 0x79A1913C, 0x504172DE, 0x7F1F8483, 0x13AC3CF6,
727 0x7A2094DB, 0xC778FA12, 0xADF7469F, 0x21786B7B,
728 0x71A445D0, 0xA8896C1B, 0x656F62FB, 0x83A059B3,
729 0x972DFE6E, 0x4122000C, 0x97D9DA19, 0x17D5947B,
730 0xB1AFFD0C, 0x6EF83B97, 0xAF7F780B, 0x4613138A,
731 0x7C3E73A6, 0xCF15E03D, 0x41576322, 0x672DF292,
732 0xB658588D, 0x33EBEFA9, 0x938CBF06, 0x06B67381,
733 0x07F192C6, 0x2BDA5855, 0x348EE0E8, 0x19DBB6E3,
734 0x3222184B, 0xB69D5DBA, 0x7E760B88, 0xAF4D8154,
735 0x007A51AD, 0x35112500, 0xC9CD2D7D, 0x4F4FB761,
736 0x694772E3, 0x694C8351, 0x4A7E3AF5, 0x67D65CE1,
737 0x9287DE92, 0x2518DB3C, 0x8CB4EC06, 0xD154D38F,
738 0xE19A26BB, 0x295EE439, 0xC50A1104, 0x2153C6A7,
739 0x82366656, 0x0713BC2F, 0x6462215A, 0x21D9BFCE,
740 0xBA8EACE6, 0xAE2DF4C1, 0x2A8D5E80, 0x3F7E52D1,
741 0x29359399, 0xFEA1D19C, 0x18879313, 0x455AFA81,
742 0xFADFE838, 0x62609838, 0xD1028839, 0x0736E92F,
743 0x3BCA22A3, 0x1485B08A, 0x2DA7900B, 0x852C156D,
744 0xE8F24803, 0x00078472, 0x13F0D332, 0x2ACFD0CF,
745 0x5F747F5C, 0x87BB1E2F, 0xA7EFCB63, 0x23F432F0,
746 0xE6CE7C5C, 0x1F954EF6, 0xB609C91B, 0x3B4571BF,
747 0xEED17DC0, 0xE556CDA0, 0xA7846A8D, 0xFF105F94,
748 0x52B7CCDE, 0x0E33E801, 0x664455EA, 0xF2C70414,
749 0x73E7B486, 0x8F830661, 0x8B59E826, 0xBB8AEDCA,
750 0xF3D70AB9, 0xD739F2B9, 0x4A04C34A, 0x88D0F089,
751 0xE02191A2, 0xD89D9C78, 0x192C2749, 0xFC43A78F,
752 0x0AAC88CB, 0x9438D42D, 0x9E280F7A, 0x36063802,
753 0x38E8D018, 0x1C42A9CB, 0x92AAFF6C, 0xA24820C5,
754 0x007F077F, 0xCE5BC543, 0x69668D58, 0x10D6FF74,
755 0xBE00F621, 0x21300BBE, 0x2E9E8F46, 0x5ACEA629,
756 0xFA1F86C7, 0x52F206B8, 0x3EDF1A75, 0x6DA8D843,
757 0xCF719928, 0x73E3891F, 0xB4B95DD6, 0xB2A42D27,
758 0xEDA20BBF, 0x1A58DBDF, 0xA449AD03, 0x6DDEF22B,
759 0x900531E6, 0x3D3BFF35, 0x5B24ABA2, 0x472B3E4C,
760 0x387F2D75, 0x4D8DBA36, 0x71CB5641, 0xE3473F3F,
761 0xF6CD4B7F, 0xBF7D1428, 0x344B64D0, 0xC5CDFCB6,
762 0xFE2E0182, 0x2C37A673, 0xDE4EB7A3, 0x63FDC933,
763 0x01DC4063, 0x611F3571, 0xD167BFAF, 0x4496596F,
764 0x3DEE0689, 0xD8704910, 0x7052A114, 0x068C9EC5,
765 0x75D0E766, 0x4D54CC20, 0xB44ECDE2, 0x4ABC653E,
766 0x2C550A21, 0x1A52C0DB, 0xCFED03D0, 0x119BAFE2,
767 0x876A6133, 0xBC232088, 0x435BA1B2, 0xAE99BBFA,
768 0xBB4F08E4, 0xA62B5F49, 0x1DA4B695, 0x336B84DE,
769 0xDC813D31, 0x00C134FB, 0x397A98E6, 0x151F0E64,
770 0xD9EB3E69, 0xD3C7DF60, 0xD2F2C336, 0x2DDD067B,
771 0xBD122835, 0xB0B3BD3A, 0xB0D54E46, 0x8641F1E4,
772 0xA0B38F96, 0x51D39199, 0x37A6AD75, 0xDF84EE41,
773 0x3C034CBA, 0xACDA62FC, 0x11923B8B, 0x45EF170A,
774 };
775
776 public override uint ComputeHash(byte[] data)
777 {
778 uint hash = 0;
779 foreach (byte b in data)
780 {
781 hash ^= sbox[b];
782 hash *= 3;
783 }
784 return hash;
785 }
786 }
787 //
788 //
789 //$assemblies = (
790 // #"System",
791 // #"System.Security.Cryptography",
792 // "System.Drawing"
793 //)
794 //Add-Type -ReferencedAssemblies $assemblies -TypeDefinition $cs -Language CSharp
795 //[ConsoleApp]::Main("")
最後のコメントアウト部分は元の「PowerShell スクリプト」にあった部分をメモのために残しただけ。アッセンブリの関係でハマるかもしらん、と警戒したので。
ただこの例は何の変哲もなかった:
1 [me@host: ~]$ csc -nologo -t:exe ConsoleApp.cs
すんなりコンパイル出来てしまった。実行も問題なし。
というわけで今回のこれは「ライブラリ」(としてのビルド?)じゃあないので、「.NET for Python から使おう」まで話は至らないんだけれど、一応「以降の実験を始められるな、これで」てことで本日のところは一応満足しとく。実行ファイルを作るより多少は難易度は上がるではあろうけれど、多分シンプルなものなら大したことないと思ってる。C# 開発経験も一応あたし、短い期間ではあったけどあるので。確かほっといても「ライブラリ」は素直に「.NET を冠する何者からでも使える君」になってた記憶はある。(対して VC++ CLR はこれほど簡単じゃない。あっちは「あれこれ混在」ならではの「柔軟性と複雑怪奇さ」があるので。)