昨日の記事で、 secure_compare
は String#==
とは異なり常に一定時間で処理が行われる、と書いた。
Rack::Utils.secure_compare を読む - ユユユユユ (https://jnsato.hateblo.jp/entry/2020/06/27/230000)
あらためて 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回繰り返して、有意と言える差は出ている。わずかな差といえばわずかな差であるが、少なくとも表題の疑問には答えられているだろう。