読者です 読者をやめる 読者になる 読者になる

i remember nothing

文章の練習も兼ねています

最近買ってよかったもの(書籍除く)

  • ほぼ日ウィークリー

このくらいの大きさが持ち歩くのにちょうどいい気がする。

考え事をするときにとにかく書きなぐる用に最適。万年筆が裏写りしないし、普通のノートと違い無理なく開きっぱなしができる。

  • 無印の脇に縫い目のないパジャマ

寝巻きにこだわりはなかったのだが一度着るとやめられなくなる。

これにアロマオイル垂らしてから寝ると心地良い。

携帯機と据え置き機をうまく融合してる。ソフトはゼルダとぷよテトを買った。 試射会面白かった。

かっこいい。なんか運動量とか教えてくれる。

傘より小さいサイズにたたんで持ち歩ける。傘で片手が塞がるのが嫌いなのでよい。

  • ニットキャップ

寝癖があってもかぶって家出れば職場に着く頃には寝癖直ってる。

  • Alfred PowerPack

カスタム機能が鬼便利。dash と連携するとできるエンジニア感でる。

  • フード

デスクで集中したい時や少し冷える時に便利。あとフードかぶってパソコンかたかたしてるとできるエンジニア感でる。

  • fidget cube

https://www.rakunew.com/items/75932

ポッケに入れて電車とかでカチカチすると落ち着く。できるエンジニア感でる。

  • 左右分離式キーボード

キー入力のために腕を狭める必要がなくなり助かる。できるエンジニア感でる。

3/23

インターネットをやり始めて10年以上、

プログラムを書き始めて6年ほど経つが、未だに世界中でネットワーク通信が行われており、ブラウザでウェブサイトが動いているということに実感がわかない。

プログラミングElixir独習 1-9章

第1章

Elixirは普遍的な状態を用いた関数プログラミングと並行性(concurrent)へのactorベースのアプローチをモダンな文法にラップしたもの

1.1

  • プログラミングではデータを隠蔽したいのではなく、変換したい。
  • 私たちは仕事を済ませたいのであって、維持したいのではない。

パイプラインによる変換の組み合わせ

コマンドパイプラインは並列に実行できる。

 grep Elixir *.pml | wc -l

上の例だと、 wcgrep は並列に実行される。grep により出力された先から wc に渡され処理される。

Elixirで書かれた以下の pmap はこのような並列性を示唆するものである。

defmodule Parallel do
  def pmap(collection, func) do
    collection
      |> Enum.map(&(Task.async(fn -> func. (&1) end)))
      |> Enum.map(&Task.await/1)
  end
end

result = Parallel.pmap 1..1000, &(&1, * &1)

これは1000個のバックグラウンドプロセスを起動する。

関数 = データ変換器

Elixirでの問題の解き方はUnix シェルと同様であり、コマンドライン関数の代わりにElixirの関数がある。 関数を並列に走らせたり、互いにmessage passingをさせたりできる。 プログラミング一般の考え方では、関数は入力を出力に変換させるものである。 オブジェクト指向の考え方に慣れていると大変かもしれませんが、関数型を楽しくやっていこう! みたいな良い話

第2章

代入

iex > a = 1
1
iex > 1 = a
1
iex > 2 = a
 //=> MatchError

Elixirの比較は代入というより代数的な比較に近い。

リストのマッチ

  • 練習問題 a = 1, 2, 3 [a,b] = [1, 2, 3] はマッチされない。なぜなら、値の中に対応する 単一の 項がないからだ。

アンダースコア

iex> [1, 2, _] = [1,2,3]

ワイルドカード的に使える。

pin operator

iex> a = 1
1
iex> a = 2
2
iex>^a = 1
#\> MatchError

すでにある変数の値を使いたいときはキャレット(^)演算子を用いる。

Elixirではすべてのデータが不変である。いわゆるストリクトな関数型とここらへんは近い。

defmodule Chop do
  def guess(actual, a..b) do
    midp = a + div(b-a, 2)
    IO.puts("Is it #{midp}")
    compare(actual, midp, a..b)
  end

  defp compare(actual, midpoint, _.._) when actual == midpoint do
    IO.puts("It is #{actual}")
  end

  defp compare(actual, midpoint, a.._) when actual < midpoint do
    guess(actual, a..midpoint)
  end

  defp compare(actual, midpoint, _..b) when actual >= midpoint do
    guess(actual, midpoint..b)
  end

end

パイプ演算子

filling = DB.find_customers
          |> Orders.for_customers
          |> sales_tax(2015)
          |> prepare_filling

|> 演算子は左の項の式の結果をとって右の関数の第一パラメータとして渡すことができる。

val |> f(a,b) === f(val, a, b) となる。

モジュール

定義するものにネームスペースを提供する。

defmodule Mix.Tasks.Doctest do
  def run do
  end
end

Elixirは単純に外側のモジュールの名前を内側のモジュールの名前にドットを挟んで定義している

モジュールのディレクティブ

  • import ディレクティブ

モジュールの関数やマクロをカレントスコープに持ってくる。

defmodule Example do
  def func1 do
    List.flatten [1, [2,3], 4]
  end
  def func2 do
    import List, only: [flatten: 1]
    flatten [5,[6,7],8]
  end
end

import List, only: [flatten:1, duplicate:2]

  • alias ディレクレィブ
defmodule Example do

  def compile do
    alias My.Other.Module.Parser, as: Parser
    source
      |> Parser.parse
  end

end

モジュール名のエイリアスを作るディレクティブ。

  • require ディレクティブ

モジュールで定義したマクロを使う時にそのモジュールをrequireするとマクロ定義が有効になっていることが保証されるらしい。*1

モジュール属性

defmodule Example do
  @author "Dave Thomas"
  def get_author do
    @author
  end
end

メタデータの属性に@name valueで値を与えることができる。 同じ属性に何度も値を与えることもできる。定数のようなもの

Elixir, Erlang, アトム

Elixirのモジュールの名前はアトムに過ぎない。 IO などの大文字から始まる名前を書いた時Elixir.IOという名前に内部で変換される。

iex(IEX-8684@gergate)1> is_atom IO
true
iex(IEX-8684@gergate)2> to_string IO
"Elixir.IO"
iex(IEX-8684@gergate)3> "Elixir.IO" === IO
false
iex(IEX-8684@gergate)4> :"Elixir.IO" === IO
true

IO.puts:"Elixir.IO".puts というふうに呼び出すこともできる。

Erlangライブラリの呼び出し

iex(IEX-8684@gergate)5> :io.format("The number is ~3.1f~n", [5.678])
The number is 5.7
:ok

小文字のアトムとして呼び出す。

第7章 リストと再帰

このへんはHaskellAgdaで慣れているのでさらっと

iex(IEX-8684@gergate)13> [head | tail] = [1,2,3]
[1, 2, 3]
iex(IEX-8684@gergate)14> head
1
iex(IEX-8684@gergate)15> tail
[2, 3]
defmodule MyList do
  def len([]), do: 0
  def len([_head | tail]), do: 1 + len(tail)
end
iex(IEX-8684@gergate)17> MyList.len([1,2,3])
3
iex(IEX-8684@gergate)18> MyList.len([])
0

うんうんNilとConsだね

defmodule MyList do
  def len([]), do: 0
  def len([_head | tail]), do: 1 + len(tail)

  def square([]), do:[]
  def square([head | tail]), do: [head*head | square(tail)]
end

末尾再帰

defmodule MyList do
  def len([]), do: 0
  def len([_head | tail]), do: 1 + len(tail)

  def square([]), do:[]
  def square([head | tail]), do: [head*head | square(tail)]

  def map([], _func), do: []
  def map([head | tail], func) do: [func.(head) | map(tail, func)]
end
iex(IEX-8684@gergate)22> MyList.map [1,2,3,4], fn (n) -> n*n end
[1, 4, 9, 16]

List.mapだね

defmodule MyList do
  def len([]), do: 0
  def len([_head | tail]), do: 1 + len(tail)

  def square([]), do: []
  def square([head | tail]), do: [head*head | square(tail)]

  def map([], _func), do: []
  def map([head | tail], func), do: [func.(head) | map(tail, func)]

  def sum(list), do: _sum(list, 0)

  # private function
  defp _sum([], total), do: total
  defp _sum([head | tail], total), do: _sum([tail], head + total)

end

ヘルパー関数を使って再帰的にsumを実装

defmodule MyList do
  def len([]), do: 0
  def len([_head | tail]), do: 1 + len(tail)

  def square([]), do: []
  def square([head | tail]), do: [head*head | square(tail)]

  def map([], _func), do: []
  def map([head | tail], func), do: [func.(head) | map(tail, func)]

  def sum(list), do: _sum(list, 0)

  # private function
  defp _sum([], total), do: total
  defp _sum([head | tail], total), do: _sum([tail], head + total)

  def reduce([], value, _) do
    value
  end
  def reduce([head | tail], value, func) do
    reduce(tail, func.(head, value), func)
  end
end

foldLeft!

  • 練習問題

def mapsum(list, func) do
  reduce(map(list, func), 0, (&(&1 + &2)))
end
def max([]), do: 0
def max([head | tail]),do: reduce([head | tail], head, &(compare(&1, &2)))

def compare(p1, p2) when p1 > p2, do: p1
def compare(p1, p2) when p1 <= p2, do: p2
def caesar(list, n) do
  map(list, fn x -> _decode_char(x, n) end)
end

defp _decode_char(char, num) when char + num > 122 do
  char + num - 26
end
defp _decode_char(char, num) when char + num < 122 do
    char + num
end
def span(from, to) when from < to do
  [from | span(from + 1, to)]
end
def span(from, to) when from == to, do: [to]

第8章 マップ、キーワードリスト、セット、構造体

map vs keyword list

  • パターンマッチを行いたい時はmap
  • 同じキーを持つエントリが複数現れる時はkeyword
  • 要素の順番を保証しないといけない時はkeyword
  • それ以外はmap

キーワードリスト

defmodule Canvas do
  @defaults [fg: "black", bg: "white", font: "Merriweather"]

  def draw_text(text, options \\ []) do
    options = Keyword.merge(@defaults, options)
    IO.puts "Drawing text #{inspect(text)}"
    IO.puts "Foreground : #{options[:fg]}"
    IO.puts "Background : #{Keyword.get(options, :bg)}"
    IO.puts "Font : #{Keyword.get(options,:font)}"
    IO.puts "Style : #{inspect Keyword.get_values(options, :style)}"
  end
end

マップ

iex(IEX-8684@gergate)67> map = %{name: "Dave", likes: "Programming", where: "Daras"}
%{likes: "Programming", name: "Dave", where: "Daras"}
iex(IEX-8684@gergate)68> Map.keys map
[:likes, :name, :where]
iex(IEX-8684@gergate)69> Map.values map
["Programming", "Dave", "Daras"]
iex(IEX-8684@gergate)70> map[:name]
"Dave"
iex(IEX-8684@gergate)71> map1 = Map.d
delete/2    drop/2
iex(IEX-8684@gergate)71> map1 = Map.drop map, [:where, :likes]
%{name: "Dave"}
iex(IEX-8684@gergate)72> map1 = Map.p map, [:where, :likes]
pop/2             pop/3             pop_lazy/3        put/3
put_new/3         put_new_lazy/3
iex(IEX-8684@gergate)72> map1 = Map.put map, :also_likes, "Ruby"
%{also_likes: "Ruby", likes: "Programming", name: "Dave", where: "Daras"}
iex(IEX-8684@gergate)73> Map.has_key? map1, :where
true
iex(IEX-8684@gergate)74> {value, updated_map} = Map.pop map1, :also_likes
{"Ruby", %{likes: "Programming", name: "Dave", where: "Daras"}}

MapのAPIでいろいろできる

パターンマッチ

iex(IEX-8684@gergate)75> person = %{name: "Dave", height: 1.88}
%{height: 1.88, name: "Dave"}
iex(IEX-8684@gergate)76> %{name: a_name} = person
%{height: 1.88, name: "Dave"}
iex(IEX-8684@gergate)77> a_name
"Dave"
iex(IEX-8684@gergate)78> %{name: _, height: _} = person
%{height: 1.88, name: "Dave"}
iex(IEX-8684@gergate)79> %{name: "Dave"} = person
%{height: 1.88, name: "Dave"}
iex(IEX-8684@gergate)80> %{name: _, weight: _} = person
** (MatchError) no match of right hand side value: %{height: 1.88, name: "Dave"}

キーや値に対してパターンマッチをすることができる。

people = [
  %{ name: "Grumpy", height: 1.24 },
  %{ name: "Dave", height: 1.88 },
  %{ name: "Dopey", height: 1.32 },
  %{ name: "Shaquille", height: 2.16 },
  %{ name: "Snezzy", height: 1.28 }
]

IO.inspect(for person = %{height: height} <- people, height > 1.5, do: person)
#=> [%{height: 1.88, name: "Dave"}, %{height: 2.16, name: "Shaquille"}]

マップのリストを内包表記してそれぞれのマップをpersonに束縛し変数heightでフィルタし、doブロックでperson全体を出力している。

パターンマッチはキーに値を束縛できない

%{2 => state} = %{1 => :ok, 2 => :error}

はできるけど、

%{item => :ok} = %{1 => :ok, 2 => :error}

のように書くことはできない。

ピン演算子に変数を束縛することもできる。

iex(IEX-8684@gergate)81> data = %{name: "Dave", state: "TX", likes: "Elixir"}
%{likes: "Elixir", name: "Dave", state: "TX"}
iex(IEX-8684@gergate)82> for key <- [:name, :likes] do
...(IEX-8684@gergate)82> %{^key => value} = data
...(IEX-8684@gergate)82> value
...(IEX-8684@gergate)82> end
["Dave", "Elixir"]

マップの更新

new_map = %{old_map | key => value, ...}

のような書き方でマップを更新できる。 新しいキーをマップに追加するには Map.put_new/3を使う。

構造体

defmodule Subscriber do
  defstruct name: "", paid: false, over_18: true
end

エリクサーにも構造体はある。

iex(2)> sl = %Subscriber{}
%Subscriber{name: "", over_18: true, paid: false}
iex(3)> s2 = %Subscriber{name: "kyoko"}
%Subscriber{name: "kyoko", over_18: true, paid: false}
iex(4)> s3 = %Subscriber{name: "geru", paid: true}
%Subscriber{name: "geru", over_18: true, paid: true}
iex(5)> s3.name
"geru"
iex(6)> s4 = %Subscriber{s3 | name: "newgeruge"}
%Subscriber{name: "newgeruge", over_18: true, paid: true}

こんな感じでマップと同じように作れて、値を更新できる。

defmodule Atendee do
  defstruct name: "", paid: false, over_18: true

  def may_attend_after_party(atendee = %Atendee{}) do
    atendee.paid && atendee.over_18
  end

  def print_vip_badge(%Atendee{name : name}) when name != "" do
    IO.puts "very cheep badge for #{name}"
  end

  def print_vip_badge(%Atendee{})  do
    raise "missing name for badge"
  end
end

マップとの違いは、構造体独自の関数を追加することができる点である。

入れ子になった辞書構造体

入れ子になった構造体の値を更新するとき、これまでのやり方だと

iex > report = %Hoge{ name | huga_name: %Huga ...]}

のように書かなければならず、非常に煩雑である。 put_inという入れ子アクセサのメソッドを使って、以下のように書ける。

iex > put_in(report.name.huga_name, "aaaa")

とはいえこれは単なるマクロらしい。 update_inも似たように入れ子にアクセスし、値に関数を適用する。

iex> update_in(report.name.huga_name, &("!!!" <> &1))

get_inget_and_update などの入れ子アクセサもある。

マップやキーワードリストに入れ子アクセサを用いる場合は、キーをアトムで書くことができる。

get_inget_and_update などは、関数をキーとして渡すと、対応する値を返す。これは動的なバージョンがサポートされているからである。

セット

MapSet というセットの実装がある。

第9章 型

プリミティブなデータ型は、それが表現できる型と同じである必要がない。 *2

*1:詳しくはマクロの章で。

*2:duck typing とOCamlの structural subtyping は似ている

3/22

今日は暖かかった。気圧は低く、頭は痛かったが。

おかげで体調もだいぶ良くなってきた。

ゴアテックスのズボン穿いたら暑かった。

 

体を鍛えてムキムキになりたい。

前職の思い出

ある同期にあまりに毎日陰湿で威圧的な態度を取られるため体調を崩し他の同期に相談していたところ、それを察したらしい張本人が

 

「こっちが把握してないところでこそこそやられるとヘイトたまるわ」

 

と言うようなことをツイートしていた。(当時は相互フォローだった)

 

私はその次の日から休職した。

 

彼は"新卒のまとめ役"を任されていたらしく、(その分給与が高かったとも聞く)

自分に全ての情報が回ってこないと気がすまなかったんだろう。

いやそんな態度じゃ人もついていかないだろ、と思うけど、

何に問題があったかは半年以上たった今でも理解していなさそうだ。

3/20

昨日酒を飲んで悪酔いしてしまい一日寝込んでいた。

普段はお酒をあまり飲まないのだが三連休にかまけて飲みすぎてしまった。反省。

気がくさくさしてるのて本でも読んで早く寝よう。

プロフェッショナルSSLTLS 第一章 SSL/TLSと暗号技術

クライアント通信ライブラリのデファクトで未だにTLS1.2対応していないものが活発に使われていたりする。大丈夫なのだろうか。

1.1 Transport Layer Security

セキュリティ以外の目標もある 含めると4つ

  1. 暗号学的なセキュリティ
  2. 相互運用性
  3. 拡張性
  4. 効率性

1.2 ネットワーク階層

  • IP/TCPがインターネットの仕組みを支えている。
  • データはパケットに格納され複数回のホップを通して送られる。

これらは覗かれる可能性があるもので、IP/TCP脆弱性がある。 TCP/IP以外にも、DNSやBGPなどの経路制御プロトコルにも脆弱性がある。 プロトコル自体を乗っ取られたら意図と異なる経路からデータが送られてくる可能性がある。

  • これらのなりすまし、改ざんに対しTLSではPublic Key Infrastructure(PKI)という技術を採用している。

TLSOSI参照モデルからもわかる通りTCPの上、HTTPの下に位置している。 そしてネットワークの階層構造上TLSトランスポート層より上の層に影響しない。

1.3 プロトコルの歴史

TSLの前身のSSLNetscapeで開発されていた。 SSL2がNetscape Navigator1.1で実装された。 SSL2には脆弱性があったためSSL3.0が開発され、これは2に対して設計が根本的に異なるものである。 これが現在のTLSプロトコルの基本設計となっている。 その後SSLIETFに移管された。その後数年たってRFC2246としてTLS1.0がリリースされる。 SSL3.0とTLS1.0の機能的な違いはほとんどないが互換性はなかった。 その後TLS1.1, 1.2がリリースされる。1.2ではAEADが対応され、またプロトコルも柔軟なものになった。

1.4 暗号技術

TLSでは暗号技術によって機密性、真証性(auth)、完全性が解決できる。

1.4.1 要素技術

暗号技術にはもちろんさまざまな要素技術が使われている。

  • 共通鍵暗号化方式 あの有名なアリスとボブのアレ。余談だが、暗号技術で出てくる盗聴してくるやつの名前の由来は盗聴者 (eavesdropper) からきているらしい。結城浩さんの本で読んだ。

暗号技術には、 Auguste Kerkhoffs の原則と呼ばれる以下のような洞察がある。

  • 暗号システムは鍵以外のすべてが攻撃者に掌握されたとしても安全でなければならない。

  • ストリーム暗号化方式

暗号アルゴリズムに1バイトの平文を流して1バイトの暗号にし受信側で逆の操作にする。 鍵ストリームの各バイトの位置を攻撃者に予測されなければ安全とみなせる。 同じ鍵を使いまわさないことが重要である。 この方式を取っている最も有名なものがRC4である。

  1. ブロック暗号化方式

データの一定の大きさの塊をまとめて暗号化する。 128bitがスタンダードだと言われる。 AESが有名。 ブロック暗号化方式は決定論的であるのでそれらに対処しなければあんまり役に立たない。 実際に使うときは暗号化利用モードと言われる暗号化スキームを利用する。 これにより認証機能もサポートできる。 MAC擬似乱数の生成の基盤として用いられている。

  1. パディング

ブロック長より短いデータに対して余分なデータを与え整形するやつ。 暗号化ブロックの末尾にパディングの長さを格納して受信者にパディングの長さを通知する。

  1. ハッシュ関数

任意の長さの入力を固定長の出力に変換するアルゴリズム。 暗号化技術的には、 - 原像計算困難性 - 第二原像計算困難性 - 衝突耐性 などの性質を求められている。 ハッシュ値はMDとかフィンガープリントとか呼ばれているのがそれ。 SHA1 や SHA256 などのハッシュ関数がよく使われている。 SHA1 は最近衝突したことが騒がれていましたね。 ハッシュ関数の強さはハッシュ値の長さと同一ではない。

  1. MAC メッセージ認証コード。完全性を保証するために用いられる。ハッシュ関数を拡張して認証を可能にした関数。 鍵付きハッシュなどとも呼ばれる。

  2. 暗号化利用モード 任意の長さのデータを暗号化できるようにした処理のこと。 ECBとかCBCとかいろいろある。 TLSではCBCが使われているがGCMも使える。

  3. 公開鍵暗号化システム

  4. デジタル署名
  5. 乱数生成器

この辺はよく知られている技術だろう。

1.4.2 プロトコル

要素技術は複数組み合わせて用いられる。TLSもこれらの技術を複数組み合わせたものである。 認証と鍵交換->機密性と完全性を保障したデータ交換->シャットダウンという一連の流れがハンドシェイクである。

1.4.3 攻撃

  • 複雑なシステムには多様な攻撃がなされる。鍵の探索空間が小さければしらみつぶしにされる。 暗号技術そのものに脆弱性があればその穴を突かれる。
  • プロトコルの実装そのものに対する攻撃もある。暗号ライブラリの多くは低級言語で書かれており、 その分脆弱性がまぎれ込みやすくなる。プロトコルは慎重に実装する必要がある。
  • 暗号技術自体が強固でもソフトウェア構成がゆるいとそこを狙われる。 サーバに侵入されてそこに置いてある鍵が盗まれるなどしたらどうしようもない。 確立されたプロトコルを使い、高レベルのライブラリを用い、十分な鍵長でアルゴリズムを使う必要がある。

1.4.4 暗号強度

  • 128ビットの鍵に対しては2128回の総当たりで十分である。256になると指数関数的に総当たり回数が増えるので長期間にわたるセキュリティの確保がしたければ256がよい。

暗号強度は厳密に測ることはできない。が、ENISAなどのドキュメントは頼りになる。

1.4.5 MITM攻撃

中間者攻撃と呼ばれるもの。Man in the middle Attack の略。

  1. アクセスの奪取 ルータなどネットワークが経由するノードにアクセスし、パケットの中身を見たり妨害したりする。 認証なしの無線ネットワークなどでよくある。

  2. ARPスプーフィング 任意のIPアドレスMACアドレスに結びつけて経路を変えてしまう。

  3. WPADハイジャック プロキシを乗っ取ってWPADに対する攻撃を行う。

  4. DNSハイジャック レジストラと共謀してドメインを乗っ取ったりDNSの設定を変更しトラフィックを乗っ取る。

  5. DNSキャッシュポイゾニング DNSサーバのキャッシュの脆弱性を悪用する。不正なドメイン名の情報をキャッシュに入れ込むことで利用者は不正な情報を受け取ってしまう。

  6. BGP経路ハイジャック ルータが利用する経路制御プロトコルを乗っ取りIPアドレスのブロックの行き先を変えてしまう。

受動的な攻撃、能動的な攻撃

  • トラフィックが暗号化されていないとき受動的攻撃は有効に働く。

広範なモニタリングは可能な限り暗号化によって防御するべきとIETFは宣言している

  • 暗号化されたトラフィックであっても一度保存して置いて暗号を破れるまで保存できたりする。

今解けない暗号でも10年後には解かれているかもしれない!

  • TLS で攻撃者が受信者に対して有効な証明書を提示できてしまう場合、攻撃自体が検知されない。 ブラウザの検証機構を騙して有効に見える証明書を作ることもできる。

  • NSA QuantumInsert というプログラムの下で、インターネット上の任意のコンピュータに対する能動的攻撃が可能になったということが指摘されている。 特定の個人に対してブラウザの挙動を変えられるもので、パケットを生成するノードを通信インフラの重要起点に設置することで本来のサーバよりはやくNSAは応答を返し、トラフィックを制御してしまう。