Task: Cipolla's algorithm



C#: using System;
using System.Numerics;

namespace CipollaAlgorithm {
    class Program {
        static readonly BigInteger BIG = BigInteger.Pow(10, 50) + 151;

        private static Tuple<BigInteger, BigInteger, bool> C(string ns, string ps) {
            BigInteger n = BigInteger.Parse(ns);
            BigInteger p = ps.Length > 0 ? BigInteger.Parse(ps) : BIG;

            
            BigInteger ls(BigInteger a0) => BigInteger.ModPow(a0, (p - 1) / 2, p);

            
            if (ls(n) != 1) {
                return new Tuple<BigInteger, BigInteger, bool>(0, 0, false);
            }

            
            BigInteger a = 0;
            BigInteger omega2;
            while (true) {
                omega2 = (a * a + p - n) % p;
                if (ls(omega2) == p - 1) {
                    break;
                }
                a += 1;
            }

            
            BigInteger finalOmega = omega2;
            Tuple<BigInteger, BigInteger> mul(Tuple<BigInteger, BigInteger> aa, Tuple<BigInteger, BigInteger> bb) {
                return new Tuple<BigInteger, BigInteger>(
                    (aa.Item1 * bb.Item1 + aa.Item2 * bb.Item2 * finalOmega) % p,
                    (aa.Item1 * bb.Item2 + bb.Item1 * aa.Item2) % p
                );
            }

            
            Tuple<BigInteger, BigInteger> r = new Tuple<BigInteger, BigInteger>(1, 0);
            Tuple<BigInteger, BigInteger> s = new Tuple<BigInteger, BigInteger>(a, 1);
            BigInteger nn = ((p + 1) >> 1) % p;
            while (nn > 0) {
                if ((nn & 1) == 1) {
                    r = mul(r, s);
                }
                s = mul(s, s);
                nn >>= 1;
            }

            
            if (r.Item2 != 0) {
                return new Tuple<BigInteger, BigInteger, bool>(0, 0, false);
            }

            
            if (r.Item1 * r.Item1 % p != n) {
                return new Tuple<BigInteger, BigInteger, bool>(0, 0, false);
            }

            
            return new Tuple<BigInteger, BigInteger, bool>(r.Item1, p - r.Item1, true);
        }

        static void Main(string[] args) {
            Console.WriteLine(C("10", "13"));
            Console.WriteLine(C("56", "101"));
            Console.WriteLine(C("8218", "10007"));
            Console.WriteLine(C("8219", "10007"));
            Console.WriteLine(C("331575", "1000003"));
            Console.WriteLine(C("665165880", "1000000007"));
            Console.WriteLine(C("881398088036", "1000000000039"));
            Console.WriteLine(C("34035243914635549601583369544560650254325084643201", ""));
        }
    }
}






VB: Imports System.Numerics

Module Module1

    ReadOnly BIG = BigInteger.Pow(10, 50) + 151

    Function C(ns As String, ps As String) As Tuple(Of BigInteger, BigInteger, Boolean)
        Dim n = BigInteger.Parse(ns)
        Dim p = If(ps.Length > 0, BigInteger.Parse(ps), BIG)

        
        Dim ls = Function(a0 As BigInteger) BigInteger.ModPow(a0, (p - 1) / 2, p)

        
        If ls(n) <> 1 Then
            Return Tuple.Create(BigInteger.Zero, BigInteger.Zero, False)
        End If

        
        Dim a = BigInteger.Zero
        Dim omega2 As BigInteger
        Do
            omega2 = (a * a + p - n) Mod p
            If ls(omega2) = p - 1 Then
                Exit Do
            End If
            a += 1
        Loop

        
        Dim mul = Function(aa As Tuple(Of BigInteger, BigInteger), bb As Tuple(Of BigInteger, BigInteger))
                      Return Tuple.Create((aa.Item1 * bb.Item1 + aa.Item2 * bb.Item2 * omega2) Mod p, (aa.Item1 * bb.Item2 + bb.Item1 * aa.Item2) Mod p)
                  End Function

        
        Dim r = Tuple.Create(BigInteger.One, BigInteger.Zero)
        Dim s = Tuple.Create(a, BigInteger.One)
        Dim nn = ((p + 1) >> 1) Mod p
        While nn > 0
            If nn Mod 2 = 1 Then
                r = mul(r, s)
            End If
            s = mul(s, s)
            nn >>= 1
        End While

        
        If r.Item2 <> 0 Then
            Return Tuple.Create(BigInteger.Zero, BigInteger.Zero, False)
        End If

        
        If r.Item1 * r.Item1 Mod p <> n Then
            Return Tuple.Create(BigInteger.Zero, BigInteger.Zero, False)
        End If

        
        Return Tuple.Create(r.Item1, p - r.Item1, True)
    End Function

    Sub Main()
        Console.WriteLine(C("10", "13"))
        Console.WriteLine(C("56", "101"))
        Console.WriteLine(C("8218", "10007"))
        Console.WriteLine(C("8219", "10007"))
        Console.WriteLine(C("331575", "1000003"))
        Console.WriteLine(C("665165880", "1000000007"))
        Console.WriteLine(C("881398088036", "1000000000039"))
        Console.WriteLine(C("34035243914635549601583369544560650254325084643201", ""))
    End Sub

End Module