clear
len = 0400
e   = prime_gen( hex( 0x$len / 16 ) )
// e    = 010001
x   = new_rsa_genstd( $len, $e )
n   = hmid( $x, 00, hex( 0x$len / 8 ) )
d   = hmid( $x, hex( 0x$len / 8 ) )

// e    = 05
// d    = int2hex(88447120342035329077203801890175181441227843548712394915405983098804986074228491993716303861346713336901472423214577098721961679062412555594462454080858396158886857405021364693424253936899868042331165487633709535319154171592544118785565876198853503758641178366299573880796663815089204345025378660387680199869)

// n    = 9d70ebf2737cb43a7e0ef17b6ce467ab9a116efedbecf1ead94c83e5a082811009100708d690c43c3297b787426b926568a109894f1c48257fc826321177058418e595d16aed5b358d61069150cea832cc7f2df884548f92801606dd3357c39a7ddc868ca8fa7d64d6b64a7395a3247c069112698a365a77761db6b97a2a03a5
// len  = 0400

// 已知
// N = P*Q
// FN = (P-1)*(Q-1)
// 得到
// P*Q- (P-1)*(Q-1) = PQ -(PQ-P-Q+1) = PQ-PQ+P+Q-1 = PQ-1
// 所以
// N - FN + 1 = P + Q
// 所以可构造一个方程组中包含(P+Q),pq,比如(x-p)(x-q)
// = x^2 -px - qx + pq
// = x^2 -(p+q)x + pq

// = x^2 -(n-fn+1)x + n = (x-p)(x-q)
// +----------------------------+
// |  -b +/-sqrt(b^2-4*a*c)     |
// | ------------------------   |
// |          2a                |
// +----------------------------+

// +--------------------------------------------------------+
// |  另一种方法                                            |
// |  看链接 https://www.40huo.cn/blog/get-pq-from-ned.html |
// +--------------------------------------------------------+

step1:
    
inc_indent
        
//   1. let k = de - 1
        k   = big_mul( $d, $e )
        
k   = big_sub( $k, 01 )
        
//   2. write k as k = 2^t * r, where r is the largest odd integer
        //     dividing k, and t >= 1. or
        //     in simpler terms, divide k repeatedly by 2 until you
        //     reach an odd number
        t   = 00
        
r   = $k
step2:
    
inc_indent
        
len = strlen( $r )
        
len = sub( $len, 01 )
        
bit = memgetbit( $r, $len, 00, 00 )
        
if $bit == 00
            
r   = big_div( $r, 02 )
            
t   = add( $t, 01 )
            
goto step2
        
endif

        
//r = big_mod( $r, $n )

step3:
    
inc_indent
        
//   3. for i = 1 to 100 do
        nlen    = strlen( $n )
        
n_1     = big_sub( $n, 01 )
        
one     = hdup( $nlen, 00 )
        
one     = big_add( $one, 01 )
        
success = 00

        
i       = 01
step3_1:
    
inc_indent
        
inc_indent
            
//     a. generate a random interger g in the range[ 0..n-1]
            g       = hrandom( $nlen )
            
g       = big_mod( $g, $n )
            
//     b. let y = g^r mod n
            y       = big_mod_exp( $g, $r, $n )
            
nlen_10 = hex2int( $nlen )
            
y       = leftpack( $y, $nlen_10 )
            
//     c. if y == 1 or y == n-1, then goto step3.1
            if $y == $one
                
goto continue
            
endif
            
if $y == $n_1
                
goto continue
            
endif
            
//     d. for j = 1 to t-1 do
            j   = 01
step_d:
    
inc_indent
        
inc_indent
            
inc_indent

                
//          i. let x = y^2 mod n
                x   = big_mod_mul( $y, $y, $n )
                
x   = leftpack( $x, $nlen_10 )
                
if $x == $one
                    
//      ii. if x == 1 goto(outer)step 5
                    success = 01
                    
goto step5
                
else if $x == $n_1
                    
//      iii. if x == n-1 goto step 3.1

                    
goto continue
                
else
                    
//      iv. let y = x
                    y       = $x
                
endif
                
j   = add( $j, 01 )
                
if $j <= $t
                    
goto step_d
                
endif

                
// g. continue
continue:
    
inc_indent
        
inc_indent

            
i   = add( $i, 01 )
            
if $i <= 0065
                
goto step3_1
            
endif

step4:
    
inc_indent
        
? "prime factors not found"
        
pause


step5:
    
inc_indent

        
if $success == 01
            
y_1     = big_sub( $y, 01 )
            
p       = big_gcd( $y_1, $n )
            
q       = big_div( $n, $p )
            
x       = new_rsa_calculate_other_by_pqe( hex( 0x$nlen * 08 ), $e, $p, $q )
            
len     = div( $nlen, 02 )
            
len     = hex2int( $len )

            
n2      = mid( $x, 0, int( $len * 2 ) )
            
d2      = mid( $x, int( $len * 2 ), int( $len * 2 ) )
            
dp2     = mid( $x, int( $len * 4 ), $len )
            
dq2     = mid( $x, int( $len * 5 ), $len )
            
qinv2   = mid( $x, int( $len * 6 ), $len )

            
if $n != $n2
                
?
                
pause
            
endif
            
if $d != $d2
                
?
                
pause
            
endif
            
            
? "再次使用snooper提供的函数来计算"
            
x = new_rsa_calculate_other_by_nde( hex( 0x$nlen * 08 ), $e, $n, $d )
            
p3      = mid( $x, 0, int( $len ) )
            
q3      = mid( $x, int( $len * 1 ), $len )
            
dp3     = mid( $x, int( $len * 2 ), $len )
            
dq3     = mid( $x, int( $len * 3 ), $len )
            
qinv3   = mid( $x, int( $len * 4 ), $len )
            
            
if $p == $p3
                
? "p = p3"
            
else if $p == $q3
                
? "p = q3"
            
else
                
? "脚本与snooper计算不一致"
                
pause
            
endif
            
if $q == $q3
                
? "q = q3"
            
else if $q == $p3
                
? "q = p3"
            
else
                
? "脚本与snooper计算不一致"
                
pause
            
endif
            
            
? "ok"
        
else
            
? " cannot computer p and q"
        
endif