/// <summary> /// Perform a Matrix operation (add / subtract) /// </summary> /// <param name="sid">Session ID</param> /// <param name="operation">Operation to perform</param> /// <param name="code">Azure Function key</param> private async Task PerformMatrixOperation(string sid, string operation, string code) { ClearLog(); Log($"Session ID: {sid}"); MatrixData mda = MatrixA.Matrix.DataContext as MatrixData; MatrixData mdb = MatrixB.Matrix.DataContext as MatrixData; Plaintext plaina = Utilities.MatrixToPlaintext(Utilities.MatrixDataToMatrix(mda), encoder_); Plaintext plainb = Utilities.MatrixToPlaintext(Utilities.MatrixDataToMatrix(mdb), encoder_); Plaintext plain = await PerformOperation(sid, operation, code, plaina, plainb); if (null == plain) { OperationResult.MatrixTitle = $"Error executing {operation}"; OperationResult.ClearMatrix(); return; } int rows = mda.DataView.Table.Rows.Count; int cols = mda.DataView.Table.Columns.Count; int[,] matresult = Utilities.PlaintextToMatrix(plain, rows, cols, encoder_); OperationResult.MatrixTitle = "Result"; OperationResult.InitMatrix(matresult); }
/// <summary> /// Initialize a MatrixData instance of the appropriate size /// </summary> /// <param name="rows">Rows in MatrixData</param> /// <param name="columns">Columns in MatrixData</param> /// <returns>Initialized MatrixData</returns> private static MatrixData InitMatrixData(int[,] matrix) { MatrixData data = new MatrixData(); int rows = matrix.GetLength(dimension: 0); int cols = matrix.GetLength(dimension: 1); for (int c = 0; c < cols; c++) { data.DataTable.Columns.Add((c + 1).ToString()); data.DataTable.Columns[c].DataType = typeof(int); data.DataTable.Columns[c].AllowDBNull = false; } for (int r = 0; r < rows; r++) { object[] rowVals = new object[cols]; for (int c = 0; c < cols; c++) { rowVals[c] = matrix[r, c]; } data.DataTable.Rows.Add(rowVals); } return(data); }
/// <summary> /// Initialize data grid with the given matrix /// </summary> /// <param name="matrix"></param> public void InitMatrix(int[,] matrix) { MatrixData data = InitMatrixData(matrix); MatrixData oldData = DataContext as MatrixData; DataContext = data; bool matrixChanged = (oldData == null) || (null != oldData && (oldData.DataTable.Rows.Count != data.DataTable.Rows.Count || oldData.DataTable.Columns.Count != data.DataTable.Columns.Count)); if (matrixChanged) { MatrixSizeChanged?.Invoke(this, EventArgs.Empty); } }
/// <summary> /// Get a Matrix of integers from a MatrixData object /// </summary> /// <param name="md">MatrixData object to get the matrix from</param> /// <returns>Matrix of integers</returns> public static int[,] MatrixDataToMatrix(MatrixData md) { int rows = md.DataView.Table.Rows.Count; int cols = md.DataView.Table.Columns.Count; int[,] result = new int[rows, cols]; for (int r = 0; r < rows; r++) { for (int c = 0; c < cols; c++) { result[r, c] = (int)md.DataView.Table.Rows[r].ItemArray[c]; } } return(result); }
/// <summary> /// Perform a Matrix multiplication. /// /// Please refer to the file MATRIXMULTIPLICATION.md for an explanation of /// how matrix multiplication is implemented in this application. /// </summary> private async Task PerformMatrixMultiplication(string sid, string code) { ClearLog(); Log($"Session ID: {sid}"); // Query RelinKeys with given sid if (!await QueryPublicKeys(sid, "RelinKeys", GlobalProperties.Codes.PublicKeysQuery)) { // Upload RelinKeys if needed if (!await UploadPublicKeys( sid, GlobalProperties.PublicKeyType.RelinKeys, GlobalProperties.Codes.PublicKeysUpload)) { Log($"RelinKeys upload failed"); return; } } // Query GaloisKeys with given sid if (!await QueryPublicKeys(sid, "GaloisKeys", GlobalProperties.Codes.PublicKeysQuery)) { // Upload GaloisKeys if needed if (!await UploadPublicKeys( sid, GlobalProperties.PublicKeyType.GaloisKeys, GlobalProperties.Codes.PublicKeysUpload)) { Log($"GaloisKeys upload failed"); return; } } MatrixData mda = MatrixA.Matrix.DataContext as MatrixData; MatrixData mdb = MatrixB.Matrix.DataContext as MatrixData; int[,] matrixa = Utilities.MatrixDataToMatrix(mda); int[,] matrixb = Utilities.MatrixDataToMatrix(mdb); int marows = matrixa.GetLength(dimension: 0); int macols = matrixa.GetLength(dimension: 1); int mbrows = matrixb.GetLength(dimension: 0); int mbcols = matrixb.GetLength(dimension: 1); if (marows < 1 || macols < 1 || mbrows < 1 || mbcols < 1 || macols != mbrows) { throw new InvalidOperationException("matrices are incompatible for multiplication"); } bool transposed = false; if (Math.Max(mbrows, mbcols) < Math.Max(marows, macols)) { transposed = true; Log("Computing on transposes for improved performance"); (matrixa, matrixb) = (Utilities.Transpose(matrixb), Utilities.Transpose(matrixa)); (marows, macols, mbrows, mbcols) = (mbcols, mbrows, macols, marows); } // We use a power of two dimension always int dimension = Utilities.FindNextPowerOfTwo((ulong)Math.Max(marows, macols)); int[,] paddedMatrixa = new int[dimension, dimension]; for (int r = 0; r < marows; r++) { for (int c = 0; c < macols; c++) { paddedMatrixa[r, c] = matrixa[r, c]; } } // Create a matrix whose rows are generalized diagonals of matrix A int[,] cyclicDiagsMatrix = new int[dimension, dimension]; for (int r = 0; r < dimension; r++) { for (int c = 0; c < dimension; c++) { cyclicDiagsMatrix[r, c] = paddedMatrixa[c, (c + r) % dimension]; } } // Make cyclicDiagsMatrix into a List of plaintexts List <Plaintext> cdmPlains = Utilities.RowsToPlaintexts(cyclicDiagsMatrix, mbcols, encoder_); // Make matrixb into row-major set of plaintexts int[,] paddedMatrixb = new int[dimension, mbcols]; for (int r = 0; r < mbrows; r++) { for (int c = 0; c < mbcols; c++) { paddedMatrixb[r, c] = matrixb[r, c]; } } Plaintext matrixbPlain = Utilities.MatrixToTwistedPlaintext(paddedMatrixb, encoder_); Plaintext plainResult = await PerformMatrixProductOperation(sid, code, cdmPlains, matrixbPlain); if (null == plainResult) { OperationResult.MatrixTitle = "Error performing matrix product"; OperationResult.ClearMatrix(); return; } int[,] wideResult = new int[dimension, mbcols]; wideResult = Utilities.PlaintextToMatrix(plainResult, dimension, mbcols, encoder_); if (transposed) { wideResult = Utilities.Transpose(wideResult); (marows, macols, mbrows, mbcols) = (mbcols, mbrows, macols, marows); } int[,] result = new int[marows, mbcols]; for (int r = 0; r < marows; r++) { for (int c = 0; c < mbcols; c++) { result[r, c] = wideResult[r, c]; } } OperationResult.MatrixTitle = "Result"; OperationResult.InitMatrix(result); }