summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Hook <dgh@cryptoworkshop.com>2022-08-08 17:38:07 +1000
committerDavid Hook <dgh@cryptoworkshop.com>2022-08-08 17:38:07 +1000
commitf8defaf942ebd8424243794230b5452636d02ca4 (patch)
treeb1209d6e0be6720dbb98957c787f918cee6d85ab
parentInitial Falcon implementation (diff)
parentRemove unnecessary AsSpan (diff)
downloadBouncyCastle.NET-ed25519-f8defaf942ebd8424243794230b5452636d02ca4.tar.xz
Merge remote-tracking branch 'refs/remotes/origin/master'
-rw-r--r--crypto/src/crmf/PKMacBuilder.cs9
-rw-r--r--crypto/src/crypto/Check.cs2
-rw-r--r--crypto/src/crypto/IBlockResult.cs12
-rw-r--r--crypto/src/crypto/SimpleBlockResult.cs9
-rw-r--r--crypto/src/crypto/digests/RipeMD128Digest.cs33
-rw-r--r--crypto/src/crypto/digests/RipeMD160Digest.cs37
-rw-r--r--crypto/src/crypto/digests/RipeMD256Digest.cs36
-rw-r--r--crypto/src/crypto/digests/RipeMD320Digest.cs40
-rw-r--r--crypto/src/crypto/digests/SkeinEngine.cs22
-rw-r--r--crypto/src/crypto/digests/TigerDigest.cs51
-rw-r--r--crypto/src/crypto/engines/AesX86Engine.cs12
-rw-r--r--crypto/src/crypto/engines/ChaCha7539Engine.cs66
-rw-r--r--crypto/src/crypto/engines/ChaChaEngine.cs6
-rw-r--r--crypto/src/crypto/engines/ThreefishEngine.cs78
-rw-r--r--crypto/src/crypto/operators/DefaultSignatureResult.cs9
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113Field.cs23
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131Field.cs31
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163Field.cs32
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193Field.cs36
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233Field.cs52
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239Field.cs52
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283Field.cs54
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409Field.cs18
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571Field.cs10
-rw-r--r--crypto/src/ocsp/BasicOCSPRespGenerator.cs37
-rw-r--r--crypto/src/tls/AbstractTlsContext.cs3
-rw-r--r--crypto/src/tls/ChannelBinding.cs5
-rw-r--r--crypto/test/src/tls/test/MockTlsClient.cs3
-rw-r--r--crypto/test/src/tls/test/MockTlsServer.cs3
29 files changed, 486 insertions, 295 deletions
diff --git a/crypto/src/crmf/PKMacBuilder.cs b/crypto/src/crmf/PKMacBuilder.cs
index 156936eac..9b483fbfb 100644
--- a/crypto/src/crmf/PKMacBuilder.cs
+++ b/crypto/src/crmf/PKMacBuilder.cs
@@ -83,6 +83,15 @@ namespace Org.BouncyCastle.Crmf
             signature.CopyTo(sig, sigOff);
             return signature.Length;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int Collect(Span<byte> destination)
+        {
+            byte[] result = Collect();
+            result.CopyTo(destination);
+            return result.Length;
+        }
+#endif
     }
 
     public class PKMacBuilder
diff --git a/crypto/src/crypto/Check.cs b/crypto/src/crypto/Check.cs
index 81d07e23c..36263dc24 100644
--- a/crypto/src/crypto/Check.cs
+++ b/crypto/src/crypto/Check.cs
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Crypto
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        internal static void DataLength(Span<byte> input, int len, string msg)
+        internal static void DataLength(ReadOnlySpan<byte> input, int len, string msg)
         {
             if (input.Length < len)
                 throw new DataLengthException(msg);
diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs
index 0f054fedc..3ed96a7c1 100644
--- a/crypto/src/crypto/IBlockResult.cs
+++ b/crypto/src/crypto/IBlockResult.cs
@@ -1,4 +1,5 @@
-
+using System;
+
 namespace Org.BouncyCastle.Crypto
 {
     /// <summary>
@@ -20,5 +21,14 @@ namespace Org.BouncyCastle.Crypto
         /// <param name="destination">The byte array to copy the result into.</param>
         /// <param name="offset">The offset into destination to start copying the result at.</param>
         int Collect(byte[] destination, int offset);
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        /// <summary>
+        /// Store the final result of the operation by copying it into the destination span.
+        /// </summary>
+        /// <returns>The number of bytes copied into destination.</returns>
+        /// <param name="destination">The span to copy the result into.</param>
+        int Collect(Span<byte> destination);
+#endif
     }
 }
diff --git a/crypto/src/crypto/SimpleBlockResult.cs b/crypto/src/crypto/SimpleBlockResult.cs
index 6cacda63f..35432c2b3 100644
--- a/crypto/src/crypto/SimpleBlockResult.cs
+++ b/crypto/src/crypto/SimpleBlockResult.cs
@@ -49,5 +49,14 @@ namespace Org.BouncyCastle.Crypto
 
             return result.Length;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int Collect(Span<byte> destination)
+        {
+            result.CopyTo(destination);
+
+            return result.Length;
+        }
+#endif
     }
 }
diff --git a/crypto/src/crypto/digests/RipeMD128Digest.cs b/crypto/src/crypto/digests/RipeMD128Digest.cs
index e8a0331ca..cba2c65d3 100644
--- a/crypto/src/crypto/digests/RipeMD128Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD128Digest.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -57,12 +58,9 @@ namespace Org.BouncyCastle.Crypto.Digests
 			return DigestLength;
 		}
 
-		internal override void ProcessWord(
-            byte[] input,
-            int inOff)
+		internal override void ProcessWord(byte[] input, int inOff)
         {
-            X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
-                | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+            X[xOff++] = (int)Pack.LE_To_UInt32(input, inOff);
 
             if (xOff == 16)
             {
@@ -82,27 +80,14 @@ namespace Org.BouncyCastle.Crypto.Digests
             X[15] = (int)((ulong) bitLength >> 32);
         }
 
-        private void UnpackWord(
-            int word,
-            byte[] outBytes,
-            int outOff)
-        {
-            outBytes[outOff]     = (byte)word;
-            outBytes[outOff + 1] = (byte)((uint) word >> 8);
-            outBytes[outOff + 2] = (byte)((uint) word >> 16);
-            outBytes[outOff + 3] = (byte)((uint) word >> 24);
-        }
-
-        public override int DoFinal(
-            byte[] output,
-            int outOff)
+        public override int DoFinal(byte[] output, int outOff)
         {
             Finish();
 
-            UnpackWord(H0, output, outOff);
-            UnpackWord(H1, output, outOff + 4);
-            UnpackWord(H2, output, outOff + 8);
-            UnpackWord(H3, output, outOff + 12);
+            Pack.UInt32_To_LE((uint)H0, output, outOff);
+            Pack.UInt32_To_LE((uint)H1, output, outOff + 4);
+            Pack.UInt32_To_LE((uint)H2, output, outOff + 8);
+            Pack.UInt32_To_LE((uint)H3, output, outOff + 12);
 
             Reset();
 
@@ -478,7 +463,5 @@ namespace Org.BouncyCastle.Crypto.Digests
 
 			CopyIn(d);
 		}
-
     }
-
 }
diff --git a/crypto/src/crypto/digests/RipeMD160Digest.cs b/crypto/src/crypto/digests/RipeMD160Digest.cs
index af4aa44bb..0fc2a4a1c 100644
--- a/crypto/src/crypto/digests/RipeMD160Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD160Digest.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -59,12 +60,9 @@ namespace Org.BouncyCastle.Crypto.Digests
 			return DigestLength;
 		}
 
-		internal override void ProcessWord(
-            byte[] input,
-            int inOff)
+		internal override void ProcessWord(byte[] input, int inOff)
         {
-            X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
-                | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+            X[xOff++] = (int)Pack.LE_To_UInt32(input, inOff);
 
             if (xOff == 16)
             {
@@ -72,7 +70,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             }
         }
 
-		internal override void ProcessLength(
+        internal override void ProcessLength(
             long bitLength)
         {
             if (xOff > 14)
@@ -84,28 +82,15 @@ namespace Org.BouncyCastle.Crypto.Digests
             X[15] = (int)((ulong) bitLength >> 32);
         }
 
-        private void UnpackWord(
-            int word,
-            byte[] outBytes,
-            int outOff)
-        {
-            outBytes[outOff]     = (byte)word;
-            outBytes[outOff + 1] = (byte)((uint) word >> 8);
-            outBytes[outOff + 2] = (byte)((uint) word >> 16);
-            outBytes[outOff + 3] = (byte)((uint) word >> 24);
-        }
-
-        public override int DoFinal(
-            byte[] output,
-            int outOff)
+        public override int DoFinal(byte[] output, int outOff)
         {
             Finish();
 
-            UnpackWord(H0, output, outOff);
-            UnpackWord(H1, output, outOff + 4);
-            UnpackWord(H2, output, outOff + 8);
-            UnpackWord(H3, output, outOff + 12);
-            UnpackWord(H4, output, outOff + 16);
+            Pack.UInt32_To_LE((uint)H0, output, outOff);
+            Pack.UInt32_To_LE((uint)H1, output, outOff + 4);
+            Pack.UInt32_To_LE((uint)H2, output, outOff + 8);
+            Pack.UInt32_To_LE((uint)H3, output, outOff + 12);
+            Pack.UInt32_To_LE((uint)H4, output, outOff + 16);
 
             Reset();
 
@@ -439,7 +424,5 @@ namespace Org.BouncyCastle.Crypto.Digests
 
 			CopyIn(d);
 		}
-
     }
-
 }
diff --git a/crypto/src/crypto/digests/RipeMD256Digest.cs b/crypto/src/crypto/digests/RipeMD256Digest.cs
index 306275767..621162a6f 100644
--- a/crypto/src/crypto/digests/RipeMD256Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD256Digest.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -59,12 +60,9 @@ namespace Org.BouncyCastle.Crypto.Digests
             xOff = t.xOff;
         }
 
-        internal override void ProcessWord(
-            byte[] input,
-            int inOff)
+        internal override void ProcessWord(byte[] input, int inOff)
         {
-            X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
-                | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+            X[xOff++] = (int)Pack.LE_To_UInt32(input, inOff);
 
             if (xOff == 16)
             {
@@ -84,29 +82,18 @@ namespace Org.BouncyCastle.Crypto.Digests
             X[15] = (int)((ulong)bitLength >> 32);
         }
 
-        private void UnpackWord(
-            int word,
-            byte[] outBytes,
-            int outOff)
-        {
-            outBytes[outOff] = (byte)(uint)word;
-            outBytes[outOff + 1] = (byte)((uint)word >> 8);
-            outBytes[outOff + 2] = (byte)((uint)word >> 16);
-            outBytes[outOff + 3] = (byte)((uint)word >> 24);
-        }
-
         public override int DoFinal(byte[] output, int outOff)
         {
             Finish();
 
-            UnpackWord(H0, output, outOff);
-            UnpackWord(H1, output, outOff + 4);
-            UnpackWord(H2, output, outOff + 8);
-            UnpackWord(H3, output, outOff + 12);
-            UnpackWord(H4, output, outOff + 16);
-            UnpackWord(H5, output, outOff + 20);
-            UnpackWord(H6, output, outOff + 24);
-            UnpackWord(H7, output, outOff + 28);
+            Pack.UInt32_To_LE((uint)H0, output, outOff);
+            Pack.UInt32_To_LE((uint)H1, output, outOff + 4);
+            Pack.UInt32_To_LE((uint)H2, output, outOff + 8);
+            Pack.UInt32_To_LE((uint)H3, output, outOff + 12);
+            Pack.UInt32_To_LE((uint)H4, output, outOff + 16);
+            Pack.UInt32_To_LE((uint)H5, output, outOff + 20);
+            Pack.UInt32_To_LE((uint)H6, output, outOff + 24);
+            Pack.UInt32_To_LE((uint)H7, output, outOff + 28);
 
             Reset();
 
@@ -425,6 +412,5 @@ namespace Org.BouncyCastle.Crypto.Digests
 
 			CopyIn(d);
 		}
-
     }
 }
diff --git a/crypto/src/crypto/digests/RipeMD320Digest.cs b/crypto/src/crypto/digests/RipeMD320Digest.cs
index 767d74dba..c46bc4fea 100644
--- a/crypto/src/crypto/digests/RipeMD320Digest.cs
+++ b/crypto/src/crypto/digests/RipeMD320Digest.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -62,12 +63,9 @@ namespace Org.BouncyCastle.Crypto.Digests
             xOff = t.xOff;
         }
 
-        internal override void ProcessWord(
-            byte[] input,
-            int inOff)
+        internal override void ProcessWord(byte[] input, int inOff)
         {
-            X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8)
-                | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24);
+            X[xOff++] = (int)Pack.LE_To_UInt32(input, inOff);
 
             if (xOff == 16)
             {
@@ -87,31 +85,20 @@ namespace Org.BouncyCastle.Crypto.Digests
             X[15] = (int)((ulong)bitLength >> 32);
         }
 
-        private void UnpackWord(
-            int word,
-            byte[] outBytes,
-            int outOff)
-        {
-            outBytes[outOff] = (byte)word;
-            outBytes[outOff + 1] = (byte)((uint)word >> 8);
-            outBytes[outOff + 2] = (byte)((uint)word >> 16);
-            outBytes[outOff + 3] = (byte)((uint)word >> 24);
-        }
-
         public override int DoFinal(byte[] output, int outOff)
         {
             Finish();
 
-            UnpackWord(H0, output, outOff);
-            UnpackWord(H1, output, outOff + 4);
-            UnpackWord(H2, output, outOff + 8);
-            UnpackWord(H3, output, outOff + 12);
-            UnpackWord(H4, output, outOff + 16);
-            UnpackWord(H5, output, outOff + 20);
-            UnpackWord(H6, output, outOff + 24);
-            UnpackWord(H7, output, outOff + 28);
-            UnpackWord(H8, output, outOff + 32);
-            UnpackWord(H9, output, outOff + 36);
+            Pack.UInt32_To_LE((uint)H0, output, outOff);
+            Pack.UInt32_To_LE((uint)H1, output, outOff + 4);
+            Pack.UInt32_To_LE((uint)H2, output, outOff + 8);
+            Pack.UInt32_To_LE((uint)H3, output, outOff + 12);
+            Pack.UInt32_To_LE((uint)H4, output, outOff + 16);
+            Pack.UInt32_To_LE((uint)H5, output, outOff + 20);
+            Pack.UInt32_To_LE((uint)H6, output, outOff + 24);
+            Pack.UInt32_To_LE((uint)H7, output, outOff + 28);
+            Pack.UInt32_To_LE((uint)H8, output, outOff + 32);
+            Pack.UInt32_To_LE((uint)H9, output, outOff + 36);
 
             Reset();
 
@@ -454,6 +441,5 @@ namespace Org.BouncyCastle.Crypto.Digests
 
 			CopyIn(d);
 		}
-
     }
 }
diff --git a/crypto/src/crypto/digests/SkeinEngine.cs b/crypto/src/crypto/digests/SkeinEngine.cs
index 2f38115d2..a36ac8fe7 100644
--- a/crypto/src/crypto/digests/SkeinEngine.cs
+++ b/crypto/src/crypto/digests/SkeinEngine.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 
@@ -75,7 +76,7 @@ namespace Org.BouncyCastle.Crypto.Digests
                 bytes[5] = 0;
 
                 // 8..15 = output length
-                ThreefishEngine.WordToBytes((ulong)outputSizeBits, bytes, 8);
+                Pack.UInt64_To_LE((ulong)outputSizeBits, bytes, 8);
             }
 
             public byte[] Bytes
@@ -441,10 +442,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             private void ProcessBlock(ulong[] output)
             {
                 engine.threefish.Init(true, engine.chain, tweak.GetWords());
-                for (int i = 0; i < message.Length; i++)
-                {
-                    message[i] = ThreefishEngine.BytesToWord(currentBlock, i * 8);
-                }
+                Pack.LE_To_UInt64(currentBlock, 0, message);
 
                 engine.threefish.ProcessBlock(message, output);
 
@@ -465,7 +463,6 @@ namespace Org.BouncyCastle.Crypto.Digests
                 tweak.Final = true;
                 ProcessBlock(output);
             }
-
         }
 
         /**
@@ -776,31 +773,28 @@ namespace Org.BouncyCastle.Crypto.Digests
         private void Output(ulong outputSequence, byte[] outBytes, int outOff, int outputBytes)
         {
             byte[] currentBytes = new byte[8];
-            ThreefishEngine.WordToBytes(outputSequence, currentBytes, 0);
+            Pack.UInt64_To_LE(outputSequence, currentBytes, 0);
 
-            // Output is a sequence of UBI invocations all of which use and preserve the pre-output
-            // state
+            // Output is a sequence of UBI invocations all of which use and preserve the pre-output state
             ulong[] outputWords = new ulong[chain.Length];
             UbiInit(PARAM_TYPE_OUTPUT);
             this.ubi.Update(currentBytes, 0, currentBytes.Length, outputWords);
             ubi.DoFinal(outputWords);
 
-            int wordsRequired = ((outputBytes + 8 - 1) / 8);
+            int wordsRequired = (outputBytes + 8 - 1) / 8;
             for (int i = 0; i < wordsRequired; i++)
             {
                 int toWrite = System.Math.Min(8, outputBytes - (i * 8));
                 if (toWrite == 8)
                 {
-                    ThreefishEngine.WordToBytes(outputWords[i], outBytes, outOff + (i * 8));
+                    Pack.UInt64_To_LE(outputWords[i], outBytes, outOff + (i * 8));
                 }
                 else
                 {
-                    ThreefishEngine.WordToBytes(outputWords[i], currentBytes, 0);
+                    Pack.UInt64_To_LE(outputWords[i], currentBytes, 0);
                     Array.Copy(currentBytes, 0, outBytes, outOff + (i * 8), toWrite);
                 }
             }
         }
-
     }
 }
-
diff --git a/crypto/src/crypto/digests/TigerDigest.cs b/crypto/src/crypto/digests/TigerDigest.cs
index ce9efdbed..a452d3f0b 100644
--- a/crypto/src/crypto/digests/TigerDigest.cs
+++ b/crypto/src/crypto/digests/TigerDigest.cs
@@ -1,6 +1,6 @@
 using System;
 
-using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -553,7 +553,7 @@ namespace Org.BouncyCastle.Crypto.Digests
         //
         // buffers
         //
-        private byte[]  Buffer = new byte[8];
+        private byte[]  m_buffer = new byte[8];
         private int     bOff;
 
         private long[]  x = new long[8];
@@ -591,18 +591,9 @@ namespace Org.BouncyCastle.Crypto.Digests
 			return MyByteLength;
 		}
 
-		private void ProcessWord(
-            byte[]  b,
-            int     off)
+		private void ProcessWord(byte[] b, int off)
         {
-            x[xOff++] =   ((long)(b[off + 7] & 0xff) << 56)
-                        | ((long)(b[off + 6] & 0xff) << 48)
-                        | ((long)(b[off + 5] & 0xff) << 40)
-                        | ((long)(b[off + 4] & 0xff) << 32)
-                        | ((long)(b[off + 3] & 0xff) << 24)
-                        | ((long)(b[off + 2] & 0xff) << 16)
-                        | ((long)(b[off + 1] & 0xff) << 8)
-                        | ((uint)(b[off + 0] & 0xff));
+            x[xOff++] = (long)Pack.LE_To_UInt64(b, off);
 
             if (xOff == x.Length)
             {
@@ -615,11 +606,11 @@ namespace Org.BouncyCastle.Crypto.Digests
         public void Update(
             byte input)
         {
-            Buffer[bOff++] = input;
+            m_buffer[bOff++] = input;
 
-            if (bOff == Buffer.Length)
+            if (bOff == m_buffer.Length)
             {
-                ProcessWord(Buffer, 0);
+                ProcessWord(m_buffer, 0);
             }
 
             byteCount++;
@@ -781,21 +772,6 @@ namespace Org.BouncyCastle.Crypto.Digests
             }
         }
 
-        private void UnpackWord(
-            long    r,
-            byte[]  output,
-            int     outOff)
-        {
-            output[outOff + 7]     = (byte)(r >> 56);
-            output[outOff + 6] = (byte)(r >> 48);
-            output[outOff + 5] = (byte)(r >> 40);
-            output[outOff + 4] = (byte)(r >> 32);
-            output[outOff + 3] = (byte)(r >> 24);
-            output[outOff + 2] = (byte)(r >> 16);
-            output[outOff + 1] = (byte)(r >> 8);
-            output[outOff] = (byte)r;
-        }
-
         private void ProcessLength(
             long    bitLength)
         {
@@ -824,9 +800,9 @@ namespace Org.BouncyCastle.Crypto.Digests
         {
             Finish();
 
-            UnpackWord(a, output, outOff);
-            UnpackWord(b, output, outOff + 8);
-            UnpackWord(c, output, outOff + 16);
+            Pack.UInt64_To_LE((ulong)a, output, outOff);
+            Pack.UInt64_To_LE((ulong)b, output, outOff + 8);
+            Pack.UInt64_To_LE((ulong)c, output, outOff + 16);
 
             Reset();
 
@@ -849,9 +825,9 @@ namespace Org.BouncyCastle.Crypto.Digests
             }
 
             bOff = 0;
-            for (int i = 0; i != Buffer.Length; i++)
+            for (int i = 0; i != m_buffer.Length; i++)
             {
-                Buffer[i] = 0;
+                m_buffer[i] = 0;
             }
 
             byteCount = 0;
@@ -873,11 +849,10 @@ namespace Org.BouncyCastle.Crypto.Digests
 			Array.Copy(t.x, 0, x, 0, t.x.Length);
 			xOff = t.xOff;
 
-			Array.Copy(t.Buffer, 0, Buffer, 0, t.Buffer.Length);
+			Array.Copy(t.m_buffer, 0, m_buffer, 0, t.m_buffer.Length);
 			bOff = t.bOff;
 
 			byteCount = t.byteCount;
 		}    
-
 	}
 }
diff --git a/crypto/src/crypto/engines/AesX86Engine.cs b/crypto/src/crypto/engines/AesX86Engine.cs
index a7dcfc686..a270c2ad2 100644
--- a/crypto/src/crypto/engines/AesX86Engine.cs
+++ b/crypto/src/crypto/engines/AesX86Engine.cs
@@ -190,7 +190,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return 16;
         }
 
-        public int ProcessBlock(Span<byte> input, Span<byte> output)
+        public int ProcessBlock(ReadOnlySpan<byte> input, Span<byte> output)
         {
             Check.DataLength(input, 16, "input buffer too short");
             Check.OutputLength(output, 16, "output buffer too short");
@@ -329,13 +329,13 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static Vector128<byte> Load128(Span<byte> t)
+        private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
         {
 #if NET7_0_OR_GREATER
             return Vector128.Create<byte>(t);
 #else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-                return Unsafe.ReadUnaligned<Vector128<byte>>(ref t[0]);
+                return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
 
             return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
                 t[13], t[14], t[15]);
@@ -343,13 +343,13 @@ namespace Org.BouncyCastle.Crypto.Engines
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static Vector64<byte> Load64(Span<byte> t)
+        private static Vector64<byte> Load64(ReadOnlySpan<byte> t)
         {
 #if NET7_0_OR_GREATER
             return Vector64.Create<byte>(t);
 #else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector64<byte>>() == 8)
-                return Unsafe.ReadUnaligned<Vector64<byte>>(ref t[0]);
+                return Unsafe.ReadUnaligned<Vector64<byte>>(ref Unsafe.AsRef(t[0]));
 
             return Vector64.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
 #endif
@@ -369,7 +369,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             var u = s.AsUInt64();
             Utilities.Pack.UInt64_To_LE(u.GetElement(0), t);
-            Utilities.Pack.UInt64_To_LE(u.GetElement(1), t.Slice(8));
+            Utilities.Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
 #endif
         }
     }
diff --git a/crypto/src/crypto/engines/ChaCha7539Engine.cs b/crypto/src/crypto/engines/ChaCha7539Engine.cs
index 81e97478b..d1dd9755b 100644
--- a/crypto/src/crypto/engines/ChaCha7539Engine.cs
+++ b/crypto/src/crypto/engines/ChaCha7539Engine.cs
@@ -168,7 +168,8 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 #if NETCOREAPP3_0_OR_GREATER
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
-		internal static void ImplProcessBlocks2_X86_Avx2(int rounds, uint[] state, Span<byte> input, Span<byte> output)
+		internal static void ImplProcessBlocks2_X86_Avx2(int rounds, uint[] state, ReadOnlySpan<byte> input,
+			Span<byte> output)
 		{
 			if (!Avx2.IsSupported)
 				throw new PlatformNotSupportedException();
@@ -244,18 +245,19 @@ namespace Org.BouncyCastle.Crypto.Engines
 			var n3 = Avx2.Permute2x128(v2, v3, 0x31).AsByte();
 
 			n0 = Avx2.Xor(n0, Load256_Byte(input));
-			n1 = Avx2.Xor(n1, Load256_Byte(input.Slice(0x20)));
-			n2 = Avx2.Xor(n2, Load256_Byte(input.Slice(0x40)));
-			n3 = Avx2.Xor(n3, Load256_Byte(input.Slice(0x60)));
+			n1 = Avx2.Xor(n1, Load256_Byte(input[0x20..]));
+			n2 = Avx2.Xor(n2, Load256_Byte(input[0x40..]));
+			n3 = Avx2.Xor(n3, Load256_Byte(input[0x60..]));
 
 			Store256_Byte(ref n0, output);
-			Store256_Byte(ref n1, output.Slice(0x20));
-			Store256_Byte(ref n2, output.Slice(0x40));
-			Store256_Byte(ref n3, output.Slice(0x60));
+			Store256_Byte(ref n1, output[0x20..]);
+			Store256_Byte(ref n2, output[0x40..]);
+			Store256_Byte(ref n3, output[0x60..]);
 		}
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-		internal static void ImplProcessBlocks2_X86_Sse2(int rounds, uint[] state, Span<byte> input, Span<byte> output)
+		internal static void ImplProcessBlocks2_X86_Sse2(int rounds, uint[] state, ReadOnlySpan<byte> input,
+			Span<byte> output)
 		{
 			if (!Sse2.IsSupported)
 				throw new PlatformNotSupportedException();
@@ -319,9 +321,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 			v3 = Sse2.Add(v3, x3);
 
 			var n0 = Load128_Byte(input);
-			var n1 = Load128_Byte(input.Slice(0x10));
-			var n2 = Load128_Byte(input.Slice(0x20));
-			var n3 = Load128_Byte(input.Slice(0x30));
+			var n1 = Load128_Byte(input[0x10..]);
+			var n2 = Load128_Byte(input[0x20..]);
+			var n3 = Load128_Byte(input[0x30..]);
 
 			n0 = Sse2.Xor(n0, v0.AsByte());
 			n1 = Sse2.Xor(n1, v1.AsByte());
@@ -329,9 +331,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 			n3 = Sse2.Xor(n3, v3.AsByte());
 
 			Store128_Byte(ref n0, output);
-			Store128_Byte(ref n1, output.Slice(0x10));
-			Store128_Byte(ref n2, output.Slice(0x20));
-			Store128_Byte(ref n3, output.Slice(0x30));
+			Store128_Byte(ref n1, output[0x10..]);
+			Store128_Byte(ref n2, output[0x20..]);
+			Store128_Byte(ref n3, output[0x30..]);
 
 			x3 = Load128_UInt32(state.AsSpan(12));
 			++state[12];
@@ -383,46 +385,46 @@ namespace Org.BouncyCastle.Crypto.Engines
 			v2 = Sse2.Add(v2, x2);
 			v3 = Sse2.Add(v3, x3);
 
-			n0 = Load128_Byte(input.Slice(0x40));
-			n1 = Load128_Byte(input.Slice(0x50));
-			n2 = Load128_Byte(input.Slice(0x60));
-			n3 = Load128_Byte(input.Slice(0x70));
+			n0 = Load128_Byte(input[0x40..]);
+			n1 = Load128_Byte(input[0x50..]);
+			n2 = Load128_Byte(input[0x60..]);
+			n3 = Load128_Byte(input[0x70..]);
 
 			n0 = Sse2.Xor(n0, v0.AsByte());
 			n1 = Sse2.Xor(n1, v1.AsByte());
 			n2 = Sse2.Xor(n2, v2.AsByte());
 			n3 = Sse2.Xor(n3, v3.AsByte());
 
-			Store128_Byte(ref n0, output.Slice(0x40));
-			Store128_Byte(ref n1, output.Slice(0x50));
-			Store128_Byte(ref n2, output.Slice(0x60));
-			Store128_Byte(ref n3, output.Slice(0x70));
+			Store128_Byte(ref n0, output[0x40..]);
+			Store128_Byte(ref n1, output[0x50..]);
+			Store128_Byte(ref n2, output[0x60..]);
+			Store128_Byte(ref n3, output[0x70..]);
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
-		private static Vector128<byte> Load128_Byte(Span<byte> t)
+		private static Vector128<byte> Load128_Byte(ReadOnlySpan<byte> t)
 		{
 			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-				return Unsafe.ReadUnaligned<Vector128<byte>>(ref t[0]);
+				return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
 
 			return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
 				t[13], t[14], t[15]);
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
-		private static Vector128<uint> Load128_UInt32(Span<uint> t)
+		private static Vector128<uint> Load128_UInt32(ReadOnlySpan<uint> t)
 		{
 			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
-				return Unsafe.ReadUnaligned<Vector128<uint>>(ref Unsafe.As<uint, byte>(ref t[0]));
+				return Unsafe.ReadUnaligned<Vector128<uint>>(ref Unsafe.As<uint, byte>(ref Unsafe.AsRef(t[0])));
 
 			return Vector128.Create(t[0], t[1], t[2], t[3]);
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
-		private static Vector256<byte> Load256_Byte(Span<byte> t)
+		private static Vector256<byte> Load256_Byte(ReadOnlySpan<byte> t)
         {
 			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
-				return Unsafe.ReadUnaligned<Vector256<byte>>(ref t[0]);
+				return Unsafe.ReadUnaligned<Vector256<byte>>(ref Unsafe.AsRef(t[0]));
 
 			return Vector256.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
 				t[13], t[14], t[15], t[16], t[17], t[18], t[19], t[20], t[21], t[22], t[23], t[24], t[25], t[26], t[27],
@@ -440,7 +442,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			var u = s.AsUInt64();
 			Pack.UInt64_To_LE(u.GetElement(0), t);
-			Pack.UInt64_To_LE(u.GetElement(1), t.Slice(8));
+			Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -454,9 +456,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			var u = s.AsUInt64();
 			Pack.UInt64_To_LE(u.GetElement(0), t);
-			Pack.UInt64_To_LE(u.GetElement(1), t.Slice(8));
-			Pack.UInt64_To_LE(u.GetElement(2), t.Slice(16));
-			Pack.UInt64_To_LE(u.GetElement(3), t.Slice(24));
+			Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
+			Pack.UInt64_To_LE(u.GetElement(2), t[16..]);
+			Pack.UInt64_To_LE(u.GetElement(3), t[24..]);
 		}
 #endif
 	}
diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs
index a16491ba0..646a6976c 100644
--- a/crypto/src/crypto/engines/ChaChaEngine.cs
+++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -213,10 +213,10 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 #if NETCOREAPP3_0_OR_GREATER
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
-		private static Vector128<uint> Load128_UInt32(Span<uint> t)
+		private static Vector128<uint> Load128_UInt32(ReadOnlySpan<uint> t)
 		{
 			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
-				return Unsafe.ReadUnaligned<Vector128<uint>>(ref Unsafe.As<uint, byte>(ref t[0]));
+				return Unsafe.ReadUnaligned<Vector128<uint>>(ref Unsafe.As<uint, byte>(ref Unsafe.AsRef(t[0])));
 
 			return Vector128.Create(t[0], t[1], t[2], t[3]);
 		}
@@ -232,7 +232,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			var u = s.AsUInt64();
 			Pack.UInt64_To_LE(u.GetElement(0), t);
-			Pack.UInt64_To_LE(u.GetElement(1), t.Slice(8));
+			Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
 		}
 #endif
 	}
diff --git a/crypto/src/crypto/engines/ThreefishEngine.cs b/crypto/src/crypto/engines/ThreefishEngine.cs
index eade3cc72..c5aee5395 100644
--- a/crypto/src/crypto/engines/ThreefishEngine.cs
+++ b/crypto/src/crypto/engines/ThreefishEngine.cs
@@ -135,18 +135,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			switch (blocksizeBits)
 			{
-				case BLOCKSIZE_256:
+			case BLOCKSIZE_256:
 				cipher = new Threefish256Cipher(kw, t);
 				break;
-				case BLOCKSIZE_512:
+			case BLOCKSIZE_512:
 				cipher = new Threefish512Cipher(kw, t);
 				break;
-				case BLOCKSIZE_1024:
+			case BLOCKSIZE_1024:
 				cipher = new Threefish1024Cipher(kw, t);
 				break;
-				default:
-				throw new ArgumentException(
-					"Invalid blocksize - Threefish is defined with block size of 256, 512, or 1024 bits");
+			default:
+				throw new ArgumentException("Invalid blocksize - Threefish is defined with block size of 256, 512, or 1024 bits");
 			}
 		}
 
@@ -189,10 +188,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 					                            + " bytes)");
 				}
 				keyWords = new ulong[blocksizeWords];
-				for (int i = 0; i < keyWords.Length; i++)
-				{
-					keyWords[i] = BytesToWord(keyBytes, i * 8);
-				}
+				Pack.LE_To_UInt64(keyBytes, 0, keyWords);
 			}
 			if (tweakBytes != null)
 			{
@@ -200,7 +196,8 @@ namespace Org.BouncyCastle.Crypto.Engines
 				{
 					throw new ArgumentException("Threefish tweak must be " + TWEAK_SIZE_BYTES + " bytes");
 				}
-				tweakWords = new ulong[]{BytesToWord(tweakBytes, 0), BytesToWord(tweakBytes, 8)};
+				tweakWords = new ulong[2];
+				Pack.LE_To_UInt64(tweakBytes, 0, tweakWords);
 			}
 			Init(forEncryption, keyWords, tweakWords);
 		}
@@ -298,16 +295,9 @@ namespace Org.BouncyCastle.Crypto.Engines
 				throw new DataLengthException("Input buffer too short");
 			}
 
-			for (int i = 0; i < blocksizeBytes; i += 8)
-			{
-				currentBlock[i >> 3] = BytesToWord(inBytes, inOff + i);
-			}
+			Pack.LE_To_UInt64(inBytes, inOff, currentBlock);
 			ProcessBlock(this.currentBlock, this.currentBlock);
-			for (int i = 0; i < blocksizeBytes; i += 8)
-			{
-				WordToBytes(this.currentBlock[i >> 3], outBytes, outOff + i);
-			}
-
+			Pack.UInt64_To_LE(currentBlock, outBytes, outOff);
 			return blocksizeBytes;
 		}
 
@@ -347,54 +337,6 @@ namespace Org.BouncyCastle.Crypto.Engines
 			return blocksizeWords;
 		}
 
-		/// <summary>
-		/// Read a single 64 bit word from input in LSB first order.
-		/// </summary>
-		internal static ulong BytesToWord(byte[] bytes, int off)
-		{
-			if ((off + 8) > bytes.Length)
-			{
-				// Help the JIT avoid index checks
-				throw new ArgumentException();
-			}
-
-			ulong word = 0;
-			int index = off;
-
-			word = (bytes[index++] & 0xffUL);
-			word |= (bytes[index++] & 0xffUL) << 8;
-			word |= (bytes[index++] & 0xffUL) << 16;
-			word |= (bytes[index++] & 0xffUL) << 24;
-			word |= (bytes[index++] & 0xffUL) << 32;
-			word |= (bytes[index++] & 0xffUL) << 40;
-			word |= (bytes[index++] & 0xffUL) << 48;
-			word |= (bytes[index++] & 0xffUL) << 56;
-
-			return word;
-		}
-
-		/// <summary>
-		/// Write a 64 bit word to output in LSB first order.
-		/// </summary>
-		internal static void WordToBytes(ulong word, byte[] bytes, int off)
-		{
-			if ((off + 8) > bytes.Length)
-			{
-				// Help the JIT avoid index checks
-				throw new ArgumentException();
-			}
-			int index = off;
-
-			bytes[index++] = (byte)word;
-			bytes[index++] = (byte)(word >> 8);
-			bytes[index++] = (byte)(word >> 16);
-			bytes[index++] = (byte)(word >> 24);
-			bytes[index++] = (byte)(word >> 32);
-			bytes[index++] = (byte)(word >> 40);
-			bytes[index++] = (byte)(word >> 48);
-			bytes[index++] = (byte)(word >> 56);
-		}
-
 		/**
 	     * Rotate left + xor part of the mix operation.
 	     */
diff --git a/crypto/src/crypto/operators/DefaultSignatureResult.cs b/crypto/src/crypto/operators/DefaultSignatureResult.cs
index 615f67dcb..a236838d6 100644
--- a/crypto/src/crypto/operators/DefaultSignatureResult.cs
+++ b/crypto/src/crypto/operators/DefaultSignatureResult.cs
@@ -23,5 +23,14 @@ namespace Org.BouncyCastle.Crypto.Operators
             signature.CopyTo(sig, sigOff);
             return signature.Length;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int Collect(Span<byte> destination)
+        {
+            byte[] result = Collect();
+            result.CopyTo(destination);
+            return result.Length;
+        }
+#endif
     }
 }
diff --git a/crypto/src/math/ec/custom/sec/SecT113Field.cs b/crypto/src/math/ec/custom/sec/SecT113Field.cs
index c41d9f7d7..65249562a 100644
--- a/crypto/src/math/ec/custom/sec/SecT113Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -166,6 +170,25 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11);
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1);
+                return;
+            }
+#endif
+
             /*
              * "Three-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
              */
diff --git a/crypto/src/math/ec/custom/sec/SecT131Field.cs b/crypto/src/math/ec/custom/sec/SecT131Field.cs
index 4ff5999a4..6088b264c 100644
--- a/crypto/src/math/ec/custom/sec/SecT131Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -194,6 +198,33 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var X2_ = Vector128.CreateScalar(x[2]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+                var Y2_ = Vector128.CreateScalar(y[2]);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y2_, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11),
+                                   Pclmulqdq.CarrylessMultiply(X2_, Y01, 0x00)));
+                var Z34 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y2_, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X2_, Y01, 0x10));
+                var Z4_ =          Pclmulqdq.CarrylessMultiply(X2_, Y2_, 0x00);
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1) ^ Z34.GetElement(0);
+                zz[4] = Z4_.GetElement(0) ^ Z34.GetElement(1);
+                return;
+            }
+#endif
+
             /*
              * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
              */
diff --git a/crypto/src/math/ec/custom/sec/SecT163Field.cs b/crypto/src/math/ec/custom/sec/SecT163Field.cs
index 44105039d..0c616600a 100644
--- a/crypto/src/math/ec/custom/sec/SecT163Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -205,6 +209,34 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var X2_ = Vector128.CreateScalar(x[2]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+                var Y2_ = Vector128.CreateScalar(y[2]);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y2_, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11),
+                                   Pclmulqdq.CarrylessMultiply(X2_, Y01, 0x00)));
+                var Z34 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y2_, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X2_, Y01, 0x10));
+                var Z45 =          Pclmulqdq.CarrylessMultiply(X2_, Y2_, 0x00);
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1) ^ Z34.GetElement(0);
+                zz[4] = Z45.GetElement(0) ^ Z34.GetElement(1);
+                zz[5] = Z45.GetElement(1);
+                return;
+            }
+#endif
+
             /*
              * "Five-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
              */
diff --git a/crypto/src/math/ec/custom/sec/SecT193Field.cs b/crypto/src/math/ec/custom/sec/SecT193Field.cs
index 59da8b000..4aa3ad5c2 100644
--- a/crypto/src/math/ec/custom/sec/SecT193Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -226,6 +230,38 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var X2_ = Vector128.CreateScalar(x[2]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+                var Y2_ = Vector128.CreateScalar(y[2]);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y2_, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11),
+                                   Pclmulqdq.CarrylessMultiply(X2_, Y01, 0x00)));
+                var Z34 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y2_, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X2_, Y01, 0x10));
+                var Z45 =          Pclmulqdq.CarrylessMultiply(X2_, Y2_, 0x00);
+
+                ulong X3M = 0UL - x[3];
+                ulong Y3M = 0UL - y[3];
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1) ^ Z34.GetElement(0) ^ (X3M & y[0]) ^ (x[0] & Y3M);
+                zz[4] = Z45.GetElement(0) ^ Z34.GetElement(1) ^ (X3M & y[1]) ^ (x[1] & Y3M);
+                zz[5] = Z45.GetElement(1)                     ^ (X3M & y[2]) ^ (x[2] & Y3M);
+                zz[6] =                                          X3M & y[3];
+                return;
+            }
+#endif
+
             /*
              * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
              */
diff --git a/crypto/src/math/ec/custom/sec/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs
index c16a3d612..e4e291154 100644
--- a/crypto/src/math/ec/custom/sec/SecT233Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -237,6 +241,54 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var X23 = Vector128.Create(x[2], x[3]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+                var Y23 = Vector128.Create(y[2], y[3]);
+                var X03 = Sse2.Xor(X01, X23);
+                var Y03 = Sse2.Xor(Y01, Y23);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11);
+
+                var Z45 =          Pclmulqdq.CarrylessMultiply(X23, Y23, 0x00);
+                var Z56 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y23, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X23, Y23, 0x10));
+                var Z67 =          Pclmulqdq.CarrylessMultiply(X23, Y23, 0x11);
+
+                var K01 =          Pclmulqdq.CarrylessMultiply(X03, Y03, 0x00);
+                var K12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X03, Y03, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X03, Y03, 0x10));
+                var K23 =          Pclmulqdq.CarrylessMultiply(X03, Y03, 0x11);
+
+                K01 = Sse2.Xor(K01, Z01);
+                K12 = Sse2.Xor(K12, Z12);
+                K23 = Sse2.Xor(K23, Z23);
+
+                K01 = Sse2.Xor(K01, Z45);
+                K12 = Sse2.Xor(K12, Z56);
+                K23 = Sse2.Xor(K23, Z67);
+
+                Z23 = Sse2.Xor(Z23, K01);
+                Z45 = Sse2.Xor(Z45, K23);
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1) ^ K12.GetElement(0);
+                zz[4] = Z45.GetElement(0) ^ K12.GetElement(1);
+                zz[5] = Z45.GetElement(1) ^ Z56.GetElement(0);
+                zz[6] = Z67.GetElement(0) ^ Z56.GetElement(1);
+                zz[7] = Z67.GetElement(1);
+                return;
+            }
+#endif
+
             /*
              * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
              */
diff --git a/crypto/src/math/ec/custom/sec/SecT239Field.cs b/crypto/src/math/ec/custom/sec/SecT239Field.cs
index de87b18a2..a3851de16 100644
--- a/crypto/src/math/ec/custom/sec/SecT239Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -246,6 +250,54 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var X23 = Vector128.Create(x[2], x[3]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+                var Y23 = Vector128.Create(y[2], y[3]);
+                var X03 = Sse2.Xor(X01, X23);
+                var Y03 = Sse2.Xor(Y01, Y23);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11);
+
+                var Z45 =          Pclmulqdq.CarrylessMultiply(X23, Y23, 0x00);
+                var Z56 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y23, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X23, Y23, 0x10));
+                var Z67 =          Pclmulqdq.CarrylessMultiply(X23, Y23, 0x11);
+
+                var K01 =          Pclmulqdq.CarrylessMultiply(X03, Y03, 0x00);
+                var K12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X03, Y03, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X03, Y03, 0x10));
+                var K23 =          Pclmulqdq.CarrylessMultiply(X03, Y03, 0x11);
+
+                K01 = Sse2.Xor(K01, Z01);
+                K12 = Sse2.Xor(K12, Z12);
+                K23 = Sse2.Xor(K23, Z23);
+
+                K01 = Sse2.Xor(K01, Z45);
+                K12 = Sse2.Xor(K12, Z56);
+                K23 = Sse2.Xor(K23, Z67);
+
+                Z23 = Sse2.Xor(Z23, K01);
+                Z45 = Sse2.Xor(Z45, K23);
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1) ^ K12.GetElement(0);
+                zz[4] = Z45.GetElement(0) ^ K12.GetElement(1);
+                zz[5] = Z45.GetElement(1) ^ Z56.GetElement(0);
+                zz[6] = Z67.GetElement(0) ^ Z56.GetElement(1);
+                zz[7] = Z67.GetElement(1);
+                return;
+            }
+#endif
+
             /*
              * "Two-level seven-way recursion" as described in "Batch binary Edwards", Daniel J. Bernstein.
              */
diff --git a/crypto/src/math/ec/custom/sec/SecT283Field.cs b/crypto/src/math/ec/custom/sec/SecT283Field.cs
index ee5ad89c5..334986452 100644
--- a/crypto/src/math/ec/custom/sec/SecT283Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -245,6 +249,56 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiply(ulong[] x, ulong[] y, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X01 = Vector128.Create(x[0], x[1]);
+                var X23 = Vector128.Create(x[2], x[3]);
+                var X4_ = Vector128.CreateScalar(x[4]);
+                var Y01 = Vector128.Create(y[0], y[1]);
+                var Y23 = Vector128.Create(y[2], y[3]);
+                var Y4_ = Vector128.CreateScalar(y[4]);
+
+                var Z01 =          Pclmulqdq.CarrylessMultiply(X01, Y01, 0x00);
+                var Z12 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X01, Y01, 0x10));
+                var Z23 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y23, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y01, 0x11),
+                                   Pclmulqdq.CarrylessMultiply(X23, Y01, 0x00)));
+                var Z34 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y23, 0x01),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y23, 0x10),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y01, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X23, Y01, 0x10))));
+                var Z45 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y4_, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y23, 0x11),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y23, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y01, 0x11),
+                                   Pclmulqdq.CarrylessMultiply(X4_, Y01, 0x00)))));
+                var Z56 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X01, Y4_, 0x01),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y23, 0x01),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y23, 0x10),
+                                   Pclmulqdq.CarrylessMultiply(X4_, Y01, 0x10))));
+                var Z67 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y4_, 0x00),
+                          Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y23, 0x11),
+                                   Pclmulqdq.CarrylessMultiply(X4_, Y23, 0x00)));
+                var Z78 = Sse2.Xor(Pclmulqdq.CarrylessMultiply(X23, Y4_, 0x01),
+                                   Pclmulqdq.CarrylessMultiply(X4_, Y23, 0x10));
+                var Z89 =          Pclmulqdq.CarrylessMultiply(X4_, Y4_, 0x00);
+
+                zz[0] = Z01.GetElement(0);
+                zz[1] = Z01.GetElement(1) ^ Z12.GetElement(0);
+                zz[2] = Z23.GetElement(0) ^ Z12.GetElement(1);
+                zz[3] = Z23.GetElement(1) ^ Z34.GetElement(0);
+                zz[4] = Z45.GetElement(0) ^ Z34.GetElement(1);
+                zz[5] = Z45.GetElement(1) ^ Z56.GetElement(0);
+                zz[6] = Z67.GetElement(0) ^ Z56.GetElement(1);
+                zz[7] = Z67.GetElement(1) ^ Z78.GetElement(0);
+                zz[8] = Z89.GetElement(0) ^ Z78.GetElement(1);
+                zz[9] = Z89.GetElement(1);
+                return;
+            }
+#endif
+
             /*
              * Formula (17) from "Some New Results on Binary Polynomial Multiplication",
              * Murat Cenk and M. Anwar Hasan.
diff --git a/crypto/src/math/ec/custom/sec/SecT409Field.cs b/crypto/src/math/ec/custom/sec/SecT409Field.cs
index 0fb7377f6..414a094a8 100644
--- a/crypto/src/math/ec/custom/sec/SecT409Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -1,5 +1,9 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Math.Raw;
 
@@ -344,6 +348,20 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             Debug.Assert(x >> 59 == 0);
             Debug.Assert(y >> 59 == 0);
 
+#if NETCOREAPP3_0_OR_GREATER
+            if (Pclmulqdq.IsSupported)
+            {
+                var X = Vector128.CreateScalar(x);
+                var Y = Vector128.CreateScalar(y);
+                var Z = Pclmulqdq.CarrylessMultiply(X, Y, 0x00);
+                ulong z0 = Z.GetElement(0);
+                ulong z1 = Z.GetElement(1);
+                z[zOff    ] ^= z0 & M59;
+                z[zOff + 1] ^= (z0 >> 59) ^ (z1 << 5);
+                return;
+            }
+#endif
+
             //u[0] = 0;
             u[1] = y;
             u[2] = u[1] << 1;
diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs
index 91a3fde9d..5a393409a 100644
--- a/crypto/src/math/ec/custom/sec/SecT571Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -175,6 +175,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public static ulong[] PrecompMultiplicand(ulong[] x)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            ulong[] z = Nat576.Create64();
+            Nat576.Copy64(x, z);
+            return z;
+#else
             /*
              * Precompute table of all 4-bit products of x (first section)
              */
@@ -197,6 +202,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             Nat.ShiftUpBits64(len, t, 0, 4, 0UL, t, len);
 
             return t;
+#endif
         }
 
         public static void Reduce(ulong[] xx, ulong[] z)
@@ -367,6 +373,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         protected static void ImplMultiplyPrecomp(ulong[] x, ulong[] precomp, ulong[] zz)
         {
+#if NETCOREAPP3_0_OR_GREATER
+            ImplMultiply(x, precomp, zz);
+#else
             uint MASK = 0xF;
 
             /*
@@ -399,6 +408,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
                     Nat.ShiftUpBits64(18, zz, 0, 8, 0UL);
                 }
             }
+#endif
         }
 
         protected static void ImplMulwAcc(ulong[] u, ulong x, ulong y, ulong[] z, int zOff)
diff --git a/crypto/src/ocsp/BasicOCSPRespGenerator.cs b/crypto/src/ocsp/BasicOCSPRespGenerator.cs
index d4ec3df80..63d577404 100644
--- a/crypto/src/ocsp/BasicOCSPRespGenerator.cs
+++ b/crypto/src/ocsp/BasicOCSPRespGenerator.cs
@@ -32,30 +32,11 @@ namespace Org.BouncyCastle.Ocsp
 			internal DerGeneralizedTime    nextUpdate;
 			internal X509Extensions        extensions;
 
-			public ResponseObject(
+			internal ResponseObject(
 				CertificateID		certId,
 				CertificateStatus	certStatus,
 				DateTime			thisUpdate,
-				X509Extensions		extensions)
-				: this(certId, certStatus, new DerGeneralizedTime(thisUpdate), null, extensions)
-			{
-			}
-
-			public ResponseObject(
-				CertificateID		certId,
-				CertificateStatus	certStatus,
-				DateTime			thisUpdate,
-				DateTime			nextUpdate,
-				X509Extensions		extensions)
-				: this(certId, certStatus, new DerGeneralizedTime(thisUpdate), new DerGeneralizedTime(nextUpdate), extensions)
-			{
-			}
-
-			private ResponseObject(
-				CertificateID		certId,
-				CertificateStatus	certStatus,
-				DerGeneralizedTime	thisUpdate,
-				DerGeneralizedTime	nextUpdate,
+				DateTime?			nextUpdate,
 				X509Extensions		extensions)
 			{
 				this.certId = certId;
@@ -79,8 +60,8 @@ namespace Org.BouncyCastle.Ocsp
 						new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason));
 				}
 
-				this.thisUpdate = thisUpdate;
-				this.nextUpdate = nextUpdate;
+				this.thisUpdate = new DerGeneralizedTime(thisUpdate);
+				this.nextUpdate = nextUpdate.HasValue ? new DerGeneralizedTime(nextUpdate.Value) : null;
 
 				this.extensions = extensions;
 			}
@@ -119,7 +100,7 @@ namespace Org.BouncyCastle.Ocsp
 			CertificateID		certID,
 			CertificateStatus	certStatus)
 		{
-			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null));
+			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null, null));
 		}
 
 		/**
@@ -134,7 +115,7 @@ namespace Org.BouncyCastle.Ocsp
 			CertificateStatus	certStatus,
 			X509Extensions		singleExtensions)
 		{
-			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, singleExtensions));
+			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, null, singleExtensions));
 		}
 
 		/**
@@ -148,7 +129,7 @@ namespace Org.BouncyCastle.Ocsp
 		public void AddResponse(
 			CertificateID		certID,
 			CertificateStatus	certStatus,
-			DateTime			nextUpdate,
+			DateTime?			nextUpdate,
 			X509Extensions		singleExtensions)
 		{
 			list.Add(new ResponseObject(certID, certStatus, DateTime.UtcNow, nextUpdate, singleExtensions));
@@ -167,7 +148,7 @@ namespace Org.BouncyCastle.Ocsp
 			CertificateID		certID,
 			CertificateStatus	certStatus,
 			DateTime			thisUpdate,
-			DateTime			nextUpdate,
+			DateTime?			nextUpdate,
 			X509Extensions		singleExtensions)
 		{
 			list.Add(new ResponseObject(certID, certStatus, thisUpdate, nextUpdate, singleExtensions));
@@ -230,7 +211,7 @@ namespace Org.BouncyCastle.Ocsp
 			DerSequence chainSeq = null;
 			if (chain != null && chain.Length > 0)
 			{
-				Asn1EncodableVector v = new Asn1EncodableVector();
+				Asn1EncodableVector v = new Asn1EncodableVector(chain.Length);
 				try
 				{
 					for (int i = 0; i != chain.Length; i++)
diff --git a/crypto/src/tls/AbstractTlsContext.cs b/crypto/src/tls/AbstractTlsContext.cs
index be7a67dfc..a5ac85962 100644
--- a/crypto/src/tls/AbstractTlsContext.cs
+++ b/crypto/src/tls/AbstractTlsContext.cs
@@ -170,6 +170,9 @@ namespace Org.BouncyCastle.Tls
 
             SecurityParameters securityParameters = SecurityParameters;
 
+            if (ChannelBinding.tls_exporter == channelBinding)
+                return ExportKeyingMaterial("EXPORTER-Channel-Binding", TlsUtilities.EmptyBytes, 32);
+
             if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion))
                 return null;
 
diff --git a/crypto/src/tls/ChannelBinding.cs b/crypto/src/tls/ChannelBinding.cs
index 84f8bc4df..d6e0cbe27 100644
--- a/crypto/src/tls/ChannelBinding.cs
+++ b/crypto/src/tls/ChannelBinding.cs
@@ -15,5 +15,10 @@ namespace Org.BouncyCastle.Tls
         public const int tls_server_end_point = 0;
         public const int tls_unique = 1;
         public const int tls_unique_for_telnet = 2;
+
+        /*
+         * RFC 9266
+         */
+        public const int tls_exporter = 3;
     }
 }
diff --git a/crypto/test/src/tls/test/MockTlsClient.cs b/crypto/test/src/tls/test/MockTlsClient.cs
index 98898dd30..731504757 100644
--- a/crypto/test/src/tls/test/MockTlsClient.cs
+++ b/crypto/test/src/tls/test/MockTlsClient.cs
@@ -127,6 +127,9 @@ namespace Org.BouncyCastle.Tls.Tests
 
                 byte[] tlsUnique = m_context.ExportChannelBinding(ChannelBinding.tls_unique);
                 Console.WriteLine("Client 'tls-unique': " + ToHexString(tlsUnique));
+
+                byte[] tlsExporter = m_context.ExportChannelBinding(ChannelBinding.tls_exporter);
+                Console.WriteLine("Client 'tls-exporter': " + ToHexString(tlsExporter));
             }
         }
 
diff --git a/crypto/test/src/tls/test/MockTlsServer.cs b/crypto/test/src/tls/test/MockTlsServer.cs
index d4e885117..c4aa2c74d 100644
--- a/crypto/test/src/tls/test/MockTlsServer.cs
+++ b/crypto/test/src/tls/test/MockTlsServer.cs
@@ -155,6 +155,9 @@ namespace Org.BouncyCastle.Tls.Tests
 
             byte[] tlsUnique = m_context.ExportChannelBinding(ChannelBinding.tls_unique);
             Console.WriteLine("Server 'tls-unique': " + ToHexString(tlsUnique));
+
+            byte[] tlsExporter = m_context.ExportChannelBinding(ChannelBinding.tls_exporter);
+            Console.WriteLine("Server 'tls-exporter': " + ToHexString(tlsExporter));
         }
 
         public override void ProcessClientExtensions(IDictionary<int, byte[]> clientExtensions)