内定式が近づいて来た

来年度からは紀尾井町のクソデカビルで戦うんだな、と思うと不安でいっぱいです。

学部新卒で年収をあの会社であげるのは結構難しいと思うので、そういう部分を覆せるくらいのやっていきができると最高だなと思っています。

まあそもそもそこそこの金がもらえて技術で遊ぶ余裕があって、使える技術が増やせればいいなと思っているだけなので不安もクソもとりあえず理不尽な部署とかに配属されないで欲しいくらいしかないんですが。

ブログで内定出た話は多少あったが、結局どこにするとかは書いてなかったのですが、目黒のドリ社と表参道の?社と紀尾井町のY社の内定をもらって最終的にYにすることになりました。

そこそこSNSでの発言に問題がある自覚もあるし、社会人になるにあたってその辺りをドデカ企業でシュピッとできると良さそうだなと思っていますが、御社の人間で邪悪なフォロワーがいるので不安です。

絶対に生き残って年収無限にあげてえ…

メッセージを特定個人に盗聴される恐れがある際の現実的な対策手法を考える

近況ですが、AliceとBobがメッセージをやりとりしている内容をAliceの妹Eve*1がAliceが寝ている間に端末の指紋認証を突破し盗み見てスクリーンショットを撮りAliceに直接送りつける嫌がらせをしていることが判明しました。*2 この状況のとき、各人が行える現実的なメッセージの難読化、あるいは暗号化の手法を考えたい。

私は研究をしていないと過去言われているのできっと研究をしていないのですが、配属された研究室の中には暗号理論に関わるものがいたり、私は符号理論に関わっていたりするので、そのあたりの知識を利用して考察していく。

共通鍵暗号を用いる

共通鍵暗号を用いればメッセージを比較的簡単に暗号化、あるいは復号化できる。

文字列を符号なし8ビットのバッファーに変換し、鍵文字列を用いて何らかの計算を適用しそれを再度文字列に戻すなどの方法が妥当な手法だと思われる。

しかし今回の場合は端末のほぼフルアクセスを得られるため復号化ツールもEveに利用されてしまうケースが想定できる。また、そもそもの共通鍵自体がAliceの端末から漏洩してしまう可能性が高いためあまり綺麗な手法ではない。

公開鍵暗号を用いる

公開鍵暗号を用いる場合送信メッセージの暗号化の鍵と受信メッセージの復号化の鍵の利用が想定できる。

公開鍵暗号とは言いつつもそもそも鍵自体は公開しておく必要はなく、それぞれの鍵に対応する復号鍵を計算することはほぼ不可能なので各々秘密鍵と公開鍵を所持しているだけなのでメッセージの全てがEveに復号化されるケースはなくなる。

しかしEveの目的は嫌がらせなので、この手法を用いても片側のメッセージは盗み出されてしまうためあまり効果がないという欠点が残ってしまう。

比較的単純な符号化を用いる

ハフマン符号化のように、ハフマンテーブルさえわかれば符号を復号出来るような符号化を考える。

この場合、符号は語頭符号であれば何でもよく、情報ビットたる元メッセージを符号化するルール自体は各メッセージごとに変更できるため鍵が盗まれたらメッセージが複合できるという様なパターンを避けることができる。

また、今回のケースでは送信した情報が誤って受信されるケースを想定しなくて良い為、符号化の際には符号語同士の距離*3を考慮する必要がないため、符号化のバリエーションはおそらく可算無限個程度あると想定できる。

複数の符号化を用いて難読化をすることで、正しい復号化手法をそれぞれにわからない形で伝えることができればほぼメッセージの盗聴は防げるはずである。

しかし現実的にそんな面倒なことをしていたらメッセージの伝送効率が悪すぎる為とてもじゃないが採用するのは難しそうだ。

Eveをなんとかする

これはソーシャルハックなんですが、Eveを社会的に破壊できれば問題ないというのがある。

グッと生命を絶たせたりだとか、一般社会から隔絶するとか、ブタ箱にぶち込むとか方法は様々だが、それをなんとかしてやろうと思うと割に合わないコストがかかったりするので現実的ではない。

これが実行できればかなり心の平穏が保たれるのだが、AliceがEveの親族であるので非常に面倒そうである。

人類を滅ぼす

人一人の手では不可能だが人類が滅びればメッセージの伝達そのものが不要になるので問題が消える。

第三次世界大戦…ッ!頼む!!!!!!!!!!

*1:よくある暗号理論の文脈ではそんな設定は無い

*2:悪意は無いらしいとの弁明はあったがそもそも不正アクセス禁止法に抵触します

*3:距離関数の意味で

ツイートにぶら下がってるリプライのユーザーを取得してブロックリストをエクスポートするやつを作った

これ

リポジトリ github.com

やってること

渡されたURLをNode.jsでGETしてスクレイピングしてユーザーを取得して、ガッとJSONを返すAPIをサーバ側 (https://mysticdoll.com/tools/tweet/tweetThread) で用意する

あとはReactでフロントエンドを設計。おしまい。

ファイルをダウンロードするところはObject.createObjectURLであれこれすればできる。詳しくはコード読むかなんか質問して。

任意の場所からAPI叩けたほうが良いかなと思ってついでにnginxとletsencriptをいじってmysticdoll.comにHTTPSを通しました。

こちらからは以上です。

ES6 class syntaxによって生成されたprototype上のunenumerableなメンバを列挙したかった…

class User {
  constructor(name, screenName, userId) {
    this.name = name;
    this.screenName = screenName;
    this.userId = userId;
  }
  get userPage() {
    return `https://twitter.com/${this.screenName}`;
  }
}

によって作られたUserインスタンスの配列をJSON.stringifyしてuserPageも含めてJSON化したい。

これは単一のオブジェクトに対してJSON.stringifyする場合と同値なので、それを考えると

let descriptor = Object.getOwnPropertyDescriptor(user, "userPage");
descriptor.enumerable = true;
Object.defineProperty(user, "userPage", descriptor);
JSON.stringify(user);

とすればいいかなと思うんですが、これではダメ。そもそもprototypeメンバの話なので違うのかなと思い

let descriptor = Object.getOwnPropertyDescriptor(User.prototype, "userPage");
descriptor.enumerable = true;
Object.defineProperty(User.prototype, "userPage", descriptor);
JSON.stringify(user);

としてもダメ、関係ないけど

user[Symbol.unscopables] = { userPage: false };
User.prototype[Symbol.unscopables] = { userPage: false };

でもダメ。当然JSON.stringifyで出来ないのでObject(user)してもダメ。

prototypeメンバからも列挙不可能なのでObject.keysとかでも拾えないので

  toObject() {
    return [...Object.keys(this), ...Reflect.ownKeys(this.constructor.prototype)].filter(key => key !== "constructor").reduce((obj, key) => {obj[key] = this[key]; return obj}, {});
  }

みたいな関数を生やすしかないっぽい気がしてきた。

これだったら受け側で新たにプロパティ生やしたほうが楽だなあとなり、厳しい。

一々定義時にプロパティを書かなくていいからgetter書いてたんだが、そういうわけにもいかないっぽい

Fibonacci数列

メモ化再帰とかの話読んでたらちょっと思い出したので書く。

let fib = n => n === 0 ? 0 : (n === 1 ? 1 : (n > 1 ? fib(n - 1) + fib(n - 2) : void(0)));

みたいなのを書くと、 {\displaystyle \mathcal{O} ({\alpha}^n)} ( {\displaystyle \alpha = \frac{\sqrt{5} + 1}{2}}) の計算量になるはず(ほんまか?)

これを { \displaystyle \mathcal{O} (n)}まで下げたい

まあ、こうする

let fib_seq = (n) => {
  if(n === 0) return [0];
  if(n === 1) return [1, 0];
  if(n > 1) {
    let seq = fib_seq(n - 1);
    return [seq[0] + seq[1], ...seq];
  }
};

let fib = n => fib_seq(n)[0];

fib_seqn番目までの数列を取得するやつなんですけど、やってることってn - 1番目までの配列をとってきてその添字01を足して配列に積むだけなので、たぶん {\displaystyle \mathcal{O} (n)}で済むはず。その一番上を拾うといい感じになる。

このやり方は去年大学の講義でPrologで実装するやつを見たんだけど、忘れそうだったから一応書いておいた。

まあ普通に漸化式解いて一般項求めて誤差を丸めれば  {\displaystyle \mathcal{O} (1) }だが…*1

*1:調べたら行列とか使って頑張ると  {\displaystyle \mathcal{O} (n \log n)}まで下がるらしい

単位が出ていた

単位が出ていたので卒研と余剰2単位クリアで大学全クリっぽい、幸せのあり方、心、社会への不安、無理

無理なので人間が唐突に大量に破壊されて欲しくなってきた

幸せってなんや、俺だってなあ、頭使ってなさそうな楽しそうな人間になりたかった、今からはなりたくない

東方永夜抄のスペルプラクティスでインペリシャブル・シューティングを繰り返しやっていた頃が一番幸せだった、あの時間を永遠にくれ、藤原妹紅さんの弾幕を、たのむ

後期余剰単位として何を取るか考えていない、計算機科学っぽい単位が少なすぎる、何故俺は数学系へ、数値計算の講義で降ってくるあらゆる処理をメイン関数に詰め込んだお弁当箱、よくわからないまま過ぎていった解析学、何もかもがわからない、おれは、なぜ…

波括弧レスJavaScript理論

某所で初心者のJavaScriptコードを見ると本当に酷くてつらい気持ちになります。 波括弧がちゃんと閉じていないみたいなしょうもない上にやたら愚直に書かれていて一切の可読性がないコードを読むのは辛い。

波括弧レスJavaScript

絶対に解決はしないけど、波括弧なしでJavaScriptを書けば全てが解決しますねという気持ちになりました。

for(let i = 1; i <= 100; ++i) {
  if(i % 3 !== 0 && i % 5 !== 0) {
    console.log(i);
  } else if(i % 3 === 0 && i % 5 === 0) {
    console.log("FIZZBUZZ");
  } else if(i % 3 === 0) {
    console.log("FIZZ");
  } else {
    console.log("BUZZ");
  }
}

みたいなクソ雑なFIZZBUZZがまあありますよと、これを

Array(100).fill().map((_, i) => i + 1).forEach(i => i % 15 === 0 ? console.log("FIZZBUZZ") : (i % 3 === 0 ? console.log("FIZZ") : (i % 5 === 0 ? console.log("BUZZ") : console.log(i))))

こうするみたいな話ですね。

JavaScriptで波括弧使う例

if

三項演算子を使え

switch

三項演算子でがんばれ

while

再帰関数で頑張れ

for

Array(count).fill().map((_, i) => i).forEach(i => anyfunc)みたいな感じで一定回数のループはできるのでそれでコレクションを回すのは言わずもがな

Object

もしくはnew Objectしてそこにプロパティつっこみまくれ。ArrayにつっこみまくってJSON.stringifyが必要みたいなときとか純粋にObjectが必要になったらObject.entriesとか使ってがんばれ

関数

ひたすら辛い。

基本的には単一の値を返すArrow Functionを使う。 let hoge = (arg) => arg + 1; みたいな感じ

複数の処理をさせたいときはカンマ演算子で頑張る。こいつは() => hoge, fugaみたいなことをしたらfugaが帰ってくる。つまりカンマを挟んで次の値が返却値になる。だから let a = 1,2,3とかやると a3になる。 この手法はUglifyJSとかで変換後のJSとかを見るとよく使われている。割と便利。 しかし変数の宣言は返却値のみのArrow Functionないで出来なかったりするのでスコープについては諦めるしかない(かもしれない)。

代入文は普通に代入した値を返却するのでカンマ演算子の後側で使えるし、そのへんをうまくやったりする。

また、割と&&||演算子は便利。

前者は左辺式の評価値がtrueにキャストできる場合は右辺値を評価して返し、そうでない場合は左辺式の評価値を返す。

後者は左辺式がtrueキャストできればそのまま左辺式の評価値を、そうでなければ右辺式の評価値を返す。これもよくUglifyされたやつでみる。

割となんとかなると思う。この辺で頑張って処理したり、ローカル変数をひたすら先に用意しておいて代入文とカンマ演算子と論理演算子でがんばったりするだけでもいいし。

さらに言えばチューリングマシンで計算可能な関数は原始帰納的なので、初期関数三種の合成や原始帰納を有限回繰り返すだけで作れます。 初期関数は

{ \displaystyle
Z (x) = 0
}

 { \displaystyle
S (x) = x + 1
}

 { \displaystyle
U ^i _n (x_1, \cdots , x_n) = x_i
}

の3つで、JavaScriptで書くならそれぞれ

let Z = x => 0;
let S = x => x + 1;
let U = (i, ...args) => args[i];

として書ける。3つ目のやつに関しては割と自由だし、 {\displaystyle S }に関しても逆関数が簡単に書けるし楽。

合成と原始帰納については説明を割愛するけど、これらも普通に平易にJavaScriptで書くことが出来るわけで、まあつまりチューリングマシンで計算可能なレベルの関数であれば、Arrow Functionだけで頑張れるし、波括弧はいらない。

雑に思いついたまま書いただけなので今回はあまり詳しくは書かないけどどこかで詳しく書く機会があればやるかも