From 34ed3322c4defdf3fece0a33b9b78670c6a6c9bc Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sun, 22 Mar 2026 15:22:46 -0400 Subject: [PATCH] Move some math/numeric byte array extensions --- .../ByteArrayExtensionsTests.cs | 118 ----------- .../ByteArrayExtensions.cs | 186 +----------------- .../ByteArrayExtensionsTests.cs | 125 ++++++++++++ ...SabreTools.Numerics.Extensions.Test.csproj | 1 + .../ByteArrayExtensions.cs | 186 ++++++++++++++++++ .../N3DSPartitionKeys.cs | 2 +- .../SabreTools.Security.Cryptography.csproj | 1 + 7 files changed, 315 insertions(+), 304 deletions(-) create mode 100644 SabreTools.Numerics.Extensions.Test/ByteArrayExtensionsTests.cs create mode 100644 SabreTools.Numerics.Extensions/ByteArrayExtensions.cs diff --git a/SabreTools.IO.Extensions.Test/ByteArrayExtensionsTests.cs b/SabreTools.IO.Extensions.Test/ByteArrayExtensionsTests.cs index f124ef2..cf93b7b 100644 --- a/SabreTools.IO.Extensions.Test/ByteArrayExtensionsTests.cs +++ b/SabreTools.IO.Extensions.Test/ByteArrayExtensionsTests.cs @@ -1,5 +1,3 @@ -using System.Text; -using SabreTools.Matching; using Xunit; namespace SabreTools.IO.Extensions.Test @@ -92,121 +90,5 @@ namespace SabreTools.IO.Extensions.Test } #endregion - - #region IsNumericArray - - [Fact] - public void IsNumericArray_Empty_False() - { - byte[] arr = []; - bool actual = arr.IsNumericArray(); - Assert.False(actual); - } - - [Fact] - public void IsNumericArray_NonNumeric_False() - { - byte[] arr = Encoding.ASCII.GetBytes("ABCDEF"); - bool actual = arr.IsNumericArray(); - Assert.False(actual); - } - - [Fact] - public void IsNumericArray_MixedNumeric_False() - { - byte[] arr = Encoding.ASCII.GetBytes("ABC123"); - bool actual = arr.IsNumericArray(); - Assert.False(actual); - } - - [Fact] - public void IsNumericArray_Numeric_True() - { - byte[] arr = Encoding.ASCII.GetBytes("0123456789"); - bool actual = arr.IsNumericArray(); - Assert.True(actual); - } - - #endregion - - #region Add - - [Theory] - [InlineData(new byte[0], 0, new byte[0])] - [InlineData(new byte[0], 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })] - [InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })] - [InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA4 })] - public void Add_NumericInput(byte[] self, uint add, byte[] expected) - { - byte[] actual = self.Add(add); - - Assert.Equal(expected.Length, actual.Length); - if (actual.Length > 0) - Assert.True(actual.EqualsExactly(expected)); - } - - [Theory] - [InlineData(new byte[0], new byte[0], new byte[0])] - [InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x09, 0xA4 })] - [InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })] - public void Add_ArrayInput(byte[] self, byte[] add, byte[] expected) - { - byte[] actual = self.Add(add); - - Assert.Equal(expected.Length, actual.Length); - if (actual.Length > 0) - Assert.True(actual.EqualsExactly(expected)); - } - - #endregion - - #region RotateLeft - - [Theory] - [InlineData(new byte[0], 0, new byte[0])] - [InlineData(new byte[] { 0x01 }, 0, new byte[] { 0x01 })] - [InlineData(new byte[] { 0x01 }, 1, new byte[] { 0x02 })] - [InlineData(new byte[] { 0x80 }, 1, new byte[] { 0x01 })] - [InlineData(new byte[] { 0x00, 0x01 }, 0, new byte[] { 0x00, 0x01 })] - [InlineData(new byte[] { 0x00, 0x01 }, 1, new byte[] { 0x00, 0x02 })] - [InlineData(new byte[] { 0x00, 0x80 }, 1, new byte[] { 0x01, 0x00 })] - [InlineData(new byte[] { 0x80, 0x00 }, 1, new byte[] { 0x00, 0x01 })] - public void RotateLeftTest(byte[] self, int numBits, byte[] expected) - { - byte[] actual = self.RotateLeft(numBits); - - Assert.Equal(expected.Length, actual.Length); - if (actual.Length > 0) - Assert.True(actual.EqualsExactly(expected)); - } - - #endregion - - #region Xor - - [Theory] - [InlineData(new byte[0], new byte[0], new byte[0])] - [InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 })] - [InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })] - [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })] - public void XorTest(byte[] self, byte[] add, byte[] expected) - { - byte[] actual = self.Xor(add); - - Assert.Equal(expected.Length, actual.Length); - if (actual.Length > 0) - Assert.True(actual.EqualsExactly(expected)); - } - - #endregion } } diff --git a/SabreTools.IO.Extensions/ByteArrayExtensions.cs b/SabreTools.IO.Extensions/ByteArrayExtensions.cs index 7ed2696..cbd74e3 100644 --- a/SabreTools.IO.Extensions/ByteArrayExtensions.cs +++ b/SabreTools.IO.Extensions/ByteArrayExtensions.cs @@ -1,5 +1,4 @@ using System; -using SabreTools.Numerics.Extensions; namespace SabreTools.IO.Extensions { @@ -25,7 +24,7 @@ namespace SabreTools.IO.Extensions // Align the stream position while (offset % alignment != 0 && offset < input.Length) { - _ = input.ReadByteValue(ref offset); + offset++; } // Return if the alignment completed @@ -39,188 +38,5 @@ namespace SabreTools.IO.Extensions { return array is null || array.Length == 0; } - - /// - /// Indicates if an array contains all ASCII numeric digits - /// - public static bool IsNumericArray(this byte[] arr) - { - // Empty arrays cannot be numeric - if (arr.Length == 0) - return false; - - // '0' to '9' - return Array.TrueForAll(arr, b => b >= 0x30 && b <= 0x39); - } - - #region Math - - /// - /// Add an integer value to a number represented by a byte array - /// - /// Byte array to add to - /// Amount to add - /// Byte array representing the new value - /// Assumes array values are in big-endian format - public static byte[] Add(this byte[] self, uint add) - { - // If nothing is being added, just return - if (add == 0) - return self; - - // Get the big-endian representation of the value - byte[] addBytes = BitConverter.GetBytes(add); - Array.Reverse(addBytes); - - // Pad the array out to 16 bytes - byte[] paddedBytes = new byte[16]; - Array.Copy(addBytes, 0, paddedBytes, 12, 4); - - // If the input is empty, just return the added value - if (self.Length == 0) - return paddedBytes; - - return self.Add(paddedBytes); - } - - /// - /// Add two numbers represented by byte arrays - /// - /// Byte array to add to - /// Amount to add - /// Byte array representing the new value - /// Assumes array values are in big-endian format - public static byte[] Add(this byte[] self, byte[] add) - { - // If either input is empty - if (self.Length == 0 && add.Length == 0) - return []; - else if (self.Length > 0 && add.Length == 0) - return self; - else if (self.Length == 0 && add.Length > 0) - return add; - - // Setup the output array - int outLength = Math.Max(self.Length, add.Length); - byte[] output = new byte[outLength]; - - // Loop adding with carry - uint carry = 0; - for (int i = 0; i < outLength; i++) - { - int selfIndex = self.Length - i - 1; - uint selfValue = selfIndex >= 0 ? self[selfIndex] : 0u; - - int addIndex = add.Length - i - 1; - uint addValue = addIndex >= 0 ? add[addIndex] : 0u; - - uint next = selfValue + addValue + carry; - carry = next >> 8; - - int outputIndex = output.Length - i - 1; - output[outputIndex] = (byte)(next & 0xFF); - } - - return output; - } - - /// - /// Perform a rotate left on a byte array - /// - /// Byte array value to rotate - /// Number of bits to rotate - /// Rotated byte array value - /// Assumes array values are in big-endian format - public static byte[] RotateLeft(this byte[] self, int numBits) - { - // If either input is empty - if (self.Length == 0) - return []; - else if (numBits == 0) - return self; - - byte[] output = new byte[self.Length]; - Array.Copy(self, output, output.Length); - - // Shift by bytes - while (numBits >= 8) - { - byte temp = output[0]; - for (int i = 0; i < output.Length - 1; i++) - { - output[i] = output[i + 1]; - } - - output[output.Length - 1] = temp; - numBits -= 8; - } - - // Shift by bits - if (numBits > 0) - { - byte bitMask = (byte)(8 - numBits), carry, wrap = 0; - for (int i = 0; i < output.Length; i++) - { - carry = (byte)(((255 << bitMask) & output[i]) >> bitMask); - - // Make sure the first byte carries to the end - if (i == 0) - wrap = carry; - - // Otherwise, move to the last byte - else - output[i - 1] |= carry; - - // Shift the current bits - output[i] <<= numBits; - } - - // Make sure the wrap happens - output[output.Length - 1] |= wrap; - } - - return output; - } - - /// - /// XOR two numbers represented by byte arrays - /// - /// Byte array to XOR to - /// Amount to XOR - /// Byte array representing the new value - /// Assumes array values are in big-endian format - public static byte[] Xor(this byte[] self, byte[] xor) - { - // If either input is empty - if (self.Length == 0 && xor.Length == 0) - return []; - else if (self.Length > 0 && xor.Length == 0) - return self; - else if (self.Length == 0 && xor.Length > 0) - return xor; - - // Setup the output array - int outLength = Math.Max(self.Length, xor.Length); - byte[] output = new byte[outLength]; - - // Loop XOR - for (int i = 0; i < outLength; i++) - { - int selfIndex = self.Length - i - 1; - uint selfValue = selfIndex >= 0 ? self[selfIndex] : 0u; - - int xorIndex = xor.Length - i - 1; - uint xorValue = xorIndex >= 0 ? xor[xorIndex] : 0u; - - uint next = selfValue ^ xorValue; - - int outputIndex = output.Length - i - 1; - output[outputIndex] = (byte)(next & 0xFF); - } - - return output; - } - - #endregion } } diff --git a/SabreTools.Numerics.Extensions.Test/ByteArrayExtensionsTests.cs b/SabreTools.Numerics.Extensions.Test/ByteArrayExtensionsTests.cs new file mode 100644 index 0000000..586b948 --- /dev/null +++ b/SabreTools.Numerics.Extensions.Test/ByteArrayExtensionsTests.cs @@ -0,0 +1,125 @@ +using System.Text; +using SabreTools.Matching; +using Xunit; + +namespace SabreTools.Numerics.Extensions.Test +{ + public class ByteArrayExtensionsTests + { + #region IsNumericArray + + [Fact] + public void IsNumericArray_Empty_False() + { + byte[] arr = []; + bool actual = arr.IsNumericArray(); + Assert.False(actual); + } + + [Fact] + public void IsNumericArray_NonNumeric_False() + { + byte[] arr = Encoding.ASCII.GetBytes("ABCDEF"); + bool actual = arr.IsNumericArray(); + Assert.False(actual); + } + + [Fact] + public void IsNumericArray_MixedNumeric_False() + { + byte[] arr = Encoding.ASCII.GetBytes("ABC123"); + bool actual = arr.IsNumericArray(); + Assert.False(actual); + } + + [Fact] + public void IsNumericArray_Numeric_True() + { + byte[] arr = Encoding.ASCII.GetBytes("0123456789"); + bool actual = arr.IsNumericArray(); + Assert.True(actual); + } + + #endregion + + #region Add + + [Theory] + [InlineData(new byte[0], 0, new byte[0])] + [InlineData(new byte[0], 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })] + [InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 0, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 })] + [InlineData(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xD2 }, 1234, new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0xA4 })] + public void Add_NumericInput(byte[] self, uint add, byte[] expected) + { + byte[] actual = self.Add(add); + + Assert.Equal(expected.Length, actual.Length); + if (actual.Length > 0) + Assert.True(actual.EqualsExactly(expected)); + } + + [Theory] + [InlineData(new byte[0], new byte[0], new byte[0])] + [InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x09, 0xA4 })] + [InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x09, 0xA4 })] + public void Add_ArrayInput(byte[] self, byte[] add, byte[] expected) + { + byte[] actual = self.Add(add); + + Assert.Equal(expected.Length, actual.Length); + if (actual.Length > 0) + Assert.True(actual.EqualsExactly(expected)); + } + + #endregion + + #region RotateLeft + + [Theory] + [InlineData(new byte[0], 0, new byte[0])] + [InlineData(new byte[] { 0x01 }, 0, new byte[] { 0x01 })] + [InlineData(new byte[] { 0x01 }, 1, new byte[] { 0x02 })] + [InlineData(new byte[] { 0x80 }, 1, new byte[] { 0x01 })] + [InlineData(new byte[] { 0x00, 0x01 }, 0, new byte[] { 0x00, 0x01 })] + [InlineData(new byte[] { 0x00, 0x01 }, 1, new byte[] { 0x00, 0x02 })] + [InlineData(new byte[] { 0x00, 0x80 }, 1, new byte[] { 0x01, 0x00 })] + [InlineData(new byte[] { 0x80, 0x00 }, 1, new byte[] { 0x00, 0x01 })] + public void RotateLeftTest(byte[] self, int numBits, byte[] expected) + { + byte[] actual = self.RotateLeft(numBits); + + Assert.Equal(expected.Length, actual.Length); + if (actual.Length > 0) + Assert.True(actual.EqualsExactly(expected)); + } + + #endregion + + #region Xor + + [Theory] + [InlineData(new byte[0], new byte[0], new byte[0])] + [InlineData(new byte[0], new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[0], new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x00, 0x00 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0x00, 0x00 })] + [InlineData(new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })] + [InlineData(new byte[] { 0x04, 0xD2 }, new byte[] { 0xAB, 0x04, 0xD2 }, new byte[] { 0xAB, 0x00, 0x00 })] + public void XorTest(byte[] self, byte[] add, byte[] expected) + { + byte[] actual = self.Xor(add); + + Assert.Equal(expected.Length, actual.Length); + if (actual.Length > 0) + Assert.True(actual.EqualsExactly(expected)); + } + + #endregion + } +} diff --git a/SabreTools.Numerics.Extensions.Test/SabreTools.Numerics.Extensions.Test.csproj b/SabreTools.Numerics.Extensions.Test/SabreTools.Numerics.Extensions.Test.csproj index e50c553..42918c9 100644 --- a/SabreTools.Numerics.Extensions.Test/SabreTools.Numerics.Extensions.Test.csproj +++ b/SabreTools.Numerics.Extensions.Test/SabreTools.Numerics.Extensions.Test.csproj @@ -18,6 +18,7 @@ + \ No newline at end of file diff --git a/SabreTools.Numerics.Extensions/ByteArrayExtensions.cs b/SabreTools.Numerics.Extensions/ByteArrayExtensions.cs new file mode 100644 index 0000000..a4ffe49 --- /dev/null +++ b/SabreTools.Numerics.Extensions/ByteArrayExtensions.cs @@ -0,0 +1,186 @@ +using System; + +namespace SabreTools.Numerics.Extensions +{ + public static class ByteArrayExtensions + { + /// + /// Indicates if an array contains all ASCII numeric digits + /// + public static bool IsNumericArray(this byte[] arr) + { + // Empty arrays cannot be numeric + if (arr.Length == 0) + return false; + + // '0' to '9' + return Array.TrueForAll(arr, b => b >= 0x30 && b <= 0x39); + } + + /// + /// Add an integer value to a number represented by a byte array + /// + /// Byte array to add to + /// Amount to add + /// Byte array representing the new value + /// Assumes array values are in big-endian format + public static byte[] Add(this byte[] self, uint add) + { + // If nothing is being added, just return + if (add == 0) + return self; + + // Get the big-endian representation of the value + byte[] addBytes = BitConverter.GetBytes(add); + Array.Reverse(addBytes); + + // Pad the array out to 16 bytes + byte[] paddedBytes = new byte[16]; + Array.Copy(addBytes, 0, paddedBytes, 12, 4); + + // If the input is empty, just return the added value + if (self.Length == 0) + return paddedBytes; + + return self.Add(paddedBytes); + } + + /// + /// Add two numbers represented by byte arrays + /// + /// Byte array to add to + /// Amount to add + /// Byte array representing the new value + /// Assumes array values are in big-endian format + public static byte[] Add(this byte[] self, byte[] add) + { + // If either input is empty + if (self.Length == 0 && add.Length == 0) + return []; + else if (self.Length > 0 && add.Length == 0) + return self; + else if (self.Length == 0 && add.Length > 0) + return add; + + // Setup the output array + int outLength = Math.Max(self.Length, add.Length); + byte[] output = new byte[outLength]; + + // Loop adding with carry + uint carry = 0; + for (int i = 0; i < outLength; i++) + { + int selfIndex = self.Length - i - 1; + uint selfValue = selfIndex >= 0 ? self[selfIndex] : 0u; + + int addIndex = add.Length - i - 1; + uint addValue = addIndex >= 0 ? add[addIndex] : 0u; + + uint next = selfValue + addValue + carry; + carry = next >> 8; + + int outputIndex = output.Length - i - 1; + output[outputIndex] = (byte)(next & 0xFF); + } + + return output; + } + + /// + /// Perform a rotate left on a byte array + /// + /// Byte array value to rotate + /// Number of bits to rotate + /// Rotated byte array value + /// Assumes array values are in big-endian format + public static byte[] RotateLeft(this byte[] self, int numBits) + { + // If either input is empty + if (self.Length == 0) + return []; + else if (numBits == 0) + return self; + + byte[] output = new byte[self.Length]; + Array.Copy(self, output, output.Length); + + // Shift by bytes + while (numBits >= 8) + { + byte temp = output[0]; + for (int i = 0; i < output.Length - 1; i++) + { + output[i] = output[i + 1]; + } + + output[output.Length - 1] = temp; + numBits -= 8; + } + + // Shift by bits + if (numBits > 0) + { + byte bitMask = (byte)(8 - numBits), carry, wrap = 0; + for (int i = 0; i < output.Length; i++) + { + carry = (byte)(((255 << bitMask) & output[i]) >> bitMask); + + // Make sure the first byte carries to the end + if (i == 0) + wrap = carry; + + // Otherwise, move to the last byte + else + output[i - 1] |= carry; + + // Shift the current bits + output[i] <<= numBits; + } + + // Make sure the wrap happens + output[output.Length - 1] |= wrap; + } + + return output; + } + + /// + /// XOR two numbers represented by byte arrays + /// + /// Byte array to XOR to + /// Amount to XOR + /// Byte array representing the new value + /// Assumes array values are in big-endian format + public static byte[] Xor(this byte[] self, byte[] xor) + { + // If either input is empty + if (self.Length == 0 && xor.Length == 0) + return []; + else if (self.Length > 0 && xor.Length == 0) + return self; + else if (self.Length == 0 && xor.Length > 0) + return xor; + + // Setup the output array + int outLength = Math.Max(self.Length, xor.Length); + byte[] output = new byte[outLength]; + + // Loop XOR + for (int i = 0; i < outLength; i++) + { + int selfIndex = self.Length - i - 1; + uint selfValue = selfIndex >= 0 ? self[selfIndex] : 0u; + + int xorIndex = xor.Length - i - 1; + uint xorValue = xorIndex >= 0 ? xor[xorIndex] : 0u; + + uint next = selfValue ^ xorValue; + + int outputIndex = output.Length - i - 1; + output[outputIndex] = (byte)(next & 0xFF); + } + + return output; + } + } +} diff --git a/SabreTools.Security.Cryptography/N3DSPartitionKeys.cs b/SabreTools.Security.Cryptography/N3DSPartitionKeys.cs index 0d0921f..d217a14 100644 --- a/SabreTools.Security.Cryptography/N3DSPartitionKeys.cs +++ b/SabreTools.Security.Cryptography/N3DSPartitionKeys.cs @@ -1,5 +1,5 @@ using System; -using SabreTools.IO.Extensions; +using SabreTools.Numerics.Extensions; namespace SabreTools.Security.Cryptography { diff --git a/SabreTools.Security.Cryptography/SabreTools.Security.Cryptography.csproj b/SabreTools.Security.Cryptography/SabreTools.Security.Cryptography.csproj index deace75..ed39273 100644 --- a/SabreTools.Security.Cryptography/SabreTools.Security.Cryptography.csproj +++ b/SabreTools.Security.Cryptography/SabreTools.Security.Cryptography.csproj @@ -39,6 +39,7 @@ +