ユユユユユ

webエンジニアです

`String#==` は実行時間が最適化されているか?

 昨日の記事で、 secure_compareString#== とは異なり常に一定時間で処理が行われる、と書いた。

jnsato.hateblo.jp

 あらためて GitHub Developer から引用する。

Using a plain == operator is not advised. A method like secure_compare performs a "constant time" string comparison, which renders it safe from certain timing attacks against regular equality operators._1

 しかし、本当に String#== は実行時間が最適化されていて、入力次第で実行時間が異なるのだろうか?

 String#== のドキュメントには記述がなく、 Ruby 本体のソースを読もうにも上手く見当がつけられなかったので、愚直にベンチマークをとることにした。その結果が以下。

require 'benchmark'

n = 1_000
chars = ['a'].cycle.take(n-1).join('')

s1 = 'a' + chars
s2 = 'b' + chars
s3 = chars + 'b'

t = 10_000

Benchmark.bm(12) do |x|
  x.report('at_the_front') do
    t.times { s1 == s2 }
  end

  x.report('at_the_end') do
    t.times { s1 == s3 }
  end
end

#                    user     system      total        real
# at_the_front   0.000444   0.000005   0.000449 (  0.000442)
# at_the_end     0.000990   0.000002   0.000992 (  0.000991)

 長さ1000の文字列について、先頭の文字が異なるケースと末尾の文字が異なるケースで比較している。それを10000回繰り返して、有意と言える差は出ている。わずかな差といえばわずかな差であるが、少なくとも表題の疑問には答えられているだろう。