Task: Montgomery reduction




Go: package main

import (
    "fmt"
    "math/big"
    "math/rand"
    "time"
)


type mont struct {
    n  uint     
    m  *big.Int 
    r2 *big.Int 
}


func newMont(m *big.Int) *mont {
    if m.Bit(0) != 1 {
        return nil
    }
    n := uint(m.BitLen())
    x := big.NewInt(1)
    x.Sub(x.Lsh(x, n), m)
    return &mont{n, new(big.Int).Set(m), x.Mod(x.Mul(x, x), m)}
}


func (m mont) reduce(t *big.Int) *big.Int {
    a := new(big.Int).Set(t)
    for i := uint(0); i < m.n; i++ {
        if a.Bit(0) == 1 {
            a.Add(a, m.m)
        }
        a.Rsh(a, 1)
    }
    if a.Cmp(m.m) >= 0 {
        a.Sub(a, m.m)
    }
    return a
}


func main() {
    const n = 100 

    
    rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
    one := big.NewInt(1)
    r1 := new(big.Int).Lsh(one, n-1)
    r2 := new(big.Int).Lsh(one, n-2)
    m := new(big.Int)
    m.Or(r1, m.Or(m.Lsh(m.Rand(rnd, r2), 1), one))

    
    mr := newMont(m)

    
    
    x1 := new(big.Int).Rand(rnd, m)
    x2 := new(big.Int).Rand(rnd, m)

    
    
    t1 := new(big.Int).Mul(x1, mr.r2)
    t2 := new(big.Int).Mul(x2, mr.r2)

    
    r1 = mr.reduce(t1)
    r2 = mr.reduce(t2)

    
    fmt.Println("b:  2")
    fmt.Println("n: ", mr.n)
    fmt.Println("r: ", new(big.Int).Lsh(one, mr.n))
    fmt.Println("m: ", mr.m)
    fmt.Println("t1:", t1)
    fmt.Println("t2:", t2)
    fmt.Println("r1:", r1)
    fmt.Println("r2:", r2)

    
    fmt.Println()
    fmt.Println("Original x1:       ", x1)
    fmt.Println("Recovererd from r1:", mr.reduce(r1))
    fmt.Println("Original x2:       ", x2)
    fmt.Println("Recovererd from r2:", mr.reduce(r2))

    
    fmt.Println("\nMontgomery computation of x1 ^ x2 mod m:")
    
    
    prod := mr.reduce(mr.r2)             
    base := mr.reduce(t1.Mul(x1, mr.r2)) 
    exp := new(big.Int).Set(x2)          
    for exp.BitLen() > 0 {
        if exp.Bit(0) == 1 {
            prod = mr.reduce(prod.Mul(prod, base))
        }
        exp.Rsh(exp, 1)
        base = mr.reduce(base.Mul(base, base))
    }
    fmt.Println(mr.reduce(prod))

    
    fmt.Println("\nLibrary-based computation of x1 ^ x2 mod m:")
    fmt.Println(new(big.Int).Exp(x1, x2, m))
}





VB: Imports System.Numerics
Imports System.Runtime.CompilerServices

Module Module1

    <Extension()>
    Function BitLength(v As BigInteger) As Integer
        If v < 0 Then
            v *= -1
        End If

        Dim result = 0
        While v > 0
            v >>= 1
            result += 1
        End While
        Return result
    End Function

    Structure Montgomery
        Shared ReadOnly BASE = 2
        Dim m As BigInteger
        Dim rrm As BigInteger
        Dim n As Integer

        Sub New(m As BigInteger)
            If m < 0 OrElse m.IsEven Then
                Throw New ArgumentException()
            End If

            Me.m = m
            n = m.BitLength
            rrm = (BigInteger.One << (n * 2)) Mod m
        End Sub

        Function Reduce(t As BigInteger) As BigInteger
            Dim a = t
            For i = 1 To n
                If Not a.IsEven Then
                    a += m
                End If
                a >>= 1
            Next
            If a >= m Then
                a -= m
            End If
            Return a
        End Function
    End Structure

    Sub Main()
        Dim m = BigInteger.Parse("750791094644726559640638407699")
        Dim x1 = BigInteger.Parse("540019781128412936473322405310")
        Dim x2 = BigInteger.Parse("515692107665463680305819378593")

        Dim mont As New Montgomery(m)
        Dim t1 = x1 * mont.rrm
        Dim t2 = x2 * mont.rrm

        Dim r1 = mont.Reduce(t1)
        Dim r2 = mont.Reduce(t2)
        Dim r = BigInteger.One << mont.n

        Console.WriteLine("b :  {0}", Montgomery.BASE)
        Console.WriteLine("n :  {0}", mont.n)
        Console.WriteLine("r :  {0}", r)
        Console.WriteLine("m :  {0}", mont.m)
        Console.WriteLine("t1:  {0}", t1)
        Console.WriteLine("t2:  {0}", t2)
        Console.WriteLine("r1:  {0}", r1)
        Console.WriteLine("r2:  {0}", r2)
        Console.WriteLine()
        Console.WriteLine("Original x1       : {0}", x1)
        Console.WriteLine("Recovered from r1 : {0}", mont.Reduce(r1))
        Console.WriteLine("Original x2       : {0}", x2)
        Console.WriteLine("Recovered from r2 : {0}", mont.Reduce(r2))

        Console.WriteLine()
        Console.WriteLine("Montgomery computation of x1 ^ x2 mod m :")
        Dim prod = mont.Reduce(mont.rrm)
        Dim base = mont.Reduce(x1 * mont.rrm)
        Dim exp = x2
        While exp.BitLength > 0
            If Not exp.IsEven Then
                prod = mont.Reduce(prod * base)
            End If
            exp >>= 1
            base = mont.Reduce(base * base)
        End While
        Console.WriteLine(mont.Reduce(prod))
        Console.WriteLine()
        Console.WriteLine("Alternate computation of x1 ^ x2 mod m :")
        Console.WriteLine(BigInteger.ModPow(x1, x2, m))
    End Sub

End Module