Millerrabintest

// This file implements two versions of the Miller-Rabin primality test.
// One of the implementations is deterministic and the other is probabilistic.
// The Miller-Rabin test is one of the simplest and fastest known primality
// tests and is widely used.
//
// Authors:
// [Taj](https://github.com/tjgurwara99)
// [Rak](https://github.com/raklaptudirm)

package prime

import (
	"math/rand"

	"github.com/TheAlgorithms/Go/math/modular"
)

// formatNum accepts a number and returns the
// odd number d such that num = 2^s * d + 1
func formatNum(num int64) (d int64, s int64) {
	d = num - 1
	for num%2 == 0 {
		d /= 2
		s++
	}
	return
}

// isTrivial checks if num's primality is easy to determine.
// If it is, it returns true and num's primality. Otherwise
// it returns false and false.
func isTrivial(num int64) (prime bool, trivial bool) {
	if num <= 4 {
		// 2 and 3 are primes
		prime = num == 2 || num == 3
		trivial = true
	} else {
		prime = false
		// number is trivial prime if
		// it is divisible by 2
		trivial = num%2 == 0
	}

	return
}

// MillerTest tests whether num is a strong probable prime to a witness.
// Formally: a^d ≑ 1 (mod n) or a^(2^r * d) ≑ -1 (mod n), 0 <= r <= s
func MillerTest(num, witness int64) (bool, error) {
	d, _ := formatNum(num)
	res, err := modular.Exponentiation(witness, d, num)

	if err != nil {
		return false, err
	}
	// miller conditions checks
	if res == 1 || res == num-1 {
		return true, nil
	}

	for d != num-1 {
		res = (res * res) % num
		d *= 2
		if res == 1 {
			return false, nil
		}
		if res == num-1 {
			return true, nil
		}
	}
	return false, nil
}

// MillerRandomTest This is the intermediate step that repeats within the
// miller rabin primality test for better probabilitic chances of
// receiving the correct result with random witnesses.
func MillerRandomTest(num int64) (bool, error) {
	random := rand.Int63n(num-2) + 2
	return MillerTest(num, random)
}

// MillerTestMultiple is like MillerTest but runs the test for multiple
// witnesses.
func MillerTestMultiple(num int64, witnesses ...int64) (bool, error) {
	for _, witness := range witnesses {
		prime, err := MillerTest(num, witness)
		if err != nil {
			return false, err
		}

		if !prime {
			return false, nil
		}
	}

	return true, nil
}

// MillerRabinProbabilistic is a probabilistic test for primality
// of an integer based of the algorithm devised by Miller and Rabin.
func MillerRabinProbabilistic(num, rounds int64) (bool, error) {
	if prime, trivial := isTrivial(num); trivial {
		// num is a trivial number
		return prime, nil
	}

	for i := int64(0); i < rounds; i++ {
		val, err := MillerRandomTest(num)
		if err != nil {
			return false, err
		}
		if !val {
			return false, nil
		}
	}
	return true, nil
}

// MillerRabinDeterministic is a Deterministic version of the Miller-Rabin
// test, which returns correct results for all valid int64 numbers.
func MillerRabinDeterministic(num int64) (bool, error) {
	if prime, trivial := isTrivial(num); trivial {
		// num is a trivial number
		return prime, nil
	}

	switch {
	case num < 2047:
		// witness 2 can determine the primality of any number less than 2047
		return MillerTest(num, 2)
	case num < 1_373_653:
		// witnesses 2 and 3 can determine the primality
		// of any number less than 1,373,653
		return MillerTestMultiple(num, 2, 3)
	case num < 9_080_191:
		// witnesses 31 and 73 can determine the primality
		// of any number less than 9,080,191
		return MillerTestMultiple(num, 31, 73)
	case num < 25_326_001:
		// witnesses 2, 3, and 5 can determine the
		// primality of any number less than 25,326,001
		return MillerTestMultiple(num, 2, 3, 5)
	case num < 1_122_004_669_633:
		// witnesses 2, 13, 23, and 1,662,803 can determine the
		// primality of any number less than 1,122,004,669,633
		return MillerTestMultiple(num, 2, 13, 23, 1_662_803)
	case num < 2_152_302_898_747:
		// witnesses 2, 3, 5, 7, and 11 can determine the primality
		// of any number less than 2,152,302,898,747
		return MillerTestMultiple(num, 2, 3, 5, 7, 11)
	case num < 341_550_071_728_321:
		// witnesses 2, 3, 5, 7, 11, 13, and 17 can determine the
		// primality of any number less than 341,550,071,728,321
		return MillerTestMultiple(num, 2, 3, 5, 7, 11, 13, 17)
	default:
		// witnesses 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, and 37 can determine
		// the primality of any number less than 318,665,857,834,031,151,167,461
		// which is well above the max int64 9,223,372,036,854,775,807
		return MillerTestMultiple(num, 2, 3, 5, 7, 11, 13, 17, 19, 23, 31, 37)
	}
}
Algerlogo

Β© Alger 2022

About us

We are a group of programmers helping each other build new things, whether it be writing complex encryption programs, or simple ciphers. Our goal is to work together to document and model beautiful, helpful and interesting algorithms using code. We are an open-source community - anyone can contribute. We check each other's work, communicate and collaborate to solve problems. We strive to be welcoming, respectful, yet make sure that our code follows the latest programming guidelines.