合同算術において、バレットの還元アルゴリズムは P.D. バレットによって 1986 年に開発されたアルゴリズムである。[1]以下の式を計算することを考える。

愚直な方法は、高速な除算アルゴリズムを使用する方法である。バレットの還元アルゴリズムは、除算を乗算に置き換えることにより、
が定数で
であるときにこの計算を高速化する。
の浮動小数点数としての逆数を
とおくと、
を床関数として

となる。
が十分な精度で計算される限り、これは誤差なく成り立つ。
バレットが最初に考案したのは、上記のアルゴリズムの整数版であり、特に値がマシンのワードに収まる場合に適用できる。
上記の方法で
を整数の範囲内で計算する場合、自明に対応するのは
による除算を用いる方法である。
func reduce(a uint) uint {
q := a / n // 小数部分は暗黙に切り捨てられる
return a - q * n
}
しかし、除算の計算には時間がかかり、CPUによっては定数時間で完了しない命令が使用されうる。そこで、バレットの方法では
による除算なら低コストな右シフトとして実現できることに注目し、
を
で近似する。
が与えられたとき、最良の
を見つけるために以下の式を考える。

を整数にするために、
をどうにか整数に丸める必要がある。最も近い整数に丸めるのが最適だが、
が
より大きくなるとアンダーフローを生じうるため、一般には
を用いる。
すると、前述の関数は以下のように書き換えられる。
func reduce(a uint) uint {
q := (a * m) >> k // ">> k" は k ビットの右シフト
return a - q * n
}
ここで、
なので、この関数における q
は小さめに評価される。これによりa
は
に必ずしも収まらず、
の値を取りうる。そのため、値が
を超えた場合は
を引くことによってこれを補正する。
func reduce(a uint) uint {
q := (a * m) >> k
a -= q * n
if n <= a {
a -= n
}
return a
}
は近似にすぎないので、近似が正当となる
の範囲を考える必要がある。
の近似誤差は

なので、q
の誤差は
である。
、すなわち
である限り、この還元は正当である。
である場合も必ずしもこの関数が誤った値を返すわけではないが、
を先述の範囲内に収めることで一般の場合においての正当性を保証できる。
を大きく取ると、還元が正当となる
の範囲は広がる一方、他の計算においてオーバーフローを生じる可能性がある。
16 ビット整数のシステム上で
としたときを考える。
アルゴリズムが意味をなすためには、少なくとも
は
以上である必要がある。さもなくば、剰余を必要としない小さい値に対してしか還元が正しく動作しなくなってしまう。
のときは、
であり、
のときは
である。後者においては
を
で近似することになるので、前者における
による近似と全く等価になる。
とすれば
となり、よりよい近似を得る。
と
において、アルゴリズムが正しい値を与える入力の範囲を考える。前者においては、
なので、
すなわち
である。
は整数なので、実質的な上限は 478 である。(実際は 504 まで正しく動く。)
においては、
なので
の実質的な上限は 7387 である。(実際は 7473 まで正しく動く。)
近似がより良くなる次の
は 13 であり、
を与える。もっとも、計算途中に現れる
が
でオーバーフローすることに注意すれば、この問題設定では
とした方が良い。
なる最小の整数
をとり、
を
とすると、これは上記の式で説明した「意味をなす」
である。前述のコードに対応して次の値を定義する。

.
床関数の定義から、
は整数で、
である。また、
なら
となる。このとき、前述のコードを数式で表すと

このとき、
であることが以下のように示せる。
なら

である。
が
にかかわらず成立するので、以下の式変形を得る。










マルチワード版のバレットの還元アルゴリズム
[編集]
バレットはこのアルゴリズムをRSA暗号の実装のために考案した。しかし、RSA暗号においては入力値は基本的にワードサイズを超える。そのためバレットは上記のアルゴリズムのマルチワード版も与えた。詳細については Handbook of Applied Cryptography を参照のこと。[2]
バレットのアルゴリズムは多項式除算に対しても適用できる。これは、多項式を反転して X 進数を用いることで計算される。[3]