Python for .NET の微続き。が、未整理のままの実験「ことはじめ」だけ書くので読まなくてよろしい

今すぐに何か本格的なことをするつもりで始めたわけではないけれど、ずっと気になってたヤツ。

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 のこの記事 を読んで、「ん?」と思って確認したら、ちゃんと入っておった…、そうかそうだったのか。(とかいいつつインストール時に自分で選んでたりするのかもしらんけど、だとしてもちゃんと「無償で」入手できていることには違いはない。):

「オレ」なので例によって MSYS から
 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# コードを一応再掲:

ConsoleApp.cs
  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 はこれほど簡単じゃない。あっちは「あれこれ混在」ならではの「柔軟性と複雑怪奇さ」があるので。)