0

I am using Jupyter notebook from anaconda navigator. I am trying to encrypt (RSA Algorithm) a two-dim NumPy array. While using dtype=np.float128 it is displaying AttributeError: module 'numpy' has no attribute 'float128'

Bmatrix is:

[[ 96 205 325 460 599] [ 13 109 207 307 416] [ 11 24 122 224 333] [ 15 32 53 155 268] [ 4 17 37 68 191]] <class 'numpy.ndarray'>

encrypted_matrix = np.mod(np.power(Bmatrix, 17, dtype=np.float64), 703)
print(encrypted_matrix)

[[153. 142. 445. 120. 28.] [ 11. 296. 567. 125. 128.] [ 53. 612. 216. 166. 511.] [366. 459. 365. 21. 360.] [176. 106. 564. 378. 560.]]

Expected output: [[153 394 162 81 534] [535 167 560 545 218] [64 612 582 166 629] [698 459 451 127 181] [176 161 37 216 191]]

Albert Einstein
  • 7,472
  • 8
  • 36
  • 71
  • Does https://stackoverflow.com/questions/8514565/numpy-matrix-power-exponent-with-modulo help? It has some suggesstions to circumvent overflow – FlyingTeller Jul 14 '23 at 09:21
  • 2
    Is there a reason why you use float instead of integer datatypes? With `pow` and `mod` of integers, I would expect that you only get integers – FlyingTeller Jul 14 '23 at 09:21
  • You need to use or write a [modular exponentiation implementation](https://en.wikipedia.org/wiki/Modular_exponentiation). It should only take a few lines of code to do so. – President James K. Polk Jul 14 '23 at 12:43
  • Why use an undocumented dtype? And ignore the good answer to your previous question? – hpaulj Jul 14 '23 at 15:10

3 Answers3

0

From the official page:

https://numpy.org/doc/stable/user/basics.types.html

I am quoting: "NumPy does not provide a type with more precision than C’s long double; in particular, the 128-bit IEEE quad precision data type (FORTRAN’s REAL*16) is unavailable."

You'll have to use another workaround, put it in 2 64 bits floats maybe.

Rafael
  • 1
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 17 '23 at 11:48
0

Two solutions.

One is not to use numpy, since numpy numbers are limited. So just to it with pure python's int (that are big int)

# That's your matrix. But I had to add all the comas myself. That is painful. 
# Please, next time, post a minimal reproducible example. You get less help
# when you make the life of people who might help you more difficult
B=[[ 96, 205, 325, 460, 599], [ 13, 109, 207, 307, 416], [ 11, 24, 122, 224, 333], [ 15, 32, 53, 155, 268], [ 4, 17, 37, 68, 191]]

Bpow17 = [[x**17 for x in line] for line in B]
Bpow17mod703 = [[x%703 for x in line] for line in Bpow17]

# Or, in one line
Res=[[(x**17)%703 for x in line] for line in B]

Or, if you insist on using numpy, then you must ensure that you never overflow the size of an int. (If using floats, overflow is even easier, even it it takes another form. It is not that you exactly overflow, since maximum value is way bigger that int type of same size. But it is accuracy that goes down when values go up. Up to a point where accuracy cannot even ensure integer values. And the number of exact integer float64 is able to encode is lower than the number of exact integer you can encode with int64. So don't use float just because theoretical maximum value is bigger, when you need exact int values. That is not, in your case the tradeoff "bigger values in exchange for smaller accuracy". Is is "bigger values in exchange of it doesn't work".)

But even with ints, **17 will overflow.

So the trick is never compute such values as 96**17 % 703 directly.

The trick with modulo arithmetics, is that a*b≡c[703] iff a'≡a[703] and b'≡b[703] and a'*c'≡c[703].

For example 1051*2344%703 is 232. But 1051%703 is 348 and 2344%703 is 235. So 348*235%703 is also 232.

So, same result. But operation is done with smaller values. So less risk of overflow (in the direct case, it uses 2463544 intermediary result, if computing %703 before, bigger intermediary result is 81780)

So, in practice, with numpy, you could compute this

B=np.array([[ 96, 205, 325, 460, 599], [ 13, 109, 207, 307, 416], [ 11, 24, 122, 224, 333], [ 15, 32, 53, 155, 268], [ 4, 17, 37, 68, 191]], dtype=np.uint32)
# Note: I could skip the dtype since by default, numpy would create a `int64` array. 
# But I prefer explicit. Plus, I use `int32` to further demontrate how this avoid
# yet even easier overflow

B2=B**2%703
B4=B2**2%703
B8=B4**2%703
B16=B8**2%703
B17=B16*B%703

Result is the expected one.

You can generalize that to other values

def powmod(M, p, m):
   if p==1: return M%m
   X=powmod(M, p//2, m)
   if p%2:
      return X*X*M%m
   else:
      return X*X%m
chrslg
  • 9,023
  • 5
  • 17
  • 31
  • Thank you so much for your invaluable help! Your guidance and support made a significant difference, and I'm truly grateful for your time and effort. Your expertise and willingness to assist have been instrumental in resolving my concerns. Once again, thank you for your kindness and assistance. – Dr Simhachalam Jul 20 '23 at 11:03
0

I'll just add another solution, without providing code: research modular arithmetic. Note that modular multiplication already doesn't require a full multiplication to be performed. You know this because you can calculate (625 x 3405) % 10 = 5 without touching most of the digits. There are similar tricks to perform modular exponentiation which is used in RSA. These kind of functions will not expand the values to anything (much) higher than the modulus.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263