CRC32だからといって遅くはない

うちの職場で作っている製品では、ある世代の製品ではCRC16を、ある世代の製品ではCRC32をデータの誤り検出に使っている。

今にして見ればなんでわざわざCRC16という感じもあるけど……


この職場に来てから今まで、CRC演算を使った処理に手を入れることがけっこうあったのだが、

そのとき使っていたマイコンはいずれもCRC演算用のペリフェラルがあった。

設定をしてデータを書き込むと、ペリフェラルで演算してくれると。

まとまったデータがあるならDMA転送との組み合わせが効果的である。

CRC演算は時間がかかるからDMA


ただ、CRC16を使っている世代の製品で使っているマイコンにはそういうものはない。

ゆえにアルゴリズムをプログラミングしてCRC演算をしている。

これをCRC32にするとどうなるかという話が話題になったのだが、

意外とCRC演算そのものの処理時間はあまり変わらないようだ。


なぜCRC演算そのものの処理時間があまり変わらないのか?

プログラムでCRC演算を行う場合、効率化のためテーブルが使われることが多い。

Web上で探すと8bit単位で計算するサンプルプログラムがよく見つかるが、

マイコンのROM容量も考慮してか4bit単位で計算するようにしていた。

テーブルを使う場合の処理内容はCRC16もCRC32もそんなに変わらない。

idx=(crc^data)&0x0F;
crc=(crc>>4)^table[idx];

実際はもうちょっと考えることはあるが、模式図としてはこんな感じ。

このマイコンでは32bitの演算を1命令で処理できるので、

CRC16の演算ではXORやビットシフトの演算回数を減らす工夫をしていた。

CRC32ではそうもいかないので愚直に書く必要があったぐらいである。

演算に使用するテーブルの容量も増えるが、16bit×16個が32bit×16個に増える程度だから、そこまでのインパクトはない。

32byteのテーブルが64byteに増えても軽微な問題ですよね。


マイコンによっては16bit単位でしか演算できないとかいうこともあるから、

そうするとCRC16とCRC32の演算処理は全然違うかも知れない。

あと、元々8bit単位でテーブルにあてはめて演算していたとすると、

512byteのテーブルが1024byteに増えるわけだから、ちょっと気になったかも。

(これもそんなに気にするほどの差ではないかもしれないが)


そういう意味ではCRC64なんて導入するとなればけっこう大きな話だったかも。

というかCRC64なんてあるの? と思って調べたけど、一応あるみたい。

ただ、使っているところはかなり限られるようだけど。

誤り検出としてはCRC32でもかなり高いレベルにあるということなんだろう。

あるいは改ざん防止としても効果的なSHA-256などのハッシュ関数を使うべきということだろう。

(さすがにそこまで来るとマイコンのプログラムで計算するのは大変だが)


冒頭に「今にして見ればなんでわざわざCRC16」と書いたけど、

これはおそらくはデータサイズの制約によるものではないかと思う。

確かにCRC16とCRC32のサイズの差は2byteしかないのだが、

そのわずかな差で従来1回で転送できていたデータが1回に収まりきらず、

2回に分割して通信することになると、各ブロックにCRCを含むヘッダーを付ける必要があり……

という影響の大きさを考えるとCRC16が適するという判断があったのかも。