• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#  Copyright 2011 Sybren A. Stüvel <sybren@stuvel.eu>
2#
3#  Licensed under the Apache License, Version 2.0 (the "License");
4#  you may not use this file except in compliance with the License.
5#  You may obtain a copy of the License at
6#
7#      https://www.apache.org/licenses/LICENSE-2.0
8#
9#  Unless required by applicable law or agreed to in writing, software
10#  distributed under the License is distributed on an "AS IS" BASIS,
11#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12#  See the License for the specific language governing permissions and
13#  limitations under the License.
14
15"""Functions for parallel computation on multiple cores.
16
17Introduced in Python-RSA 3.1.
18
19.. note::
20
21    Requires Python 2.6 or newer.
22
23"""
24
25import multiprocessing as mp
26from multiprocessing.connection import Connection
27
28import rsa.prime
29import rsa.randnum
30
31
32def _find_prime(nbits: int, pipe: Connection) -> None:
33    while True:
34        integer = rsa.randnum.read_random_odd_int(nbits)
35
36        # Test for primeness
37        if rsa.prime.is_prime(integer):
38            pipe.send(integer)
39            return
40
41
42def getprime(nbits: int, poolsize: int) -> int:
43    """Returns a prime number that can be stored in 'nbits' bits.
44
45    Works in multiple threads at the same time.
46
47    >>> p = getprime(128, 3)
48    >>> rsa.prime.is_prime(p-1)
49    False
50    >>> rsa.prime.is_prime(p)
51    True
52    >>> rsa.prime.is_prime(p+1)
53    False
54
55    >>> from rsa import common
56    >>> common.bit_size(p) == 128
57    True
58
59    """
60
61    (pipe_recv, pipe_send) = mp.Pipe(duplex=False)
62
63    # Create processes
64    try:
65        procs = [mp.Process(target=_find_prime, args=(nbits, pipe_send))
66                 for _ in range(poolsize)]
67        # Start processes
68        for p in procs:
69            p.start()
70
71        result = pipe_recv.recv()
72    finally:
73        pipe_recv.close()
74        pipe_send.close()
75
76    # Terminate processes
77    for p in procs:
78        p.terminate()
79
80    return result
81
82
83__all__ = ['getprime']
84
85if __name__ == '__main__':
86    print('Running doctests 1000x or until failure')
87    import doctest
88
89    for count in range(100):
90        (failures, tests) = doctest.testmod()
91        if failures:
92            break
93
94        if count % 10 == 0 and count:
95            print('%i times' % count)
96
97    print('Doctests done')
98