closure_pnp.py — src/26-pnp

The script src/26-pnp/closure_pnp.py of the validation package of the paper 26-pnp, rendered with an anchor per line. ▶ run the predicates on Google Colab.

26-pnp ledgersrc/26-pnp/closure_pnp.py · 6.4 KBclosure_pnp.pyColab
1#!/usr/bin/env python32# -*- coding: utf-8 -*-3"""4closure_pnp.py  (26-pnp/validation)  -- FINITE, no continuum, NO RANDOM NUMBER GENERATOR.5=========================================================================================6The arithmetic-hierarchy closure as the algebraic foundation of the one-way structure (sec:owf).7The ladder counting -> addition -> multiplication -> exponentiation closes: the fifth operation is8iteration of the power map P_k(x)=x^k, which on a finite carrier is orbit-counting (finite-orbit9closure), so it returns to the first role.  Consequences for P vs NP:1011  T1  ASCENT DYNAMICS / closure phase formula.  In the scale chart x=g^m (g primitive, m in Z_{P-1}),12      the fourth role acts by m->k m and its iteration by  P_k^r(g^m)=g^{k^r m mod (P-1)}.  The ascent13      a_P(j)=g^j is orbit traversal j->j+1 => g^{j+1}=g*g^j: one multiplication per COUNTED step.14  T2  THE FOUR FORWARD ROLES ARE EACH poly(ell).  counting (+1), addition (+a), multiplication (m*),15      exponentiation/ascent (g^j by square-and-multiply) all cost <= O(ell) modular operations.16  T3  ONLY THE INVERSE OF THE FOURTH ROLE BREAKS.  the descent d_P=dlog_g (recover the COUNT m from17      g^m) scales as sqrt(P) (baby-step-giant-step); ascent/descent op-ratio grows ~ sqrt(P)/ell.18      So all irreversibility is localised to inverting the last primitive role -- not a forbidden op19      but the orbit-POSITION problem the forward 'return to counting' does not supply.20  T4  BIJECTIVE vs COMPRESSIVE.  P_k is a bijection of F_P^x iff gcd(k,P-1)=1, else its image has size21      (P-1)/gcd(k,P-1); the iteration orbit r->k^r m is finite and eventually periodic (closure).2223PINNED before the numbers.  No np.random anywhere.  Dependencies: sympy.24"""25import math26from sympy import isprime, primitive_root, primerange2728PASS=029def ok(t,c,m):30    global PASS31    assert c, f"FAIL {t}: {m}"32    print(f"PASS {t}: {m}"); PASS+=13334# ---------- T1: closure / ascent phase formula ----------35print("T1  closure phase formula  P_k^r(g^m) = g^{k^r m mod (P-1)}  (iterating the 4th role = phase index x k^r)")36viol=0; nch=037for P in (13,101,1009,10009):38    g=int(primitive_root(P)); n=P-139    for k in (2,3,5,7,10):40        for m in (1,2,7):41            for r in (0,1,2,3,5):42                x=pow(g,m,P)43                for _ in range(r): x=pow(x,k,P)        # iterate the power map r times44                rhs=pow(g,(pow(k,r,n)*m)%n,P)          # closed form45                nch+=146                if x!=rhs: viol+=147print(f"     checked {nch} (P,k,m,r) cases across 4 carriers")48ok("T1", viol==0, f"the fourth role iterates as m->k^r m in the phase-index ring Z_(P-1) ({viol} violations) -- "49   "the ascent g^j is counting along the power-map orbit (g^{j+1}=g*g^j)")5051# ---------- T2: the four forward roles are each poly(ell) ----------52print("\nT2  the four forward roles are each poly(ell):  modular-op count per application")53print(f"  {'P':>10} {'ell':>4} {'count(+1)':>9} {'add(+a)':>8} {'mult(m*)':>9} {'ascent g^j (sq&mul)':>20}")54def ascent_ops(g,j,P):                                   # modmuls in square-and-multiply55    ops=0; r=1; b=g; e=j56    while e>0:57        if e&1: r=(r*b)%P; ops+=158        e>>=159        if e>0: b=(b*b)%P; ops+=160    return ops61roles_poly=True62for P in (10007,1000003,100000007):63    ell=P.bit_length(); g=int(primitive_root(P))64    asc=ascent_ops(g,P-2,P)                               # worst-ish exponent65    # counting=1 op, addition=O(ell) bit (1 modular add), multiplication=1 modular mult66    if not (asc<=2*ell+2): roles_poly=False67    print(f"  {P:>10} {ell:>4} {1:>9} {1:>8} {1:>9} {asc:>20} (<= 2 ell = {2*ell})")68ok("T2", roles_poly, "every forward role -- counting, addition, multiplication, exponentiation -- costs O(ell) "69   "modular operations; the closed ladder is poly(ell) in the forward direction")7071# ---------- T3: only the inverse of the fourth role breaks ----------72print("\nT3  only the INVERSE of the fourth role is hard:  ascent (sq&mul) vs descent dlog (BSGS)")73def dlog_bsgs(g,h,P):                                     # returns (x, group-op count)74    n=P-1; m=math.isqrt(n)+1; tbl={}; e=1; ops=075    for j in range(m): tbl.setdefault(e,j); e=(e*g)%P; ops+=176    fac=pow(g,(n-1)*m % n,P); gamma=h%P77    for i in range(m):78        if gamma in tbl: return i*m+tbl[gamma], ops+i79        gamma=(gamma*fac)%P80    return None, ops+m81print(f"  {'P':>10} {'ell':>4} {'ascent ops':>10} {'descent ops':>12} {'ratio':>10}")82ratios=[]83for P in (10007,1000003,100000007):84    ell=P.bit_length(); g=int(primitive_root(P))85    m_true=P//3; h=pow(g,m_true,P)86    asc=ascent_ops(g,m_true,P)87    x,desc=dlog_bsgs(g,h,P); assert pow(g,x,P)==h88    ratios.append(desc/asc)89    print(f"  {P:>10} {ell:>4} {asc:>10} {desc:>12} {desc/asc:>10.1f}")90ok("T3", ratios[-1]>ratios[0]*5, f"descent/ascent op-ratio grows {ratios[0]:.0f}->{ratios[-1]:.0f} (~sqrt(P)/ell): "91   "all irreversibility sits in inverting the last role -- recovering the count from its orbit position (dlog)")9293# ---------- T4: bijective vs compressive; orbit closure ----------94print("\nT4  P_k bijective iff gcd(k,P-1)=1; image size (P-1)/gcd; iteration orbit eventually periodic")95print(f"  {'P':>6} {'k':>3} {'gcd(k,P-1)':>10} {'image size':>11} {'(P-1)/gcd':>10} {'orbit period':>13}")96dich_ok=True97for P in (1009,10009):98    n=P-1; g=int(primitive_root(P))99    for k in (2,3,4,6,7):100        img=len(set(pow(x,k,P) for x in range(1,P)))101        pred=n//math.gcd(k,n)102        # iteration orbit r->k^r m mod n (m=1): period103        seen={}; m=1%n; r=0104        while m not in seen:105            seen[m]=r; m=(k*m)%n; r+=1106        period=r-seen[m]107        if img!=pred: dich_ok=False108        print(f"  {P:>6} {k:>3} {math.gcd(k,n):>10} {img:>11} {pred:>10} {period:>13}")109ok("T4", dich_ok, "image size = (P-1)/gcd(k,P-1) exactly (bijection iff gcd=1), and the iteration orbit closes "110   "(eventually periodic) -- the fifth step is a finite counted orbit, not a new primitive role")111112print(f"\nclosure_pnp: all checks passed ({PASS} checks). FINITE throughout, NO random number generator.")113print("RESULT: the arithmetic ladder closes at four roles; the ascent is counting along the orbit of the fourth")114print("(power) role; the one-way function of record (Assumption: scale-descent hardness) is exactly the INVERSE")115print("of that last role -- recovering the count from its orbit position (dlog) -- so the irreversibility is")116print("localised to one step and is not a forbidden primitive but the orbit-position problem.")117