summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2023-02-28 12:09:51 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2023-02-28 12:09:51 +0700
commitd67160cc62739b62d852820c015e3af57f9f4736 (patch)
tree97f0b63f00c602f7e703cd03df48852d1fded90c
parentException on malformed checksum (diff)
downloadBouncyCastle.NET-ed25519-d67160cc62739b62d852820c015e3af57f9f4736.tar.xz
CRC24 perf. opts.
-rw-r--r--crypto/src/bcpg/ArmoredInputStream.cs58
-rw-r--r--crypto/src/bcpg/ArmoredOutputStream.cs108
-rw-r--r--crypto/src/bcpg/Crc24.cs54
-rw-r--r--crypto/src/crypto/util/Pack.cs28
4 files changed, 165 insertions, 83 deletions
diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs
index 739d78083..b493d04fc 100644
--- a/crypto/src/bcpg/ArmoredInputStream.cs
+++ b/crypto/src/bcpg/ArmoredInputStream.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.IO;
 using System.Text;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
@@ -396,36 +397,30 @@ namespace Org.BouncyCastle.Bcpg
                         newLineFound = false;
                     }
                 }
-            
+
                 lastC = c;
 
                 if (c < 0)
                 {
                     isEndOfStream = true;
                 }
-            
+
                 return c;
             }
 
             if (bufPtr > 2 || crcFound)
             {
                 c = ReadIgnoreSpace();
-            
+
                 if (c == '\r' || c == '\n')
                 {
                     c = ReadIgnoreSpace();
-                
+
                     while (c == '\n' || c == '\r')
                     {
                         c = ReadIgnoreSpace();
                     }
 
-                    if (c < 0)                // EOF
-                    {
-                        isEndOfStream = true;
-                        return -1;
-                    }
-
                     if (c == '=')            // crc reached
                     {
                         bufPtr = Decode(ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
@@ -434,28 +429,23 @@ namespace Org.BouncyCastle.Bcpg
 
                         crcFound = true;
 
-                        int i = ((outBuf[0] & 0xff) << 16)
-                              | ((outBuf[1] & 0xff) << 8)
-                              | (outBuf[2] & 0xff);
+                        int i = (int)Pack.BE_To_UInt24(outBuf);
                         if (i != crc.Value)
                             throw new IOException("crc check failed in armored message.");
 
                         return ReadByte();
                     }
-                    else if (c == '-')        // end of record reached
+
+                    if (c == '-')        // end of record reached
                     {
                         while ((c = input.ReadByte()) >= 0)
                         {
                             if (c == '\n' || c == '\r')
-                            {
                                 break;
-                            }
                         }
 
                         if (!crcFound && detectMissingChecksum)
-                        {
                             throw new IOException("crc check not found");
-                        }
 
                         crcFound = false;
                         start = true;
@@ -468,30 +458,30 @@ namespace Org.BouncyCastle.Bcpg
 
                         return -1;
                     }
-                    else                   // data
-                    {
-                        bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
-                    }
+                }
+
+                if (c < 0)
+                {
+                    isEndOfStream = true;
+                    return -1;
+                }
+
+                bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
+
+                if (bufPtr == 0)
+                {
+                    crc.Update3(outBuf, 0);
                 }
                 else
                 {
-                    if (c >= 0)
+                    for (int i = bufPtr; i < 3; ++i)
                     {
-                        bufPtr = Decode(c, ReadIgnoreSpace(), ReadIgnoreSpace(), ReadIgnoreSpace(), outBuf);
-                    }
-                    else
-                    {
-                        isEndOfStream = true;
-                        return -1;
+                        crc.Update(outBuf[i]);
                     }
                 }
             }
 
-            c = outBuf[bufPtr++];
-
-            crc.Update((byte)c);
-
-            return c;
+            return (int)outBuf[bufPtr++];
         }
 
         protected override void Dispose(bool disposing)
diff --git a/crypto/src/bcpg/ArmoredOutputStream.cs b/crypto/src/bcpg/ArmoredOutputStream.cs
index bfed1972a..37dcf2340 100644
--- a/crypto/src/bcpg/ArmoredOutputStream.cs
+++ b/crypto/src/bcpg/ArmoredOutputStream.cs
@@ -4,6 +4,7 @@ using System.Diagnostics;
 using System.IO;
 using System.Reflection;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.Utilities.IO;
@@ -37,51 +38,81 @@ namespace Org.BouncyCastle.Bcpg
         /**
          * encode the input data producing a base 64 encoded byte array.
          */
-        private static void Encode(
-            Stream    outStream,
-            int[]    data,
-            int        len)
+        private static void Encode(Stream outStream, byte[] data, int len)
         {
             Debug.Assert(len > 0);
             Debug.Assert(len < 4);
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> bs = stackalloc byte[4];
+#else
             byte[] bs = new byte[4];
+#endif
+
             int d1 = data[0];
             bs[0] = encodingTable[(d1 >> 2) & 0x3f];
 
             switch (len)
             {
-                case 1:
-                {
-                    bs[1] = encodingTable[(d1 << 4) & 0x3f];
-                    bs[2] = (byte)'=';
-                    bs[3] = (byte)'=';
-                    break;
-                }
-                case 2:
-                {
-                    int d2 = data[1];
-                    bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
-                    bs[2] = encodingTable[(d2 << 2) & 0x3f];
-                    bs[3] = (byte)'=';
-                    break;
-                }
-                case 3:
-                {
-                    int d2 = data[1];
-                    int d3 = data[2];
-                    bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
-                    bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
-                    bs[3] = encodingTable[d3 & 0x3f];
-                    break;
-                }
+            case 1:
+            {
+                bs[1] = encodingTable[(d1 << 4) & 0x3f];
+                bs[2] = (byte)'=';
+                bs[3] = (byte)'=';
+                break;
+            }
+            case 2:
+            {
+                int d2 = data[1];
+                bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+                bs[2] = encodingTable[(d2 << 2) & 0x3f];
+                bs[3] = (byte)'=';
+                break;
+            }
+            case 3:
+            {
+                int d2 = data[1];
+                int d3 = data[2];
+                bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+                bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+                bs[3] = encodingTable[d3 & 0x3f];
+                break;
+            }
             }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            outStream.Write(bs);
+#else
             outStream.Write(bs, 0, bs.Length);
+#endif
+        }
+
+        private static void Encode3(Stream outStream, byte[] data)
+        {
+            int d1 = data[0];
+            int d2 = data[1];
+            int d3 = data[2];
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> bs = stackalloc byte[4];
+#else
+            byte[] bs = new byte[4];
+#endif
+
+            bs[0] = encodingTable[(d1 >> 2) & 0x3f];
+            bs[1] = encodingTable[((d1 << 4) | (d2 >> 4)) & 0x3f];
+            bs[2] = encodingTable[((d2 << 2) | (d3 >> 6)) & 0x3f];
+            bs[3] = encodingTable[d3 & 0x3f];
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            outStream.Write(bs);
+#else
+            outStream.Write(bs, 0, bs.Length);
+#endif
         }
 
         private readonly Stream outStream;
-        private int[]           buf = new int[3];
+        private byte[]          buf = new byte[3];
         private int             bufPtr = 0;
         private Crc24           crc = new Crc24();
         private int             chunkCount = 0;
@@ -324,7 +355,8 @@ namespace Org.BouncyCastle.Bcpg
 
             if (bufPtr == 3)
             {
-                Encode(outStream, buf, bufPtr);
+                crc.Update3(buf, 0);
+                Encode3(outStream, buf);
                 bufPtr = 0;
                 if ((++chunkCount & 0xf) == 0)
                 {
@@ -332,8 +364,7 @@ namespace Org.BouncyCastle.Bcpg
                 }
             }
 
-            crc.Update(value);
-            buf[bufPtr++] = value & 0xff;
+            buf[bufPtr++] = value;
         }
 
         /**
@@ -359,18 +390,17 @@ namespace Org.BouncyCastle.Bcpg
         {
             if (bufPtr > 0)
             {
+                for (int i = 0; i < bufPtr; ++i)
+                {
+                    crc.Update(buf[i]);
+                }
                 Encode(outStream, buf, bufPtr);
             }
 
             DoWrite(NewLine + '=');
 
-            int crcV = crc.Value;
-
-            buf[0] = ((crcV >> 16) & 0xff);
-            buf[1] = ((crcV >> 8) & 0xff);
-            buf[2] = (crcV & 0xff);
-
-            Encode(outStream, buf, 3);
+            Pack.UInt24_To_BE((uint)crc.Value, buf);
+            Encode3(outStream, buf);
 
             DoWrite(NewLine);
             DoWrite(footerStart);
diff --git a/crypto/src/bcpg/Crc24.cs b/crypto/src/bcpg/Crc24.cs
index 54c9f2f5a..66cea0b06 100644
--- a/crypto/src/bcpg/Crc24.cs
+++ b/crypto/src/bcpg/Crc24.cs
@@ -1,5 +1,3 @@
-using System;
-
 namespace Org.BouncyCastle.Bcpg
 {
     public sealed class Crc24
@@ -7,6 +5,41 @@ namespace Org.BouncyCastle.Bcpg
         private const int Crc24Init = 0x0b704ce;
         private const int Crc24Poly = 0x1864cfb;
 
+        private static readonly int[] Table0, Table8, Table16;
+
+        static Crc24()
+        {
+            int[] table0 = new int[256];
+            int[] table8 = new int[256];
+            int[] table16 = new int[256];
+
+            int crc = 0x800000;
+            for (int i = 1; i < 256; i <<= 1)
+            {
+                int carry = ((crc << 8) >> 31) & Crc24Poly;
+                crc = (crc << 1) ^ carry;
+
+                for (int j = 0; j < i; ++j)
+                {
+                    table0[i + j] = crc ^ table0[j];
+                }
+            }
+
+            for (int i = 1; i < 256; ++i)
+            {
+                int crc0 = table0[i];
+                int crc8 = ((crc0 & 0xFFFF) << 8) ^ table0[(crc0 >> 16) & 255];
+                int crc16 = ((crc8 & 0xFFFF) << 8) ^ table0[(crc8 >> 16) & 255];
+
+                table8[i] = crc8;
+                table16[i] = crc16;
+            }
+
+            Table0 = table0;
+            Table8 = table8;
+            Table16 = table16;
+        }
+
         private int m_crc = Crc24Init;
 
         public Crc24()
@@ -15,17 +48,18 @@ namespace Org.BouncyCastle.Bcpg
 
         public void Update(byte b)
         {
-            m_crc ^= (int)b << 16;
-            for (int i = 0; i < 8; i++)
-            {
-                int carry = -((m_crc >> 23) & 1) & Crc24Poly;
+            int index = (b ^ (m_crc >> 16)) & 255;
+            m_crc = (m_crc << 8) ^ Table0[index];
+        }
 
-                m_crc <<= 1;
-                m_crc ^= carry;
-            }
+        public void Update3(byte[] buf, int off)
+        {
+            m_crc = Table16[(buf[off + 0] ^ (m_crc >> 16)) & 255]
+                  ^ Table8[(buf[off + 1] ^ (m_crc >> 8)) & 255]
+                  ^ Table0[(buf[off + 2] ^ m_crc) & 255];
         }
 
-        public int Value => m_crc;
+        public int Value => m_crc & 0xFFFFFF;
 
 		public void Reset()
         {
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index e00ba39fa..cd8010f5a 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -102,6 +102,34 @@ namespace Org.BouncyCastle.Crypto.Utilities
             return ns;
         }
 
+        internal static void UInt24_To_BE(uint n, byte[] bs)
+        {
+            bs[0] = (byte)(n >> 16);
+            bs[1] = (byte)(n >> 8);
+            bs[2] = (byte)n;
+        }
+
+        internal static void UInt24_To_BE(uint n, byte[] bs, int off)
+        {
+            bs[off + 0] = (byte)(n >> 16);
+            bs[off + 1] = (byte)(n >> 8);
+            bs[off + 2] = (byte)n;
+        }
+
+        internal static uint BE_To_UInt24(byte[] bs)
+        {
+            return (uint)bs[0] << 16
+                | (uint)bs[1] << 8
+                | bs[2];
+        }
+
+        internal static uint BE_To_UInt24(byte[] bs, int off)
+        {
+            return (uint)bs[off] << 16
+                | (uint)bs[off + 1] << 8
+                | bs[off + 2];
+        }
+
         internal static void UInt32_To_BE(uint n, byte[] bs)
         {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER