1 //
2 // Copyright (c) 2010-2022 Antmicro
3 //
4 //  This file is licensed under the MIT License.
5 //  Full license text is available in 'licenses/MIT.txt'.
6 //
7 using System;
8 using System.Linq;
9 using System.Numerics;
10 using Antmicro.Renode.Utilities;
11 
12 namespace Antmicro.Renode.Peripherals.Miscellaneous.Crypto
13 {
14     public static class AthenaX5200_BigIntegerHelper
15     {
CreateBigInteger(byte[] bytes, int byteCount)16         public static BigInteger CreateBigInteger(byte[] bytes, int byteCount)
17         {
18             if(bytes[0] >= 0x80)
19             {
20                 var temp = new byte[bytes.Length + 1];
21                 Array.Copy(bytes, 0, temp, 1, bytes.Length);
22                 bytes = temp;
23             }
24             return new BigInteger(bytes.Take(byteCount).Reverse().ToArray());
25         }
26 
CreateBigIntegerFromMemory(InternalMemoryManager manager, long register, uint wordCount)27         public static BigInteger CreateBigIntegerFromMemory(InternalMemoryManager manager, long register, uint wordCount)
28         {
29             manager.TryReadBytes((long)register + ((wordCount - 1) * 4), 1, out var b);
30             // All calculations require positive values, so we are verifying the sign here:
31             // if the highest bit of the first byte is set, we effectively add a zero at
32             // the beginning of the array, so the data can be interpreted as a positive value.
33             var shouldHavePadding = b[0] >= 0x80;
34             manager.TryReadBytes(register, (int)(wordCount * 4), out var bytesRead);
35 
36             if((long)register < LittleEndianStartingAddress)
37             {
38                 // BigIntegers are expecting Little-Endian data, but internal memories in range <0x0000 - 0x7FFF> are Big-Endian
39                 Misc.EndiannessSwapInPlace(bytesRead, WordSize);
40             }
41             if(shouldHavePadding)
42             {
43                 var wordBytesLength = shouldHavePadding ? wordCount * 4 + 1 : wordCount * 4;
44                 var bytesReadPadded = new byte[wordBytesLength];
45                 Array.Copy(bytesRead, 0, bytesReadPadded, 0, (int)(wordCount * 4));
46                 return new BigInteger(bytesReadPadded);
47             }
48             return new BigInteger(bytesRead);
49         }
50 
StoreBigIntegerBytes(InternalMemoryManager manager, uint length, byte[] resultBytes, long baseAddress)51         public static void StoreBigIntegerBytes(InternalMemoryManager manager, uint length, byte[] resultBytes, long baseAddress)
52         {
53             var byteCount = (int)(length * WordSize);
54             if(resultBytes.Length > byteCount)
55             {
56                 // BigInteger.ToByteArray might return an array with an extra element
57                 // to indicate the sign of resulting value; we need to get rid of it here
58                 resultBytes = resultBytes.Take(byteCount).ToArray();
59             }
60             if(baseAddress < LittleEndianStartingAddress)
61             {
62                 // BigIntegers are containing Little-Endian data, but internal memories in range <0x0000 - 0x7FFF> are Big-Endian
63                 Misc.EndiannessSwapInPlace(resultBytes, WordSize);
64             }
65             manager.TryWriteBytes(baseAddress, resultBytes);
66         }
67 
CalculateModularInverse(BigInteger value, BigInteger modulo)68         public static BigInteger CalculateModularInverse(BigInteger value, BigInteger modulo)
69         {
70             BigInteger leftFactor = 0;
71             BigInteger mod = modulo;
72             BigInteger gcd = 0;
73             BigInteger u = 1;
74 
75             while(value != 0)
76             {
77                 var q = mod / value;
78                 var r = mod % value;
79                 var m = leftFactor - u * q;
80                 mod = value;
81                 value = r;
82                 leftFactor = u;
83                 u = m;
84                 gcd = mod;
85             }
86 
87             if(gcd != 1)
88             {
89                 throw new ArgumentException(string.Format("Invalid modulo: {0} while trying to calculate modular inverse!", modulo));
90             }
91             if(leftFactor < 0)
92             {
93                 leftFactor += modulo;
94             }
95             return leftFactor % modulo;
96         }
97 
98         private const int WordSize = 4; // in bytes
99         private const uint LittleEndianStartingAddress = 0x8000;
100     }
101 }
102