Hensel's Lifting - $p^n$ for $n > 2$

220 Views Asked by At

I found question: Algorithm for Hensel's Lifting

I implemented an algorithm for $p^2$.

Works correctly.

But I do not fully understand how to implement for $p^n$ for $n>2$.

Can someone help? To explain how to calculate for higher powers?

I do not understand how to continue calculating.

--- EDIT:

I add my code as an attachment:

#include <stdio.h>
#include <math.h>

unsigned long long int ipow( unsigned long long int base, unsigned long long int exp )
{
    unsigned long long int result = 1ULL;

    while( exp )
    {
        if ( exp & 1 )
        {
            result *= (unsigned long long int)base;
        }
        exp >>= 1;
        base *= base;
    }

    return result;
}


long pow_mod(long x, long n, long p)
{
    if (n == 0) return 1;
    if (n & 1)
        return (pow_mod(x, n-1, p) * x) % p;

    x = pow_mod(x, n/2, p);
    return (x * x) % p;
}

/* Takes as input an odd prime p and n < p and returns r
 * such that r * r = n [mod p]. */
long int tonelli_shanks(long n, long p)
{
    long s = 0;
    long q = p - 1;

    while ((q & 1) == 0)
    {
        q /= 2; ++s;
    }

    if (s == 1)
    {
        long r = pow_mod(n, (p+1)/4, p);
        if ((r * r) % p == n)
            return r;

        return 0;
    }

    // Find the first quadratic non-residue z by brute-force search
    long z = 1;
    while (pow_mod(++z, (p-1)/2, p) != p - 1 && z < 2*ceil(log(p)*log(p))+2);

    if(z == (long int) 2*ceil(log(p)*log(p))+2)
        return 0;

    long c = pow_mod(z, q, p);
    long r = pow_mod(n, (q+1)/2, p);
    long t = pow_mod(n, q, p);
    long m = s;
    while (t != 1)
    {
        long tt = t;
        long i = 0;

        while (tt != 1)
        {
            tt = (tt * tt) % p;
            ++i;
            if (i == m)
                return 0;
        }

        long b = pow_mod(c, pow_mod(2, m-i-1, p-1), p);
        long b2 = (b * b) % p;
        r = (r * b) % p;
        t = (t * b2) % p;
        c = b2;
        m = i;
    }

    if ((r * r) % p == n)
        return r;

    return 0;
}


int main()
{

    long long int xs[100], fx, fpx, t;

    long long int C = 3483;
    long long int p = 3;
    long long int degree = 6;

    xs[1] = tonelli_shanks(C%p, p);

    long long int residues;

    long int xi;
    for(xi=1; xi <= degree; xi++)
    {

        fx = xs[xi]*xs[xi] - C%(ipow(p, xi));
        fpx = 2*xs[xi];

        long long int factors_pow_m1 = ipow(p, xi);

        t = 1;
        while ( ((fx/p) + t*fpx) % factors_pow_m1 != 0 && t < 100000 )
            t++;

        xs[xi+1] = xs[xi] + t*p;

        residues = xs[xi+1] % ipow(p, xi);

    } // loop xi

    printf("residue=%lld\n", residues);

    return 0;
}

In code we looking: $x^2 \equiv 567 \pmod{3^6}$; ($3483 \equiv 567 \pmod{3^6}$). Program return $294$, but this is a bad result because $294^2 \equiv 414 \pmod{3^6}$.

Function tonelli_shanks() is good. The logic error must be in the main() function.

Maybe someone has an idea what is wrong? How should I count this?