nomoresecrets

Pythagorean Factorization Plagiarized

Aug 25th, 2024
169
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 32.32 KB | None | 0 0
  1. """
  2. Quick ~1000 line proof to show Pythagorean Factorization is just masked Fermat's
  3. Factorization Algorithm.
  4.  
  5. In the absence of reference implementation, here is the best-effort replication
  6. of the Pythagorean Factorization, based on the author Robert Edward Grant's
  7. illustration (https://archive.is/nN5Ai):
  8. """
  9. import math
  10.  
  11. def pythagorean_factorization(semiprime: int):
  12.     B = math.sqrt(semiprime)
  13.     r = math.ceil(B) - B
  14.     x = 0
  15.     while True:
  16.         # Solve leg A with the formula in Grant's image
  17.         A = math.sqrt((x + r) * (2 * B + (x + r)))
  18.  
  19.         # Note: In Grant's illustration, the 'ready-to-use'
  20.         # formula for solving A is missing the square root
  21.         # used above, but it is present in the bottom right
  22.         # of the image, where A=24 is obtained with sqrt(576).
  23.  
  24.         C = round(math.sqrt(A ** 2 + B ** 2))
  25.  
  26.         PRIME1 = round(C - A)
  27.         PRIME2 = round(C + A)
  28.  
  29.         if PRIME1 * PRIME2 == semiprime:
  30.             return PRIME1, PRIME2
  31.  
  32.         x += 1
  33.  
  34.  
  35. """
  36. Below is a 2013 implementation of Fermat's Factorization Algorithm from the
  37. 1700th century. The implementation precedes Grant's supposed algorithm by seven
  38. years. It can be found at https://stackoverflow.com/a/20465181
  39. """
  40. def isqrt(n):
  41.     x = n
  42.     y = (x + n // x) // 2
  43.     while y < x:
  44.         x = y
  45.         y = (x + n // x) // 2
  46.     return x
  47.  
  48. def fermat(n, verbose = True):
  49.     a = isqrt(n)  # int(ceil(n**0.5))
  50.     b2 = a * a - n
  51.     b = isqrt(n)  # int(b2**0.5)
  52.     count = 0
  53.     while b * b != b2:
  54.         if verbose:
  55.             print('Trying: a=%s b2=%s b=%s' % (a, b2, b))
  56.         a = a + 1
  57.         b2 = a * a - n
  58.         b = isqrt(b2)  # int(b2**0.5)
  59.         count += 1
  60.     p = a + b
  61.     q = a - b
  62.     return p, q
  63.  
  64.  
  65. """
  66. To show Grant's Pythagorean Factorization is the exact same algorithm as
  67. Fermat's factorization algorithm, we can compare the number of steps and see
  68. that they indeed take an equal number for each input, but we can also do this
  69. mathematically and just move things around and show they're equivalent.
  70.  
  71. We're going to do that in four parts.
  72.    1. Clean unnecessary stuff from Fermat implementation's code
  73.    2. Switch to using the same variable names
  74.    3. Make the Fermat's algorithm more readable
  75.    4. Show that the algorithms are the same, and that Grant is just obfuscating
  76.       his plagiarism
  77. """
  78.  
  79.  
  80. # Part I - Cleaning the code
  81.  
  82.  
  83. """
  84. Let's start by
  85.  
  86. * removing the `isqrt` function from above, as it's just an implementation of
  87.  math.isqrt, which we can import from the math library,
  88.  
  89. * removing the code comments (trailing stuff that starts with '#'),
  90.  
  91. * removing the
  92.    if verbose:
  93.        print('Trying: a=%s b2=%s b=%s' % (a, b2, b))
  94.  part as unnecessary,
  95.  
  96. * removing the lines
  97.      count = 0
  98.  and
  99.      count +=1
  100.  for now, as we're not analyzing the algorithm's efficiency, just yet.
  101.  
  102. After every change description like this, the code below will reflect the
  103. changes.
  104. """
  105. from math import isqrt
  106.  
  107. def version1(n):
  108.     a = isqrt(n)
  109.     b2 = a * a - n
  110.     b = isqrt(n)
  111.  
  112.     while b * b != b2:
  113.         a = a + 1
  114.         b2 = a * a - n
  115.         b = isqrt(b2)
  116.  
  117.     p = a + b
  118.     q = a - b
  119.     return p, q
  120.  
  121.  
  122. """
  123. The line
  124.    from math import isqrt
  125. doesn't need to be done again and again so we'll leave it here at the top of
  126. this document.
  127. """
  128.  
  129.  
  130. # Part II - Switch to using the same variable names
  131.  
  132.  
  133. """
  134. Next, let's swap some names of variables so that they match those of the
  135. Pythagorean Factorization.
  136.  
  137. Since finding the prime factors `p` and `q` have identical final steps in both
  138. algorithms, we can identify some variable names to change.
  139.  
  140.      Fermat  |     Grant
  141.    ---------------------------
  142.    p = a+b   |  PRIME2 = C + A
  143.    q = a-b   |  PRIME1 = C - A
  144.  
  145. So, let's change:
  146.    p → PRIME2
  147.    q → PRIME1
  148.    a → C
  149.    b → A
  150.  
  151. The parameter `n` is the semiprime that Grant incorrectly calls the
  152. "public key".
  153.  
  154. An RSA public key consists of two parts
  155.    1) the modulus (n), that is the semiprime (product of two large primes
  156.       numbers), and
  157.    2) a public exponent, usually 65537.
  158.  
  159. But since breaking the public key is about finding the factors of the modulus,
  160. we'll just ignore this as another instance of "Grant has never read a book on
  161. the topic".
  162.  
  163. In Grant's illustration, the side B of the right triangle is the square root of
  164. the modulus `n`. So,
  165.    B² = n
  166. and thus,
  167.    B = √(n)
  168.  
  169. To make the variables in the algorithm easier to recognize, we'll change them
  170. to lowercase.
  171.  
  172. We'll also agree on a notation that capitalized letters represent squares of
  173. the legs and the hypotenuse, i.e.
  174.    A = a²
  175.    B = b²
  176.    C = c²
  177.  
  178.  
  179.    ^                                           ^
  180.    | \                                        | \
  181.    |  \                                       |  \
  182.    |   \                                      |   \
  183.    |    \                                     |    \
  184.    |     \                                    |     \
  185.    |      \                                   |      \
  186.    |       \ C                                |       \ c
  187. B  |        \                  🡆          b  |        \
  188.    |         \                                |         \
  189.    |          \                               |          \
  190.    |           \                              |           \
  191.    |            \                             |            \
  192.    |             \                            |             \
  193.    |              \                           |              \
  194.    |_______________\                          |_______________\
  195.            A                                           a
  196.  
  197.    Grant's triangle                            New variable names
  198.  
  199.  
  200. Pythagorean theorem respectively
  201.  
  202.      A² + B² = C²                🡆               a² + b² = c²
  203.  
  204.                                            (or)   A  + B  = C    (as upper case
  205.                                                                   represents
  206.                                                                   square value)
  207.  
  208. With the new syntax, now
  209.    b² = n
  210. that is,
  211.    B  = n
  212.  
  213. We thus know `n` represents a square of the longer leg in Grant's illustration,
  214. and we can replace `n` with `B` in the algorithm.
  215.  
  216. That together with demoting the original `A` and `C` to `a` and `c`, gives us
  217. """
  218. def version2(B):
  219.     c = isqrt(B)
  220.     b2 = c * c - B
  221.     a = isqrt(B)
  222.  
  223.     while a * a != b2:
  224.         c = c + 1
  225.         b2 = c * c - B
  226.         a = isqrt(b2)
  227.  
  228.     PRIME2 = c + a
  229.     PRIME1 = c - a
  230.     return PRIME2, PRIME1
  231.  
  232.  
  233. """
  234. Next, let's fix the wonky variable name `b2`.
  235.  
  236. As per Pythagoras,
  237.    a² + b² = c²
  238. we can subtract b² from both sides and get
  239.    a² = c² - b²
  240.  
  241. The middle statement inside the while loop says
  242.    b2 = c * c - B
  243. or
  244.    b2 =   c²  - b²
  245. we thus now know that
  246.    b2 = a² = A,
  247.  
  248. and we can replace `b2` with `A`.
  249.  
  250. Let's also swap the order of PRIME2 and PRIME1 as it's annoying PRIME2 is listed
  251. first.
  252. """
  253. def version3(B):
  254.     c = isqrt(B)
  255.     A = c * c - B
  256.     a = isqrt(B)
  257.  
  258.     while a * a != A:
  259.         c = c + 1
  260.         A = c * c - B
  261.         a = isqrt(A)
  262.  
  263.     PRIME1 = c - a
  264.     PRIME2 = c + a
  265.     return PRIME1, PRIME2
  266.  
  267.  
  268. """
  269. All variable names are now replaced.
  270. """
  271.  
  272.  
  273. # PART III - Make the Fermat's algorithm more readable
  274.  
  275. """
  276. Next, let's swap the places of the two first lines in the function
  277.    A = c * c - B
  278.    a = isqrt(B)
  279. to better show `a` and `c` are set to the same variable.
  280. """
  281. def version4(B):
  282.     c = isqrt(B)
  283.     a = isqrt(B)
  284.     A = c * c - B
  285.  
  286.     while a * a != A:
  287.         c = c + 1
  288.         A = c * c - B
  289.         a = isqrt(A)
  290.  
  291.     PRIME1 = c - a
  292.     PRIME2 = c + a
  293.     return PRIME1, PRIME2
  294.  
  295.  
  296. """
  297. Next, let's ensure we can use capitalized letters without adding lines. This is
  298. done by setting a new variable on the same line. We can separate a new statement
  299. from the previous one in Python with the `;` symbol.
  300.  
  301. This allows us to define `C` immediately when we know `c`, by doing
  302.         ; C = c*c
  303. on the same line, we define `c`, e.g.,
  304.    c = isqrt(B)                        ; C = c*c
  305.  
  306. We'll use that below, and we can then use C in place of c*c. We'll just have to
  307. reassign `C` every time `c` updates.
  308. """
  309. def version5(B):
  310.     c = isqrt(B)                        ; C = c * c
  311.     a = isqrt(B)
  312.     A = C - B
  313.  
  314.     while a * a != A:
  315.         c = c + 1                       ; C = c * c
  316.         A = C - B
  317.         a = isqrt(A)
  318.  
  319.     PRIME1 = c - a
  320.     PRIME2 = c + a
  321.     return PRIME1, PRIME2
  322.  
  323.  
  324. """
  325. Next, we can combine the lines
  326.    A = C - B
  327.    a = isqrt(A)
  328. to
  329.    a = isqrt(C - B)
  330.  
  331. This allows us to see the connection to the Pythagorean theorem, where
  332.    a = √(C - B)
  333. or
  334.    a² = c² - b²      (for reference, the Pythagorean theorem is a² + b² = c²)
  335. """
  336. def version6(B):
  337.     c = isqrt(B)                        ; C = c * c
  338.     a = isqrt(B)
  339.     A = C - B
  340.  
  341.     while a * a != A:
  342.         c = c + 1                       ; C = c * c
  343.         a = isqrt(C - B)
  344.  
  345.     PRIME1 = c - a
  346.     PRIME2 = c + a
  347.     return PRIME1, PRIME2
  348.  
  349.  
  350. """
  351. Finally, we can replace the while loop condition's `A` with `C-B` to help us
  352. understand the solution detection condition. This also allows us to remove the
  353. third line of the function
  354.    A = C - B
  355. as `A` is no longer needed.
  356. """
  357. def version7(B):
  358.     c = isqrt(B)                        ; C = c * c
  359.     a = isqrt(B)
  360.  
  361.     while a * a != C - B:
  362.         c = c + 1                       ; C = c * c
  363.         a = isqrt(C - B)
  364.  
  365.     PRIME1 = c - a
  366.     PRIME2 = c + a
  367.     return PRIME1, PRIME2
  368.  
  369.  
  370. """
  371. At this point, we have made Fermat's algorithm as readable as possible.
  372.  
  373. The algorithm performs the following steps:
  374.    1. Assume leg `a` and hypotenuse `c` are both the integer square root of B,
  375.       the modulus.
  376.           An integer square root will first calculate a normal square root to
  377.       get an accurate decimal approximation, and it then rounds it down to the
  378.       next integer. To compare with normal square root:
  379.           sqrt(5) = 2.2360679...
  380.           isqrt(5) = 2
  381.    2. Raise the integer square root `a` to the second power and see if it
  382.       completes the Pythagorean theorem
  383.           a*a = C  - B
  384.           a²  = c² - b²        
  385.  
  386.    3. Enter a `while` -loop with `x != y` condition. It means the loop
  387.       continues as long as `x` and `y` are not equal. Inside the loop
  388.        a) Increase the hypotenuse `c` by 1 to get a new hypotenuse candidate.
  389.        b) Uses isqrt to get new leg `a` candidate from known leg `b`
  390.              a = isqrt(c² - b²)
  391.        c) Jump back to check if the new `a`, when squared, completes the
  392.           Pythagorean theorem for the triangle. The check
  393.              a² == c² - b² ?
  394.           will remain False, i.e. still not equal, for quite some time,
  395.           so it jumps back to step a) to increase `c` by one. Trying all values
  396.           (of `c`) is called brute forcing, and it's the worst efficiency an
  397.           attack can have. It's essentially the "try all keys" method.
  398.  
  399.        Once the a*a will equal c² - b², the loop exits. At this point, it knows
  400.          * `c`, the hypotenuse, is the middle point between the two primes.
  401.          * `a`, the bottom side leg, is the distance of primes from the center.
  402.  
  403.    4. Calculate the prime factors with
  404.           PRIME2 = c + a
  405.           PRIME1 = c - a
  406.  
  407.    6. Return the prime factors to the user.
  408. """
  409.  
  410.  
  411. # Part IV - Plagiarism
  412.  
  413.  
  414. """
  415.  
  416. Fermat's algorithm describes the factoring method beautifully. But being so
  417. simple, plagiarizing is trivial to detect. Its nature of brute forcing the
  418. hypotenuse one integer at a time immediately shows its time complexity is 𝒪(√n).
  419.  
  420. But we need to plagiarize the algorithm to attract fame and suckers. So, we
  421. can turn to our buddy, Nassim Haramein for advice. Nassim has a long history
  422. of obfuscating existing math by replacing variables and moving things around:
  423.    https://youtu.be/_W2WBeqGNM0?si=v_QiR5um05k1xaYp&t=1884
  424.  
  425. So let's obfuscate the algorithm by brute-forcing the leg `a` instead of brute-
  426. forcing the hypotenuse `c`. Since leg `b` is already known, we can't do much
  427. else anyway.
  428.  
  429. To do that, we need to remove our guess for `a`, i.e. the second line
  430.    a = isqrt(B)
  431.  
  432. (At this stage the algorithm won't work, so we'll denote these intermediate,
  433. temporarily broken factoring implementations with a "_broken"-suffix.)
  434.  
  435. We'll also comment out the broken versions with '#' chars so they won't cause
  436. issues if this file is opened in a code editor.
  437. """
  438. # def version8_broken(B):
  439. #     c = isqrt(B)                      ; C = c*c
  440. #
  441. #     while a * a != C - B:
  442. #         c = c + 1                     ; C = c*c
  443. #         a = isqrt(C - B)
  444. #
  445. #     PRIME1 = c - a
  446. #     PRIME2 = c + a
  447. #     return PRIME1, PRIME2
  448.  
  449.  
  450. """
  451. The first trouble is, we need `a` immediately in the while loop condition. So
  452. let's move the brute-force-is-done check
  453.    a * a != C - B
  454. inside the loop. Since our while loop continued as long as there was an
  455. inequality, an if-statement checking for the condition inside the while loop
  456. must check for equality, to know when to `break` from the loop.
  457.  
  458. The while loop's condition is changed to `True` so that the while loop's
  459. condition check itself never terminates the loop.
  460. """
  461. # def version9_broken(B):
  462. #     c = isqrt(B)                      ; C = c*c
  463. #
  464. #     while True:
  465. #         c = c + 1                     ; C = c*c
  466. #         a = isqrt(C - B)
  467. #
  468. #         if a * a == C - B:
  469. #             break
  470. #
  471. #     PRIME2 = c + a
  472. #     PRIME1 = c - a
  473. #     return PRIME2, PRIME1
  474.  
  475. """
  476. Since we're no longer using the first `C` in first ;-separated `C = c*c`, we can
  477. delete that.
  478. """
  479. # def version10_broken(B):
  480. #     c = isqrt(B)
  481. #
  482. #     while True:
  483. #         c = c + 1                     ; C = c*c
  484. #         a = isqrt(C - B)
  485. #
  486. #         if a * a == C - B:
  487. #             break
  488. #
  489. #     PRIME1 = c - a
  490. #     PRIME2 = c + a
  491. #     return PRIME1, PRIME2
  492.  
  493.  
  494. """
  495. Next, to simplify, we can move the prime-forming to below the if-condition, and
  496. return factors from the loop immediately after obtaining them.
  497. """
  498. # def version11_broken(B):
  499. #     c = isqrt(B)
  500. #
  501. #     while True:
  502. #         c = c + 1                     ; C = c*c
  503. #         a = isqrt(C - B)
  504. #
  505. #         if a * a == C - B:
  506. #             PRIME1 = c - a
  507. #             PRIME2 = c + a
  508. #             return PRIME1, PRIME2
  509.  
  510.  
  511. """
  512. We've now solved the problem of `a` missing from the initial loop break
  513. condition check. But we have another problem.
  514.  
  515. This algorithm immediately increases `c` by 1. Thus, it will jump over some
  516. solutions if prime factors are very close to one another.  
  517.  
  518. But thanks to the Pythagorean theorem, we can find `c` from `b` with `a`, as
  519.    c = sqrt(a² + b²)
  520.  
  521. That means we can delete the entire line
  522.    c = c + 1                     ; C = c*c
  523.  
  524. And replace it with
  525.    c = sqrt(a² + B).
  526. Raising to exponents in Python is done with '**' operator, so we do
  527.    c = sqrt(a**2 + B)
  528.  
  529. """
  530. # from math import sqrt
  531. #
  532. # def version12_broken(B):
  533. #     c = isqrt(B)
  534. #
  535. #     while True:
  536. #         a = isqrt(C - B)
  537. #         c = sqrt(a**2 + B)
  538. #
  539. #         if a * a == C - B:
  540. #             PRIME1 = c - a
  541. #             PRIME2 = c + a
  542. #             return PRIME1, PRIME2
  543.  
  544.  
  545. """
  546. Since we can't get `a` candidate with
  547.    a = isqrt(C - B)
  548. any more, we'll delete the line.
  549. """
  550. # def version13_broken(B):
  551. #     c = isqrt(B)
  552. #
  553. #     while True:
  554. #         c = sqrt(a ** 2 + B)
  555. #
  556. #         if a * a == C - B:
  557. #             PRIME1 = c - a
  558. #             PRIME2 = c + a
  559. #             return PRIME1, PRIME2
  560.  
  561.  
  562. """
  563. And now the top row
  564.    c = isqrt(B)
  565. has become useless, so we remove it too.
  566. """
  567. # def version14_broken(B):
  568. #
  569. #     while True:
  570. #         c = sqrt(a ** 2 + B)
  571. #
  572. #         if a * a == C - B:
  573. #             PRIME1 = c - a
  574. #             PRIME2 = c + a
  575. #             return PRIME1, PRIME2
  576.  
  577.  
  578. """
  579. Next, let's figure out how to solve `a` without `c`.
  580.  
  581. The algorithm's exit condition is already
  582.    A  = C  - B
  583.    a² = c² - b²
  584.  
  585. Now, as per difference of squares ( https://en.wikipedia.org/wiki/Difference_of_two_squares ):
  586.    a²-b² = (a+b)(a-b)
  587. Thus, we can substitute
  588.    c² - b²
  589. on the right with
  590.    (b+c)(c-b)
  591. and get
  592.    a² = (b+c)(c-b)
  593. and since multiplication is commutative, we can change the order to
  594.    a² = (c-b)(b+c)
  595.  
  596. Let's then add some spaces
  597.    a² = (c-b)(b  +  c   )
  598.  
  599. And then use a bit of mathematical
  600. intuition, and add `b-b` (which is 0) to the right side.
  601.                                             ↓
  602.    a² = (c-b)(b  + b-b + c   )
  603.  
  604. Let's then rearrange the terms to get another c-b out:
  605.    a² = (c-b)(b+b       -b +c )
  606.    a² = (c-b)(2b        + c-b )
  607.                           ---
  608.  
  609. Now, let's replace the c-b with two new variables, Blonk and Blorp:
  610.    https://youtu.be/_W2WBeqGNM0?si=v_QiR5um05k1xaYp&t=1884
  611.  
  612. Let's define
  613.    c-b = x+r
  614.  
  615. Now
  616.    a² =    (c-b)(2b + (c-b))
  617. becomes
  618.    a² =    (x+r)(2b + (x+r))
  619.    a  = √( (x+r)(2b + (x+r)) )
  620.  
  621. And we're done. We have solved for `a` without `c`.
  622.  
  623. We can add this as
  624.    a = sqrt( (x+r) * (2*b + (x+r)) )
  625. """
  626. # def version15_broken(B):
  627. #
  628. #     while True:
  629. #         a = sqrt( (x+r) * (2*b + (x+r)) )
  630. #         c = sqrt(a ** 2 + B)
  631. #
  632. #         if a * a == C - B:
  633. #             PRIME1 = c - a
  634. #             PRIME2 = c + a
  635. #             return PRIME1, PRIME2
  636.  
  637.  
  638. """
  639. Now we notice that we are missing three variables, `x`, `r`, and `b`. Of these,
  640. `b` is the easy one, it's just √B. So we'll start with that, and add
  641.    b = sqrt(B)
  642. to the beginning.
  643. """
  644. # def version16_broken(B):
  645. #     b = sqrt(B)
  646. #
  647. #     while True:
  648. #         a = sqrt( (x+r) * (2*b + (x+r)) )
  649. #         c = sqrt(a ** 2 + B)
  650. #
  651. #         if a * a == C - B:
  652. #             PRIME1 = c - a
  653. #             PRIME2 = c + a
  654. #             return PRIME1, PRIME2
  655.  
  656.  
  657. """
  658. Next, let's change the way we check for completeness. We'll first get the prime
  659. candidates without the check, and then see if the two prime factors, when
  660. rounded as integers produce the semiprime B.
  661. """
  662. # def version17_broken(B):
  663. #     b = sqrt(B)
  664. #
  665. #     while True:
  666. #         a = sqrt((x + r) * (2 * b + (x + r)))
  667. #         c = sqrt(a ** 2 + B)
  668. #
  669. #         PRIME1 = round(c - a)
  670. #         PRIME2 = round(c + a)
  671. #         if PRIME1 * PRIME2 == B:
  672. #             return PRIME1, PRIME2
  673.  
  674.  
  675. """
  676. Next, let's solve r. Since the
  677.    a² + b² = c²
  678. only works with integers when the solution is correct, `r` will simply serve as
  679. a value that rounds the irrational value b = √B, to the next integer.
  680.  
  681. For this, we need what's called a ceiling function, which rounds to the next
  682. integer. The ceiling function is denoted with ⌈ and ⌉, and e.g. ⌈5.1⌉ = 6.
  683. In Python, the equivalent is math.ceil(5.1).
  684.  
  685. So
  686.    √B + r = ⌈√B⌉
  687. is thus
  688.         r = ⌈√B⌉ - √B
  689.  
  690. Or in Python,
  691.    from math import ceil
  692. #  (r =     ⌈   √ B ⌉ -    √ B)
  693.    r = ceil(sqrt(B)) - sqrt(b)
  694.  
  695. And since we already calculated
  696.    b = sqrt(B)
  697. on the first line of the function, we can get r with
  698.    r = ceil(b) - b
  699.  
  700. Which is what Grant did in his illustration.
  701. """
  702. # def version18_broken(B):
  703. #     b = sqrt(B)
  704. #     r = ceil(b) - b
  705. #
  706. #     while True:
  707. #         a = sqrt((x + r) * (2 * b + (x + r)))
  708. #         c = sqrt(a ** 2 + B)
  709. #
  710. #         PRIME1 = round(c - a)
  711. #         PRIME2 = round(c + a)
  712. #         if PRIME1 * PRIME2 == B:
  713. #             return PRIME1, PRIME2
  714.  
  715.  
  716. """
  717. Now, because we're incompetent or malicious (pick your poison), we will remove
  718. the square root from our formula for solving `a`:
  719.    a = sqrt((x + r) * (2 * b + (x + r)))
  720. becomes
  721.    a =      (x + r) * (2 * b + (x + r))
  722.  
  723. This is the state in which Grant was peddling the algorithm to his viewers.
  724. """
  725. # from math import sqrt, ceil
  726. #
  727. # def version19_broken(B):
  728. #     b = sqrt(B)
  729. #     r = ceil(b) - b
  730. #
  731. #     while True:
  732. #         a = (x + r) * (2 * b + (x + r))
  733. #         c = sqrt(a ** 2 + B)
  734. #
  735. #         PRIME1 = round(c - a)
  736. #         PRIME2 = round(c + a)
  737. #         if PRIME1 * PRIME2 == B:
  738. #             return PRIME1, PRIME2
  739.  
  740.  
  741. """
  742. Intentional or not, removing the square root means the algorithm isn't working.
  743.  
  744. Also, he didn't explain where x comes from, he just baked its value (2) into the
  745. image:
  746.    https://archive.is/nN5Ai
  747. The reason x is so small is he intentionally used an invalid RSA key where the
  748. prime factors are practically next to one another.
  749.  
  750. The reader who manages to follow the steps in Grant's illustration with no
  751. beginning or end will fail to notice that the description "x is a whole number"
  752. is doing a LOT of lifting, that is, trillions and trillions of super-computing
  753. years' worth of 'lifting'. Finding the right `x` is the key to factoring numbers
  754. with this algorithm. It's the number of brute force steps. And unlike the
  755. illustration implies, it's never, ever 2. For average-size RSA keys (3072 bits),
  756. it's verified by key generation algorithms to be at least
  757.  
  758.    2^((3072/2)-100)) = \
  759.        19014012429663796324419459331224055645026991688903
  760.        74749247369562864802585451004209832696515053742316
  761.        84659417885497720016514658819276907584086181741652
  762.        52126912455130430925740762843286365008491375209869
  763.        58696226722405264137600414778995896732994290595012
  764.        11878942986520479340011031387572153845034397193548
  765.        21112051579461663487198093927294533414503946670529
  766.        27912914855801753338166857982316138938427044449697
  767.        165870468846196415120486732660736
  768.  
  769. To put that number into perspective, Frontier, the world's most powerful
  770. super-computer could run the x only up until roughly
  771.    265000000000000000000000000000000000
  772. before our Sun runs out of fuel, in 5 billion years.
  773.  
  774. ---
  775. Before we close out, all that's left for us to do now is put back the square
  776. root to solve for `a`, and add the `x` brute force to the algorithm, and count
  777. the steps.
  778.  
  779. The Fermat implementation also has a variable `count` that counts the number of
  780. iterations of the while loop.
  781.  
  782. In Grant's variation, `x` will also conveniently count the number of steps for
  783. us. Since we're checking for exit-condition inside the loop, we must make sure
  784. to increment `x` before the if-statement to get correct results, and since we're
  785. starting from 0, we also return x + 1 to get the steps.
  786.  
  787. This allows us to verify the performance is identical to that of
  788. the original.
  789. """
  790. from math import sqrt, ceil
  791.  
  792. def grant(B):
  793.     b = sqrt(B)
  794.     r = ceil(b) - b
  795.     x = 0
  796.     while True:
  797.         a = sqrt((x + r) * (2 * b + (x + r)))
  798.         c = sqrt(a ** 2 + B)
  799.         x = x + 1
  800.         PRIME1 = round(c - a)
  801.         PRIME2 = round(c + a)
  802.         if PRIME1 * PRIME2 == B:
  803.             return PRIME1, PRIME2, x + 1
  804.  
  805. def fermat2(n):
  806.     a = isqrt(n)
  807.     b2 = a * a - n
  808.     b = isqrt(n)
  809.     count = 0
  810.     while b * b != b2:
  811.         a = a + 1
  812.         b2 = a * a - n
  813.         b = isqrt(b2)  # int(b2**0.5)
  814.         count += 1
  815.     p = a + b
  816.     q = a - b
  817.     return p, q, count + 1
  818.  
  819.  
  820. if __name__ == '__main__':
  821.     import random
  822.  
  823.     # The first 1000 primes to help us generate moduli below. Keep scrolling :)
  824.     primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
  825.               61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131,
  826.               137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
  827.               199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271,
  828.               277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353,
  829.               359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433,
  830.               439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
  831.               521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
  832.               607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677,
  833.               683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769,
  834.               773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859,
  835.               863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953,
  836.               967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
  837.               1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103,
  838.               1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193,
  839.               1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279,
  840.               1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361,
  841.               1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447,
  842.               1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511,
  843.               1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597,
  844.               1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667,
  845.               1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753,
  846.               1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861,
  847.               1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933,
  848.               1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017,
  849.               2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099,
  850.               2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203,
  851.               2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281,
  852.               2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357,
  853.               2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437,
  854.               2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543,
  855.               2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647,
  856.               2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707,
  857.               2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789,
  858.               2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861,
  859.               2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963,
  860.               2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061,
  861.               3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169,
  862.               3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257,
  863.               3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343,
  864.               3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449,
  865.               3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529,
  866.               3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607,
  867.               3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691,
  868.               3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779,
  869.               3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877,
  870.               3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947,
  871.               3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051,
  872.               4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139,
  873.               4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241,
  874.               4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337,
  875.               4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441,
  876.               4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519,
  877.               4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637,
  878.               4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721,
  879.               4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801,
  880.               4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931,
  881.               4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999,
  882.               5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087,
  883.               5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189,
  884.               5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297,
  885.               5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407,
  886.               5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479,
  887.               5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569,
  888.               5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659,
  889.               5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749,
  890.               5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849,
  891.               5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927,
  892.               5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053,
  893.               6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143,
  894.               6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247,
  895.               6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323,
  896.               6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397,
  897.               6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547,
  898.               6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637,
  899.               6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719,
  900.               6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827,
  901.               6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911,
  902.               6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997,
  903.               7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109,
  904.               7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213,
  905.               7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321,
  906.               7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457,
  907.               7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537,
  908.               7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603,
  909.               7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699,
  910.               7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817,
  911.               7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907,
  912.               7919]
  913.  
  914.     rng = random.SystemRandom()
  915.     N   = rng.choice(primes) * rng.choice(primes)
  916.  
  917.     p1, q1, count1 = fermat2(N)
  918.     p2, q2, count2 = grant(N)
  919.  
  920.     print(f"Fermat's algo:                   p={p1}, q={q1}, steps={count1}")
  921.     print(f"Fermat's algo (Grant's variant): p={p2}, q={q2}, steps={count2}")
  922.  
  923.     # No matter how many times this code is executed, the
  924.     # application will always yield the same number of steps.
  925.  
  926.  
  927. """
  928. The plagiarism
  929. --------------
  930.  
  931. The only difference between these two algorithms was that Grant went out of his
  932. way to solve for leg `a`, instead of just increasing `c`, the hypotenuse, by one
  933. at a time.
  934.  
  935. Fermat's method is much more readable and understandable. Grant never explained
  936. how he got his weird formula to solve `a`:  
  937.    a = √( (x+r) (2b + (x+r)) )
  938.  
  939. The most likely answer is that he derived it the way we showed above, or one of
  940. his grifter buddies, our guess being Nassim Haramein or Talal Ghannam, helped
  941. him obfuscate Fermat's algorithm.  
  942.  
  943. This is, again, exactly what Nassim Haramein has been doing, and considering
  944. Grant and Haramein are acquainted from another new-age grift called Resonance
  945. Science Foundation, it wouldn't be surprising if this was intentional,
  946. collaborated obfuscated plagiarism.
  947.  
  948. Further evidence of this behavior is, that Grant also earlier, in 2019, hosted a
  949. press conference where he used a camouflaged version of CADO-NFS, an open-source
  950. factoring algorithm. This couldn't be even considered forking, because they did
  951. not state they were using the General Number Field Sieve algorithm that CADO-NFS
  952. uses, they claimed the software used their algorithm, called
  953.    "CS BiPrime Algorithm (ver. 1.1.)".
  954.  
  955. Again, Grant never described where he got the formula to derive a with. If one
  956. would argue he's so competent it just comes to him, then how was he also so
  957. incompetent he forgot to include the outermost square root when solving `a`,
  958. and why did he claim this algorithm runs in constant time when it famously runs
  959. in 𝒪(√n) time? And why wasn't the algorithm ever released as code?
  960.  
  961. The answer should be obvious by now.
  962. """
  963.  
Advertisement
Add Comment
Please, Sign In to add comment