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