C# 密码学高级教程(二)

原文:Pro Cryptography and Cryptanalysis

协议:CC BY-NC-SA 4.0

三、大整数运算

在复杂密码算法的复杂实现中,基于大整数的运算是难以实现的任务。大多数限制是由硬件设备(例如处理器、RAM 存储器)或编程语言造成的。

在 C# 中,整数值表示为 32 位。在这 32 位中,只有 31 位用于表示正整数运算。在密码学中,建议我们处理 20 亿的数字,2 ^ 109

大多数编译器,比如 GCC,都提供了long long type。这提供了拥有大约 9 万亿分之一,9 ^ 1018的整数的能力。

以下示例显示了 RSA (Rivest-Shamir-Adleman)公钥加密密码系统,它需要大约 300 位数字。当处理真实事件及其概率时,在大多数情况下,计算将涉及非常大的数字。对于 C# 来说,获得主要结果可能是准确的,但是与其他困难的计算相比,我们将拥有非常大的数量。

考虑下面这个众所周知的例子:计算只有一张彩票的彩票中头奖的几率。组合数是 50 取 6 一次,“50 选 6”是)。计算过程得到的数字是 15.890.700,所以在这种情况下,获胜的几率是 1/15,890,700。如果我们用 C# 编程语言来实现,15890700 这个数字可以非常容易地表示出来。这可能会很棘手,然后我们可能会在实施 50 的过程中陷入幼稚!(使用 Windows 中的计算器计算),即 3.041409320171e+64 或

30,414,093,201,713,378,043,612,608,166,064,768,844,377,641,568,960,512,000,000,000,000

用 C # 来表示这个数字几乎是不可能的,即使我们使用的是 64 位平台。

在接下来的几节中,我们将讨论一些可用于大整数算术运算的算法。请注意,由于我们使用的是加密算法和认证协议,这可能很难实现,因为我们处理的是大整数。下面我们将展示如何处理大数的一步一步的方法。

图 3-1 和清单 3-1 显示了大整数功能的完整实现。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 3-1

计算 GCD 的 BigInteger 示例

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Numerics;

namespace BigIntExample
{
    class Program
    {
        static void Main(string[] args)
        {
            //** compute bigger factorials
            Console.Write("Enter a factorial to be computed (>100) :  ");
            int factorial = Convert.ToInt32(Console.ReadLine());
            ComputeBigFactorial(factorial);

            Console.WriteLine(Environment.NewLine);

            //** compute sum of the first
            //** even number to get Fibonacci Series
            Console.WriteLine("Enter a number for the " +
                "first even set (>= 100 000) : ");
            int evenNumberFib = Convert.ToInt32(Console.ReadLine());
            SumOfFirstOneLacEvenFibonacciSeries(evenNumberFib);
            Console.WriteLine(Environment.NewLine);

            //** computing greatest common divisor
            Console.WriteLine("GCD = " +
                    BigInteger.GreatestCommonDivisor(12, 24));

            //** comparing purpose

            BigInteger value1 = 10;
            BigInteger value2 = 100;

            switch (BigInteger.Compare(value1, value2))
            {
                case -1:
                    Console.WriteLine("{0} < {1}", value1, value2);
                    break;
                case 0:
                    Console.WriteLine("{0} = {1}", value1, value2);
                    break;
                case 1:
                    Console.WriteLine("{0} > {1}", value1, value2);
                    break;
            }

            //** parsing
            Console.WriteLine(BigInteger.Parse("10000000"));

            //** obtaining negation
            Console.WriteLine(BigInteger.Negate(-100));

            //** returning the sign
            Console.WriteLine(BigInteger.Negate(-1).Sign);

            //** returning conversion (int to BigInterger)
            int i = 100;
            BigInteger bI = (BigInteger)i;
            Console.WriteLine(bI);

            //** returning conversion (BigInteger to int)
            BigInteger BI = 200;
            int j = (int)BI;
            Console.WriteLine(j);
            Console.Read();
        }

        //** computing the factorials

        private static void ComputeBigFactorial(int factorial)
        {
            BigInteger number = factorial;
            BigInteger fact = 1;
            for (; number-- > 0; ) fact *= number+1;
            Console.WriteLine(fact);
        }

        //** computing the first even fibonacci series
        private static void SumOfFirstOneLacEvenFibonacciSeries(
                        int evenNumberFib)
        {
            int limit = evenNumberFib;

            BigInteger value1 = 1;
            BigInteger value2 = 2;
            BigInteger theSum = 0;
            BigInteger even_sum = value1 + value2;

            for (int i = 2; i < limit; i++)
            {
                theSum = value1 + value2;
                if (theSum % 2 == 0) even_sum += theSum;
                value1 = value2;
                value2 = theSum;
            }

            Console.WriteLine(even_sum);
        }
    }
}

Listing 3-1BigInteger Implementation

首先,我们需要在一个大整数中使用不同的计算来转换一个标准整数。为了做到这一点,我们编写了一个名为transformIntToBigInt(A, 123)的函数。该功能的目的是将 A 初始化为A[0]=3A[1]=2A[2]=1,并将剩余位置归零为A[3,...N-1]。清单 3-2 展示了如何通过使用一个简单的 C# 实现来完成上面的语句。在这个例子中,基址代表位符号。

public void TransformIntToBigInt(int BigNo[], int number)
{
      Int   k;

      //** start indexing with 0 position
      k = 0;

      // if we still have something left
      // within the number, continue
      while (number) {
            // insert the digit that is least significant
            // into BigNo[k] number
            BigNo[k++] = number % bitSign;

            // we don't need the least significant bit
            number /= BASE;
      }

      // complete the remain of the array with zeroes
      while (k < N)
            BigNo[k++] = 0;
}

Listing 3-2Transforming a Standard Integer Using Different Computations in a Big Integer

来自清单 3-2 的算法有 O ( N )空间和时间。

让我们继续我们的旅程,看看给一个大 int 加 1 的可能性。这个过程非常有用,在密码学中经常使用。清单 3-3 中的函数比总加法简单得多。

public void increment (int BigNo [])
{
      Int i;

      // start indexing with least significant digit
      i = 0;
      while (i < N)
      {

            // increment the digit
            BigNo[i]++;

            // if it overflows
            if (BigNo[i] == BASE)
            {

                  // make it zero and move the index to next
                  BigNo[i] = 0;
                  i++;
            }
            else
                  // else, we are done!
                  break;
      }
}

Listing 3-3Adding One to a Big Int

清单 3-2 中描述的算法对于可能的最坏情况有 O ( n )(想象一下类似于 99999999999999999999…)和ω(1)表示最佳情况。最好的情况发生在最低有效位没有溢出的时候。

继续,让我们仔细看看两个大整数相加的方法。在这种情况下,我们希望在两个不同的数组中添加两个大整数,BigNo1[0,…,N-1]和 BigNo2[0,…,N-1]。结果将保存在另一个数组 BigNo3[0,…,N-1]中。算法很基础,没什么花哨的。参见清单 3-4 。

public void addition(int BigNo1[], int BigNo2[], int BigNo3[])
{
      Int j, overflowCarry, sum;

      //** there is no necessary to carry at this moment
      carry = 0;

      //** move from the least to the most significant digit
      for (j=0; j<N; j++)
      {
            // the digit placed on j'th position of BigNo3[]
            // is the sum of j'th digits of
            // BigNo1[] and BigNo2[] and including the
            // overvflow carry
            sum = BigNo1[j] + BigNo2[j] + overflowCarry;

            // if the sum will go out of the base then
            // we will find ourself in an overflow situation
            if (sum >= BASE)
            {
                  carry = 1;

                  //** making adjustment in such way that
                  //** the sum will fit within a digit
                  sum -= BASE;
            }
            else
                  //otherwise no carryOverflow
                  carry = 0;

            // use the same sum variable to add the
            BigNo3[j] = sum;
      }

      // once we reached to the end
      // we can expect an overflow
      if (carry)
            printf ("There is an overflow in the addition!\n");
}

Listing 3-4Addition Algorithm

接下来,我们将重点讨论乘法。我们将使用一个基本的方法,将两个大数字相乘, XY ,将每个 X 数字与每个 Y 数字相乘,因此输出成为一个组成元素。每个新数字的绩效结果向左移动。我们实现的函数,multiplyingOneDigit,将把一个整数和一个数字相乘。结果将被放入一个新的大整数中。我们还将展示另一个函数,left_shifting,,它将数字向左移动一定数量的空格。用 b i 相乘,其中 b 为基数, i 表示空格数。清单 3-5 展示了乘法算法。

public void multiply (int BigInt1[], int BigInt2[],
                                   int BigInt3[])
{
      Int x, y, P[integer_length];

      // BigInt3 will store the sum of
      // partial products.  The value is set to 0.
      buildInteger (BigInt3, 0);

      // for each digit in BigInt1
      for (x=0; x<length_of_integer; x++)
      {
           // multiply BigInt2 with digit [x]
           multiplyOneDigit(BigInt2, P, BigInt1[x]);

           // left shifting the partial product with i bytes
           leftShifting(P, x);

           // add the output result to the current sum
           addResult(BigInt3, P, BigInt3);
      }
}

Listing 3-5Multiplication Algorithim

在清单 3-6 中,我们将检查一个乘以一位数的函数。

public void multiplyUsingOneDigit (int BigOne1[], int
                                       BigOne2[], int number)
{
      Int k, carryOverflow;

      // we don't need extraflow for the moment
      carryOverflow = 0;

      // for each digit, starting with least significant...
      for (k=0; k<N; k++)
      {
           // multiply the digit with the number,
           // save the result in BigOne2
           BigOne2[k] = number * BigOne1[k];

           // set extra overflow that is taking
           // place starting with the last digit
           BigOne2[k] += carryOverflow;

           // product is too big to fit in a digit
           if (BigOne2[k] >= BASE)
           {
                  //** handle the overflow
                  carryOverflow = B[k] / BASE;
                  BigOne2[k] %= BASE;
           }
           else
                  // no overflow
                  carryOverflow = 0;
      }
      if (carryOverflow)
            printf ("During the multiplication
                            we experienced an overflow!\n");
}

Listing 3-6Multiplying Using a Single Digit

清单 3-7 显示了一个将向左移动特定数量空格的函数操作。

public void leftShifting (int BigInt1[], int number) {
      int i;

      //start from left to right,
      // everything with left n spaces
      for (i=N-1; i>= number; i--)
           BigInt1[i] = BigInt1[i- number];

      // complete the last n digits with zeros
      while (i >= 0) BigInt1[i--] = 0;
}

Listing 3-7Shifting to Left a Specific Number of Spaces

在 C# 中使用大整数

.NET Framework 4.0 提供了System.Numerics.BigInteger类,该类基于Microsoft.SolverFoundation.Common.BigInteger

在设计和开发加密算法时,使用BigInteger非常有用。BigInteger表示不可变类型,用于没有上限或下限的大数。特征BigInteger类的成员是ByteInt(所有三种表示:16、32 和 64)、SByteUInt (16、32 和 64)类型。

如何使用 BigInteger 类

创建BigInteger对象有几种方法:

  • 使用new关键字并将任何浮点值作为参数提供给类的构造函数。参见清单 3-8 。

  • 通过声明一个赋值的BigInteger变量。参见清单 3-9 。

BigInteger publicCryptographyKeyFromDouble
                              = new BigInteger(131312.3454354353);
Console.WriteLine(publicCryptographyKeyFromDouble);

BigInteger publicCryptographyKeyFromInt64
                              = new BigInteger(7587643562354635);
Console.WriteLine(publicCryptographyKeyFromInt64);

Listing 3-8Using the new Keyword with BigInteger

  • 通过给一个BigInteger对象分配一个十进制或浮点值。在赋值发生之前,首先需要将值转换为BigInteger。见清单 3-10 。
long publicCryptographyKey = 87432541632312;
BigInteger cryptoPubKey = publicCryptographyKey;
Console.WriteLine(cryptoPubKey);

Listing 3-9Using a Variable with a Value Assigned

BigInteger publicCryptographyKeyFromDoubleValue
                                 = (BigInteger) 423412.3423;
Console.WriteLine(publicCryptographyKeyFromDoubleValue);

BigInteger publicCryptographyFromDecimal
                                 = (BigInteger) 23452.34m;
Console.WriteLine(publicCryptographyFromDecimal);

Listing 3-10Casting to BigIntegers

的大整数库。网

当我们在密码学中处理大整数时,64 位对于数字来说是不够的。这一节将介绍一个名为 RSA 的复杂密码系统的例子,我们将展示一些关于 .NET BigInteger类和其他。网络图书馆。

如上节所示,System.Numerics.BigIntegers是从开始引入的 .NET Framework 4.0,清单 3-11 中的简单示例展示了如何以不同于上面的其他示例的方式使用它。

var publicCryptoKey = BigInteger.Parse("5845829436572843562734865972843659784564");

var privateCryptoKey = BigInteger.Parse("245245452345252342435543527362524323455");

Listing 3-11Using System.Numerics.BigIntegers

任何运算(加、乘、除、差等。)使用publicCryptoKeyprivateCryptoKey是可能的。

良好操作规范

GMP [2 是一个命名空间,也称为 Emil,以 Emil Stefanov 命名。它结合了 F# 中 BigInt 的强大功能。这个库的缺点是它只能在 32 位系统上实现。C# 中的例子看起来与使用BigInteger的例子非常相似。参见清单 3-12 。

var publicCryptoKey = BigInt ("5845829436572843562734865972843659784564");

var privateCryptoKey = BigInt ("245245452345252342435543527362524323455");

Listing 3-12Using GMP

MPIR

MPIR [3 可以看做是 GMP [2 的一个分叉。MPIR 的目的是给 Windows 上的编译过程一个任何专业开发人员都想在他们的工具包中拥有的有味道和无痛的过程。

为了在美国使用 MPIR .NET 中,一些包装器是必要的,比如DLLImportsGetProcAddress赋值。一个非常好的可以使用的包装器是 X-MPIR,由来自阿尔吉利布 [4 ]的 Sergey Bochkanov 提出并开发。

清单 3-13 中的代码展示了如何使用 MPIR 开发复杂的密码系统。

var publicKey = mpir.mpz_init_set_str("4657334563546345", 10);
var sessionKey = mpir.mpz_init_set_str("784567354634564", 10);
var exampleOfOperation = mpir.mpz_init();

//** random operations
mpir.mpz_mul(exampleOfOperation, publicKey, sessionKey);

//** Implement the cryptosystem operations as you like **//

//** it is recommended to invoke clear
//** method in order to avoid any memory leakage
mpir.mpz_clear(publicKey);
mpir.mpz_clear(sessionKey);
mpir.mpz_clear(exampleOfOperation);

Listing 3-13Using MPIR

结论

在这一章中,我们介绍了表示大整数的最重要的方面,以及它们是如何设计和实现的。

  • 我们分析了处理大数的基本方法的实现的技术方面。

  • 我们展示了来自 .NET Framework 4.0 并展示了如何使用BigInteger对象。

  • 我们包括了其他处理大整数的库,比如 GMP 和 MPIR。

文献学

  1. BigInteger阶级。网上有: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?redirectedfrom=MSDN&view=netcore-3.1

  2. 没有限制的 GMP 算法。网上有: https://gm.plib.org /

  3. Mpir.NET。网上有: http://wezeku.github.io/Mpir.NET/

  4. 阿尔格里卜。网上有: www.alglib.net/

四、浮点运算

处理大整数可以被视为一种抽象艺术,如果密码系统没有正确实现,整个密码算法或方案可能会导致真正的灾难。本章重点介绍浮点运算及其对密码学的重要性。

为什么是浮点运算?

浮点运算代表了一种特殊形式的运算,我们需要关注它,因为它在密码学领域中的应用,如基于混沌的密码学、同态加密、量子密码术等等。这种类型的算法可以在基于混沌的加密或同态加密中观察到,这将在第 14 和 16 章中介绍。

在使用小实数和非常大的实数的系统中,也可以找到使用浮点数的计算。在他们的计算过程中,过程必须非常快。

浮点变量是一类特殊的变量,可以保存实数,如 4534.0、5.232 或 0.005443。浮动部分意味着小数点会“浮动”

C# 提供不同的浮点数据类型,如float double SByte *。*正如您从 C++或其他具有整数情况的编程语言中所知,该语言没有为这些类型定义任何大小。在现代体系结构中,大多数浮点表示都遵循二进制表示格式的 IEEE 754 标准。按照这个标准,float类型有 4 个字节,double有 8 个字节,long double有 8 个字节(与double相同),也是 80 位(通过填充我们有 12 个字节或 16 个字节)。

当您处理浮点值时,请确保至少有一个小数。这有助于编译器区分浮点数和整数。以下声明示例显示了如何声明和初始化变量:

int a = 4;        //** 4 is an integer
double b = 3.0    //** 3.0 represents a floating point (with no
                  //** suffix – double type by default)

显示浮点数

让我们考虑清单 4-1 中的例子。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CommonFloatNumbers
{
    class Program
    {
        static void Main(string[] args)
        {
            float cryptoKey1 = 5.0f;
            float cryptoKey2 = 6.7f;

            Console.WriteLine(cryptoKey1);
            Console.WriteLine(cryptoKey2);

            Console.ReadKey();

        }
    }
}

Listing 4-1Displaying Common Float Numbers

输出如图 4-1 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-1

普通浮点数的输出

通过查看程序的输出,您可以发现在第一种情况下,输出是 5 个字节,但是源代码显示的是 5.0。这是因为小数部分等于 0。在第二种情况下,打印的数字与源代码中的数字相同。在第三种情况下,数字使用科学记数法显示,这是加密算法的重要资产。

浮点的范围

让我们来看看 IEEE 754 表示,并考虑以下尺寸及其范围和精度。见表 4-1 。

表 4-1

IEEE 754 标准表示法

|

大小

|

范围

|

精确

|
| — | — | — |
| 4 字节 | 1.18×10—38 3.4 × 10 38 | 6-9 个最重要的数字。通常在 7 位数左右。 |
| 8 字节 | 2.23×10—308 1.80 × 10 308 | 15-18 个最重要的数字。通常在 16 位数左右。 |
| 80 位(通常使用 12 或 16 字节) | 3.36×10—4932 1.18 × 10 4932 | 18-21 个最重要的数字 |
| 16 字节 | 3.36×10—4932 1.18 × 10 4932 | 33-36 位最重要的数字 |

在当今的处理器上,80 位浮点是用 12 或 16 字节实现的。处理器能够管理这种大小是很常见的。

浮点精度

让我们考虑下面这个用分数表示的例子:)。十进制表示是 0.3333333…无穷大 3 s

使用一台机器,需要无限的内存来存储无限长的数。这种内存限制会将浮点数的存储限制为特定数量的有效数字。浮点数及其精度将决定在不丢失任何知识的情况下可以表达多少有效数字。如果我们确实在密码学中产生了一个浮点数,清单 4-2 中的例子展示了如何将值截断为六位数。输出见图 4-2 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-2

浮点精度的输出

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FloatingValues
{
    class Program
    {
        static void Main(string[] args)
        {
            float cryptoKey1 = 7.56756767f;
            float cryptoKey2 = 765.657667f;
            float cryptoKey3 = 345543.564f;
            float cryptoKey4 = 9976544.43f;
            float cryptoKey5 = 0.00043534345f;

            Console.WriteLine("cryptoKey1 = " + cryptoKey1);
            Console.WriteLine("cryptoKey2 = " + cryptoKey2);
            Console.WriteLine("cryptoKey3 = " + cryptoKey3);
            Console.WriteLine("cryptoKey4 = " + cryptoKey4);
            Console.WriteLine("cryptoKey5 = " + cryptoKey5);

        }
    }
}

Listing 4-2Representation of Floating Point Precision

请注意,上面的每个案例只有六个重要数字。

通常,根据所使用的编译器,指数将在最小位数内填充。指数的位数取决于所使用的编译器,例如 Visual Studio 使用 3,而其他编译器使用 2(使用符合 C99 的指令和标准实现)。表示浮点数的位数及其精度取决于大小和存储的特定值。float值的定义精度为 6 和 9 位数字,大多数值至少有 7 位有效数字。double值以 15 位和 18 位精度表示。Long double值至少由 15 或 33 位有效数字表示,这取决于字节的占用情况。

浮点运算的下一级

在第十四章中,我们将介绍一种复杂类型的加密。同态加密代表一种特殊类型的加密,被用作保护隐私的专业技术。这项技术将存储和计算外包出去。这种加密方式允许数据被加密并外包给商业(或公共)环境,目的是处理它们。所有这些过程都是在数据加密时发生的。同态加密源自带错误的环学习(见第十五章),与私有集合交集 [1 ]相关。

继续我们的复杂密码系统之旅,浮点表示法代表了加密/解密机制的热点,它通过寻找适当的方法来近似一个实数,从而支持范围和精度之间的折衷。

如上所述,浮点术语表示数字的小数点可以浮动。总之,它可以设置在数字的重要数字内的任何位置。更具体地说,当我们着眼于复杂的密码体制时,比如同态加密,一个浮点数一个可以表示为四个整数,所以在

)

n 为基数, f 为指数, j 为精度, d 为重要或有效位。重要性或有效位 d 必须满足以下关系:

)

从 with.NET 框架 4.0 开始,有一个庞大的浮点操作例程集 [8 ]。从 C# 8.0 开始,这些基本函数用于基于与浮点数相关的简单数学计算来工作和完成任务,这是普通编程和加密(低级和简单的概念)所必需的。对于高级加密算法,该函数的能力和对大浮点数的要求非常有限,并且它们不能为密码学家提供合适的设备。

下面我们将研究 IEEE 处理浮点的标准化和实现函数。与上面已经给出的应用相比,这个应用稍微复杂一些。也就是说,应用的结构包含三个类:IEEEStandardization.cs(参见清单 4-3 )、FloatingPoint.cs(参见清单 4-4 )和Program.cs(参见清单 4-5 )。下面的应用是根据 IEEE 标准开发的,展示了如何以较少的努力实现主要操作。

在清单 4-3 中,我们可以看到处理浮点值时返回的值的主要类型。这些值表示为枚举类型,包含从规范化到反规范化的值、非数字字符和符号值。在清单 4-4 中,我们实现了获取双二进制表示部分的方法、IEEE-754 标准操作的实现以及单精度位转换的方法。在清单 4-5 中,我们将所有的方法合并到一个主程序中,并让它工作,展示了我们如何使用不同的方法来计算浮点值、乘法结果和减法。见图 4-3 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 4-3

基于 IEEE 标准化的复杂浮点运算

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FloatingPointArithmetic
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("FLOATING POINT ARITHMETIC " +
                "by Marius Iulian MIHAILESCU " +
                "and Stefania Loredana NITA \n");

            Console.WriteLine("\t\tDifferent ways of computing 1/105.");
            Console.WriteLine("\t\tMultiply the output with 105 and subtract 1");
            Console.WriteLine("\t\tWe will get an error.");

            double d = 1 / 105.0;
            float s = 1 / 105.0F;

            Console.WriteLine("\t\t\tUsing double: {0} * " +
                "105 - 1 = {1} < 0!", d, d * 105.0 - 1.0);
            Console.WriteLine("\t\t\tUsing single: {0} * " +
                "105 - 1 = {1} > 0!", s, s * 105.0 - 1.0);
            Console.WriteLine();

            Console.WriteLine("\t\tComputing a chaos-based " +
                "value for cryptography purpose.");
            float chaotic_value = 4.99F * 17;
            Console.WriteLine("\t\t\tThe chaotic value is " +
                "{0}.", chaotic_value);
            Console.WriteLine();

            Console.WriteLine("\t\tAnother example of chaotic " +
                "value for which we need the integer part.");
            int another_chaotic_value = (int)(100 * (1 - 0.1F));
            Console.WriteLine("\t\t\tAnother chaotic value is {0}.",
                another_chaotic_value);
            Console.WriteLine();

            Console.WriteLine("\t\tFor cryptography is " +
                "important to have an implementation " +
                "for IEEE-754");
            double[] double_values = new double[] { 0, -1 /
                Double.PositiveInfinity, 1, -1,
                //Math.PI,
                //Math.Exp(20),
                //Math.Exp(-20),
                //Double.PositiveInfinity,
                //Double.NegativeInfinity,
                //Double.NaN,
                //Double.Epsilon,
                // -Double.Epsilon,
                //10 / Double.MaxValue
            };

            for (int i = 0; i < double_values.Length; i++)
            {
                Console.WriteLine("\t\t\tIEEE-754 Value Type({0}) = {1}",
                    double_values[i],
                    FloatingPoint.Class(double_values[i]));

                Console.WriteLine("\t\t\t{0,19:E8}{1,19:E8}{2,19}{3,19}",
                    FloatingPoint.ComputerNextValue(double_values[i],
                        Double.PositiveInfinity) - double_values[i],

                    FloatingPoint.ComputerNextValue(double_values[i],
                    Double.NegativeInfinity) - double_values[i],

                    FloatingPoint.ComputingLogB(double_values[i]),
                    FloatingPoint.ReuturnSignificantMantissa(double_values[i]));
            }
            Console.ReadLine();
        }
    }
}

Listing 4-5Main Program Implementation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FloatingPointArithmetic
{
    public sealed class FloatingPoint
    {
        #region variable and instances
            // the constructor of the class
            private FloatingPoint() { }

            // the value for conversion is 2⁶⁰
            // 2⁶⁰ = 1,152,921,504,606,846,976 (decimal base)
            // 2⁶⁰ = 10 00 00 00 00 00 00 00 (hex bytes)
            // 8 * 2⁶⁰ = 2 * 1,152,921,504,606,846,976 =
            //          = 2,305,843,009,213,693,952
            // we will use "unchecked" for supressing overflow-checking
            // for integral-type arithmetic operations and conversions
            private static readonly double UnfavorableNegativeValue
                = BitConverter.Int64BitsToDouble(unchecked(8 * 0x1000000000000000));

            // constants
            private const Double minimum_double = 4.94065645841247e-324;

            // 0x7FFFFFFFFFFFFFFF = 9,223,372,036,854,775,807 (decimal)
            private const long mask_sign_value = -1 - 0x7FFFFFFFFFFFFFFF;
            private const long clear_mask_sign = 0x7FFFFFFFFFFFFFFF;

            private const long signficand_mask = 0xFFFFFFFFFFFFF;
            private const long clearing_significand_mask = mask_sign_value | significand_exponent_mask;

            private const long significand_exponent_mask = 0x7FF0000000000000;
            private const long clearing_exponent_mask = mask_sign_value | signficand_mask;

            private const int deviation = 1023;
        private const int significant_bits = 52;
        #endregion

        #region Methods for getting parts of a double's binary representation.

            // the method return the significand of double value
            public static long ReuturnSignificantMantissa(double value)
            {
                return BitConverter.DoubleToInt64Bits(value)
                            & signficand_mask;
            }

            // the method will return the signicand
            // for a floating-point number
            public static double ReturnSignficantForFloatingPoint(double value)
            {
                if (Double.IsNaN(value)) return value;

                if (Double.IsInfinity(value)) return value;

                // computing the exponent using the deviation
                int exponentValue = ComputeDeviationExponent(value);
                long significand = ReuturnSignificantMantissa(value);

                // number 0 and denormalization
                // values has to be treated separetely
                if (exponentValue == 0)
                {
                    // if the significand is equal
                    // with we will return 0
                    if (significand == 0)
                        return 0.0;

                    // otherwise we will shit the significand to the left
                    // until significand will be 53 bits long
                    while (significand < signficand_mask)
                        significand <<= 1;

                        // truncate the leading bit
                        significand &= signficand_mask;
                }
                return BitConverter.Int64BitsToDouble
                    ((deviation << 52) + significand);
            }

            // The function will return a non-deviation
            // exponent for a floating-point value.
            // The non-deviation is computed through
            // substracting the deviation from deviated exponent.
            public static int NonDeviationExponent(double value)
            {
                return (int)((BitConverter.DoubleToInt64Bits(value)
                    & significand_exponent_mask) >> 52) - deviation;
            }

            // The function will return the
            // deviation exponnent for a
            // floating-point value.
            // The returned value is obtained
            // and computed directly from
            // and within binary representation of "value"
            public static int ComputeDeviationExponent(double value)
            {
                return (int)((BitConverter.DoubleToInt64Bits(value)
                    & significand_exponent_mask) >> 52);
            }

            // The function returns the bit sign
            // of a value. The bit sign is obtained
            // directly from the binary representation
            // of the value
            public static int SignBit(double value)
            {
                return ((BitConverter.DoubleToInt64Bits(value)
                    & mask_sign_value) != 0) ? 1 : 0;
            }
        #endregion

        #region Below contains the implementation of the IEEE-754

            // The class represents the implementation
            // of IEEE-754 floating-point
            // References:
            // https://www.geeksforgeeks.org/ieee-standard-754-floating-point-numbers/
            public static IEEEStandardization Class
                (double value)
            {
                long bits_value_representation =
                    BitConverter.DoubleToInt64Bits(value);

                bool positive_value = (bits_value_representation >= 0);

                bits_value_representation =
                    bits_value_representation & clear_mask_sign;

                // case when we have a overflow
                // for Not-A-Number
                if (bits_value_representation
                    >= 0x7ff0000000000000)
                {
                    // this is case of infinity
                    if ((bits_value_representation
                        & signficand_mask) == 0)
                    {
                        if (positive_value)
                            return IEEEStandardization.
                                Value_Positive_Infinity;
                        else
                            return IEEEStandardization.
                                Value_Negative_Infinity;
                    }
                    else

                    {
                        if ((bits_value_representation
                            & signficand_mask)
                            < 0x8000000000000)
                            return IEEEStandardization.
                                Quiet_Not_a_Number;
                        else
                            return IEEEStandardization.
                                Signaling_Not_a_Number;
                    }
                }
                // this is happening when we have
                // 0 or a denormalization value
                else if (bits_value_representation
                    < 0x0010000000000000)
                {
                    if (bits_value_representation == 0)
                    {
                        if (positive_value)
                            return IEEEStandardization.
                                Value_Positive_Zero;
                        else
                            return IEEEStandardization.
                                Value_Negative_Zero;
                    }
                    else
                    {
                        if (positive_value)
                            return IEEEStandardization.
                                Denormalization_Positive_Denormalized;
                        else
                            return IEEEStandardization.
                                Denormalization_Negative_Denormalized;
                    }
                }
                else
                {
                    if (positive_value)
                        return IEEEStandardization.
                            Normalization_Positive_Normalized;
                    else
                        return IEEEStandardization.
                            Normalization_Negative_Normalized;
                }
            }

            // The function copy the
            // sign of the number.
            // theSizeOfTheValue parameter
            //        the number for
            //        which we copy the sign
            // theValueOfTheSign parameter
            //        the value of the number
            //        for which we do the copy
            public static double CopyProcedureForSign
                    (double theSizeOfTheValue,
                     double theValueOfTheSign)
            {
                // we do a bit manipulation
                // do the copying process for
                //* the first bit for theSizeOfTheValue
                // and theValueOfTheSign
                return BitConverter.Int64BitsToDouble(
                    (BitConverter.DoubleToInt64Bits
                        (theSizeOfTheValue) &
                            clear_mask_sign)
                    | (BitConverter.DoubleToInt64Bits
                        (theValueOfTheSign) &
                            mask_sign_value));
            }

            // a boolean function to
            // check if the value is
            // finite or not
            public bool CheckIfIsFinite(double value)
            {
            // Verify the part represented by the exponent.
            // if all the bits are 1, then we
            // are dealing with a infinity (not-a-number).
                long bits = BitConverter.
                    DoubleToInt64Bits(value);
                return ((bits & significand_exponent_mask)
                    == significand_exponent_mask);
            }

            // The function will return the
            // non-biased exponent for a value.
            public static double ComputingLogB(double value)
            {
                // Let's deal with the
                // important situations.
                if (double.IsNaN(value))
                    return value;
                if (double.IsInfinity(value))
                    return double.PositiveInfinity;
                if (value == 0)
                    return double.NegativeInfinity;

                int exponentDeviationValue =
                    ComputeDeviationExponent(value);

                // if we dealing with a denormalization value
                // we need to take the right action
                if (exponentDeviationValue == 0)
                {
                    exponentDeviationValue = -1074;

                    // compute the signficand with no sign
                    long bits = BitConverter.
                        DoubleToInt64Bits(value) & clear_mask_sign;

                    // we move on if we finish dealing with situations
                    // when bits = 0
                    do
                    {
                        bits >>= 1;
                        exponentDeviationValue++;
                    }
                    while (bits > 0);
                    return exponentDeviationValue;
                }

                // exponentDeviationValue was significand,
                // proceed with subtraction the deviation
                // to obtain and compute the non-deviation exponent
                return exponentDeviationValue - deviation;
            }

            // Compute the floating-point
            // number for the next number.
            // 'from' parameter
            //        - represent the starting point
            // 'to' parameter
            //        - represent a value that shows
            //          the direction in which we will
            //          move in order to identity
            //          the next value
            public static double
                ComputerNextValue(double from, double to)
            {
                // If 'to' is equal with from
                // there is no direction to move in,
                // so we will compute and get 'from' value
                if (from == to)
                    return from;

                // if not-a-number occur will
                // be returned by themselves
                if (double.IsNaN(from))
                    return from;
                if (double.IsNaN(to))
                    return to;

                // an infinity will be an infinity all time
                if (double.IsInfinity(from))
                    return from;

                // deal with 0 situation
                if (from == 0)
                    return (to > 0) ?
                        minimum_double : -minimum_double;

                // For the rest of the
                // situation we are dealing.
                // With incrementation or
                // decrementation the bits value.
                // Values for transitions to infinity,
                // denormalized values, and to zero are
                // managed in this way.
                long bits_value = BitConverter.DoubleToInt64Bits(from);

                // A xor here avoids nesting conditionals. We have to increment if
                // fromValue lies between 0 and toValue.

                // XOR operation will help us to
                // not taken into consideration
                // conditionals.
                if ((from > 0) ^ (from > to))
                    bits_value++;
                else
                    bits_value--;
                return BitConverter.
                    Int64BitsToDouble(bits_value);
            }

            // the function compute and return
            // a value that is powered with 2
            public static double Scalb(double number,
                                       int exponent)
            {
                // Treat special cases first.
                if (number == 0 ||
                            double.IsInfinity(number) ||
                            double.IsNaN(number))
                    return number;

                if (exponent == 0)
                    return number;

                int computedExponentValue = ComputeDeviationExponent(number);
                long significand = ReuturnSignificantMantissa(number);
                long getting_sign = ((number > 0) ? 0 : mask_sign_value);

                // check if 'number' is denormalized
                if (computedExponentValue == 0)
                {
                    if (exponent < 0)
                    {
                        // an exponent that is negative
                        // we will shift the significand
                        // -exponent bits to the right
                        significand >>= -exponent;
                        return BitConverter.
                            Int64BitsToDouble(getting_sign | significand);
                    }
                    else

                    {
                        // a number that is positive is
                        // necessary to be shifted on left
                        // and this will be done until a
                        // normalized number is obtained
                        while (significand <= signficand_mask
                            && exponent > 0)
                        {
                            significand <<= 1;
                            exponent--;
                        }

                        if (significand > signficand_mask)
                            exponent++;

                        // test if we have a overflow
                        if (exponent > 2 * deviation)
                            return (number > 0) ?
                                double.PositiveInfinity
                                : double.NegativeInfinity;

                        // the number represents the
                        // significand exponent for the result
                        return BitConverter.Int64BitsToDouble(getting_sign
                            | ((long)exponent << 52) |
                                (significand & signficand_mask));
                    }
                }

                // Once we are reaching here,
                // we are aware that 'exoponent'
                // is normalized.
                // Proceeding with scaling. 'exponent'
                // will be the significand exponent for the result
                computedExponentValue =
                    computedExponentValue + exponent;

                // verify if we have 0 or denormalization
                if (computedExponentValue < 0)
                {
                    significand = ((1L << 52) +
                        significand) >> (1 -
                            computedExponentValue);

                    return BitConverter.
                        Int64BitsToDouble(getting_sign | significand);
                }

                // Veirfy if we have an overflow
                if (computedExponentValue >
                    2 * deviation)
                    return (number > 0) ?
                        double.PositiveInfinity :
                        double.NegativeInfinity;

                // If we're here, the result is normalized.
                long bits = getting_sign |
                    ((long)computedExponentValue << 52) | significand;

                return BitConverter.Int64BitsToDouble(bits);
            }

            // the function computes a value
            // wich will point out if the two
            // values are unordered
            public static bool Unordered(double value1, double value2)
            {
                return double.IsNaN(value1) || double.IsNaN(value2);
            }
        #endregion

        #region Methods for conversion bit with single-precision
            public static unsafe int ConversionSingleToInt32Bits(float val)
            {
                return *((int*)&val);
            }

            public static unsafe float ConversionInt32BitsToSingle(int val)
            {
                return *((float*)&val);
            }
        #endregion
    }
}

Listing 4-4Floating Point Implementation

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace FloatingPointArithmetic
{
    public enum IEEEStandardization
    {
        // the value is a signaling NaN - not a number
        Signaling_Not_a_Number,

        // the value is represented by a quiet
        // NaN - not a number and non-signaling
        Quiet_Not_a_Number,

        // the value represents a positive infinity
        Value_Positive_Infinity,

        // the value represents a negative infinity
        Value_Negative_Infinity,

        // The value represents a normal and positive number
        Normalization_Positive_Normalized,

        // The value represents a normal and negative number
        Normalization_Negative_Normalized,

        // A denormalized positive number
        Denormalization_Positive_Denormalized,

        // The value is a denormalized negative number
        Denormalization_Negative_Denormalized,

        // The value represents a positive zero
        Value_Positive_Zero,

        // the value represents a negative zero
        Value_Negative_Zero
    }
}

Listing 4-3IEEE Standardization Implementation

结论

在这一章中,我们讨论了浮点数的一般表示,以及如何在复杂的密码系统中实现它们。我们分析了最重要的术语和基本概念,专业人员在计划建立一个开发复杂密码系统的环境时应该了解这些概念。

我们还证明了浮点运算在复杂密码系统中的重要性,如同态加密、基于混沌的密码、基于格的密码或带错误的环学习。

文献学

  1. H.来自同态加密的快速私有集合交集。2017 年 ACM SIGSAC 计算机与通信安全会议 CCS '17 论文集,2017。

  2. 长度 Ducas 和 D. Micciancio,“FHEW:在不到一秒的时间内引导同态加密”,载于密码学进展-Eurocrypt 2015,第 617-640 页,施普林格,柏林,德国,2015 年。

  3. 南 Halevi 和 V. Shoup,“HElib 中的算法”,载于Crypto14,第 8616 卷,施普林格,海德堡,德国,2014 年。

  4. J.坎波斯、p .夏尔马、e .詹图宁、d .巴格利和 l .福马加利,“保护高级维护开发所需数据的网络安全框架的挑战”,载于*《CIRP 进程报*,第 47 卷,第 227 页,2016 年。

  5. c .燃烧物品和 j .Ziegler,“Fast Recursive Division”,inresearchreport max-Planck 计算机科学研究所 report MPI-I-98-1-022,max-Planck-Instituto für informatique,sahabrüber,Germany,1998 年。

  6. 名词(noun 的缩写)Dowlin,R. Gilad-Bachrach,K. Laine,K. Lauter,M. Naehrig 和 J. Wernsing,“使用同态加密进行生物信息学的手册”,载于 IEEE 会议录*,第 105 卷,第 3 期,2017 年。*

  7. J.H. Cheon、A. Kim、M. Kim 和 Y. Song,“近似数算术的同态加密”,载于《密码学与信息安全的理论和应用国际会议(ASIA-CRYPT’17)会议录(??),第 409-437 页,中国香港,2017 年 12 月。

  8. 浮点支持。网上有: https://docs.microsoft.com/en-us/cpp/c-runtime-library/floating-point-support?view=vs-2019

五、C# 8.0 的新特性

本章将为密码学和密码分析领域的专业人士讲述 C# 8.0 最重要的特性。有关哪个版本的 C# 用于不同版本的 .NET 框架和 .NET Core,我们推荐 [3 ]的资源。

C# 8.0 对 C# 语言进行了许多改进和增强,其中一些可以成功地用于提高加密和密码分析算法以及安全方案的实现过程的性能。上支持 C# 8.0。网芯 3。x 和。网络标准 2.1。关于 C# 语言版本控制的更多细节可以在这里找到 [1 。这些增强功能包括

  • 只读成员

  • 默认接口方法

  • 模式匹配的改进:开关表达式、属性模式、元组模式、位置模式

  • 使用声明

  • 静态局部函数

  • 一次性参考支柱

  • 可为空的引用类型

  • 异步流

  • 异步一次性

  • 指数和范围

  • 零合并赋值

  • 非托管构造类型

  • 嵌套表达式中的 Stackalloc

  • 插值逐字字符串的增强

如前所述,本章将描述有助于专业人员提高加密解决方案质量和性能的特性。要探索环境中 C# 8.0 提供的特性的更多细节,建议使用dotnet try工具。要深入探索这些功能,可以成功使用以下解决方案和步骤:

以下部分将涵盖显著提高加密应用的质量和性能的增强功能。

只读成员

新的 readonly 修饰符可以应用于结构的成员。当我们不希望成员的状态被修改时,使用 readonly。我们将通过对成员应用 readonly 而不是 struct 声明来展示更细粒度的表示。

让我们考虑清单 5-1 中的例子,其中我们实现了一个处理 RSA 密码系统的结构。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Listing_5_1___ReadOnlyMembers
{
    class Program
    {
        public int cryptoKey1;

        //** initializing and dealing with
        public readonly int cryptoKey2 = 25;
        public readonly int cryptoKey3;

        public Program()
        {
            // Initialize a readonly instance field
            cryptoKey3 = 24;
        }

        public Program(int value1, int value2, int value3)
        {
            cryptoKey1 = value1;
            cryptoKey2 = value2;
            cryptoKey3 = value3;
        }

        public static void Main()

        {
            Program cryptoProgram1 = new Program(13, 27, 39);
            Console.WriteLine($"Crypto Program 1: crypto_key 1={cryptoProgram1.cryptoKey1}, crypto_key 2={cryptoProgram1.cryptoKey2}, crypto_key 3={cryptoProgram1.cryptoKey3}");

            Program cryptoProgram2 = new Program();
            cryptoProgram2.cryptoKey1 = 55;
            Console.WriteLine($"Crypto Program 2: crypto_key 1={cryptoProgram2.cryptoKey1}, crypto_key 2={cryptoProgram2.cryptoKey2}, crypto_key 3={cryptoProgram2.cryptoKey3}");

            Console.ReadKey();
        }
    }
}

Listing 5-1Applying Readonly for a Cryptographic Purpose

与大多数结构一样,ToString()方法不会更新或修改状态。我们可以通过将readonly放在override关键字的前面来指定发生这种情况(见图 5-1 )。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-1

使用 readonly 关键字的输出示例

模式匹配

在加密模式匹配中,技术可以用在不同的地方,例如解析密码要求、字符串和加密密钥预期。

从 C# 8.0 开始,可以在代码的不同位置使用和实现更多的模式表达式。C# 8.0 的另一个重要增强是递归模式,一个可以在另一个模式表达式结果的输出上使用的模式表达式。让我们考虑清单 5-2 中的例子,我们使用一个enum结构来列出加密算法。

public enum CryptoType
{
    RSA,
    AES,
    TripleDES,
}

Listing 5-2Using an enum struct

如果正在开发的应用包含CryptographicAlgorithm类型的定义,则它是由加密组件(例如加密、解密、计算私钥、计算公钥等)构建的。),所以我们可以使用清单 5-3 中的例子,用一条switch指令将一个CryptographicAlgorithm值转换成CryptoType值。

public static CryptographicAlgorithm
      GetCryptoAlgorithm(CryptographicAlgorithm crypto)
{
   return crypto.cryptosystemType switch
   {
      CryptoType.RSA => new RSA(),
      CryptoType.AES => new AES(),
      CryptoType.TripleDES => new TripleDES(),
      _ => throw new ArgumentException(message: "There is no
                 such cryptographic algorithm ",
                 paramName: nameof(crypto.cryptosystemType))
   };
}

Listing 5-3Using a switch Expression

清单 5-4 给出了一个完整的例子。该列表的结果如图 5-2 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-2

清单 5-4 中代码的结果

using System;

namespace PatternsMatching
{
    class Program
    {
        static void Main(string[] args)
        {
            CryptographicAlgorithm cryptoAlg =
                      new CryptographicAlgorithm();
            Console.WriteLine("Pick a cryptosystem [1=RSA,
                                 2=AES, 3=TripleDES]");

            string type = Console.ReadLine();
            CryptoType ct = type switch
            {
                "1" => CryptoType.RSA,
                "2" => CryptoType.AES,
                "3" => CryptoType.TripleDES,
                _ => throw new ArgumentException(message:
                      "There is no such option ",
                      paramName: nameof(type))
            };

            try
            {
                cryptoAlg.cryptosystemType = ct;
                GetCryptoAlgorithm(cryptoAlg);

                Console.ReadKey();
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public static CryptographicAlgorithm
              GetCryptoAlgorithm(
                      CryptographicAlgorithm crypto)
        {
            return crypto.cryptosystemType switch
            {
                CryptoType.RSA => new RSA(),
                CryptoType.AES => new AES(),
                CryptoType.TripleDES => new TripleDES(),
                _ => throw new ArgumentException(message:
                      "There is no such cryptographic algorithm ",
                       paramName: nameof(crypto.cryptosystemType))
            };
        }
    }
    public enum CryptoType
    {
        RSA,
        AES,
        TripleDES,
    }

    public class CryptographicAlgorithm
    {
        internal CryptoType cryptosystemType;
        public CryptographicAlgorithm()
        {

        }
    }

    class RSA : CryptographicAlgorithm
    {
        public RSA()
        {
            Console.WriteLine("RSA chosen!");
        }
    }

    class AES : CryptographicAlgorithm
    {
        public AES()
        {
            Console.WriteLine("AES chosen!");
        }
    }

    class TripleDES : CryptographicAlgorithm
    {
        public TripleDES()
        {
            Console.WriteLine("TripleDES chosen!");
        }
    }
}

Listing 5-4Chosing an Encryption System Based on switch Expressions

模式

属性模式

使用属性模式的新特性让专业人员能够匹配属于对象的属性。让我们考虑一个电子学习平台作为例子(见清单 5-5 )。我们需要基于CryptographicAlgorithm对象的cryptosystemType属性,使用特定的加密算法对消息进行加密。请注意,这些部分中的示例仅用于演示。

public static int Encrypt(CryptographicAlgorithm crypto, Parameters parameters, int message)
{
    return crypto switch
    {
      { cryptosystemType: CryptoType.RSA } => (new RSA()).
Encrypt(parameters.n, parameters.e, message),
      { cryptosystemType: CryptoType.AES } => (new AES()).
                Encrypt(parameters.key, message),
      { cryptosystemType: CryptoType.TripleDES } => (new
             TripleDES().Encrypt(parameters.k1, parameters.k2,
                            parameters.k3, message)),
     _ => throw new ArgumentException(message: "There is no
                           such cryptographic algorithm ",
                           paramName:
                             nameof(crypto.cryptosystemType))
     };
  }

Listing 5-5Using Property Patterns

清单 5-6 中给出了完整的代码,输出如图 5-3 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-3

清单 5-6 中代码的结果

using System;

namespace PropertyPatterns
{
    class Program
    {
        static void Main(string[] args)
        {
            CryptographicAlgorithm cryptoAlg = new
                          CryptographicAlgorithm();
            Console.WriteLine("Pick a cryptosystem [1=RSA,
                              2=AES, 3=TripleDES]");

            string type = Console.ReadLine();
            CryptoType ct = type switch
            {
                "1" => CryptoType.RSA,
                "2" => CryptoType.AES,
                "3" => CryptoType.TripleDES,
                _ => throw new ArgumentException(message:
                     "There is no such option ",
                      paramName: nameof(type))
            };

            //** the parameters should be initialized
            Parameters parameters = new Parameters();
            //** the message that needs to be encrypted
            int message = 0;
            try
            {
                cryptoAlg.cryptosystemType = ct;
                Encrypt(cryptoAlg, parameters, message);
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public static int Encrypt(
                     CryptographicAlgorithm  crypto,
                     Parameters parameters,
                     int message)
        {
            return crypto switch
            {
                { cryptosystemType: CryptoType.RSA } => (new
                        RSA()).Encrypt(parameters.n,
                                       parameters.e,
                                       message),
                { cryptosystemType: CryptoType.AES } => (new
                        AES()).Encrypt(parameters.key,
                                       message),
                { cryptosystemType: CryptoType.TripleDES } =>
                       (new TripleDES().Encrypt(parameters.k1,
                                            parameters.k2,
                                            parameters.k3,
                                            message)),
                _ => throw new ArgumentException(message:
                          "There is no such cryptographic
                           algorithm ",
                           paramName:
                             nameof(crypto.cryptosystemType))
            };
        }
    }
    public enum CryptoType
    { RSA, AES, TripleDES, }

    public class Parameters
    {
        public Parameters() { }
        internal int n, e, k1, k2, k3;
        internal int[,] key;
    }

    public class CryptographicAlgorithm
    {
        internal CryptoType cryptosystemType;
        public CryptographicAlgorithm() { }
        public int Encrypt()
        {
            return 0;
        }
    }

    class RSA : CryptographicAlgorithm
    {
        public RSA()
        {
            Console.WriteLine("RSA chosen!");
        }

        public int Encrypt(int n, int e, int message)
        {
            Console.WriteLine("Here goes the implementation of
                           the RSA encryption algorithm.");
            return 0;
        }

    }

    class AES : CryptographicAlgorithm
    {
        public AES()
        {
            Console.WriteLine("AES chosen!");
        }
        public int Encrypt(int[,] key, int message)
        {
            Console.WriteLine("Here goes the implementation of
                              the AES encryption algorithm.");
            return 0;
        }
    }

    class TripleDES : CryptographicAlgorithm
    {
        public TripleDES()
        {
            Console.WriteLine("TripleDES chosen!");
        }
        public int Encrypt(int k1, int k2, int k3,
                           int message)
        {
            Console.WriteLine("Here goes the implementation of
                       the TripleDES encryption algorithm.");
            return 0;
        }
    }
}

Listing 5-6Demonstration of Using Property Patterns

多重模式

一些加密算法(例如 RSA 或可搜索的加密方案)依赖于各种输入。使用元组模式给了我们在用元组表示的多个值之间切换的可能性。清单 5-7 中的代码说明了如何使用开关表达式在不同的加密算法之间进行切换。

在本例中,您可以根据密钥的数量选择加密系统:一个密钥用于加密和解密,或者一对密钥(用于加密的公钥和用于解密的密钥)。列表 5-7 的结果如图 5-4 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-4

列表结果 5-7

using System;

namespace TuplePatterns
{
    class Program
    {
        static void Main(string[] args)
        {
            CryptographicAlgorithm cryptoAlg =
                           new CryptographicAlgorithm();
            Console.WriteLine("Enter the number of keys:
                         1=(secret key);
                         2=(public key, secret key); ");

            string noOfKeys = Console.ReadLine();

            try
            {
                Console.WriteLine(noOfKeys switch
                {
                    "1" => InitializingAlgKeys(cryptoAlg,
                                                 false, true),
                    "2" => InitializingAlgKeys(cryptoAlg,
                                                  true, true),
                    _ => throw new ArgumentException(message:
                                  "There is no such option ")
                });

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        public static string InitializingAlgKeys
                     (CryptographicAlgorithm crypto,
                         bool publicKey,
                         bool secretKey)
        {
            return (publicKey, secretKey) switch
            {
                (true, true) => (new RSA()).InitializeKeys(),
                (false, true) => (new AES()).InitializeKeys(),
                _ => throw new ArgumentException(message:
                                 "There is no such option. ")
            };
        }
    }

    public class CryptographicAlgorithm
    {
        public CryptographicAlgorithm() { }
        public string InitializeKeys()
        {
            return "";
        }
    }

    class RSA : CryptographicAlgorithm
    {
        public string InitializeKeys(int publicKey = -1,
                                     int secretKey = -1)
        {
            return "RSA uses a public key and a secret key.
                    Initializing the keys for RSA...";
        }
    }

    class AES : CryptographicAlgorithm
    {
        public string InitializeKeys(int secretKey = -1)
        {
            return "AES uses a secret key.
                   Initializing the  key for AES...";
        }
    }
}

Listing 5-7Using Tupple Patterns

位置模式

一些应用和实现使用了Deconstruct方法。此方法的目的是将属性解构为离散变量。要使用位置模式,Deconstruct方法应该是可访问的,这样我们将能够查看特征对象的属性,并使用这些属性来生成模式。清单 5-8 显示了CryptoAlgorithms类,它包括一个Deconstruct方法,以便为prvKey(私钥)和pubKey(公钥)创建一个离散变量。清单 5-8 中的代码展示了位置模式在密码学领域的应用。结果如图 5-5 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-5

列表结果 5-8

using System;

namespace PositionalPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            KeysAdministration k1 = new
               KeysAdministration("This is the private key",
                                 "This is the public key");
            KeysAdministration k2 = new
                 KeysAdministration("This is the private key", null);
            KeysAdministration k3 = new
               KeysAdministration(null, "This is the public key");

            CryptographicAlgorithm cryptoAlg;

            cryptoAlg = GetAlgorithmType(k1);
            Console.WriteLine("public and private keys: " +
                              cryptoAlg.ToString());
            cryptoAlg = GetAlgorithmType(k2);
            Console.WriteLine("just the private key: " +
                              cryptoAlg.ToString());
            cryptoAlg = GetAlgorithmType(k3);
            Console.WriteLine("no matching keys: " +
                              cryptoAlg.ToString());

            Console.ReadKey();

        }
        static CryptographicAlgorithm
               GetAlgorithmType(KeysAdministration keys)
               => keys switch
        {
            var (privKey, pubKey) when
                   !string.IsNullOrEmpty(privKey) &&
                   !string.IsNullOrEmpty(pubKey)
                       => CryptographicAlgorithm.RSA,
            var (privKey, pubKey) when
                   !string.IsNullOrEmpty(privKey) &&
                   string.IsNullOrEmpty(pubKey)
                     => CryptographicAlgorithm.AES,
            _ => CryptographicAlgorithm.Unknown
        };
    }

    public enum CryptographicAlgorithm
    {
        Unknown,
        RSA,
        AES,
    }

    public class KeysAdministration
    {
        public string prvKey { get; }
        public string pubKey { get; }

        public KeysAdministration(string PrivateKey,
                                  string PublicKey)
                => (prvKey, pubKey) = (PrivateKey, PublicKey);
        public void Deconstruct(out string PrivateKey,
                                out string PublicKey)
                => (PrivateKey, PublicKey) = (prvKey, pubKey);
    }
}

Listing 5-8Positional Patterns

使用声明

使用声明表示一种在变量(或其类型)前面有using关键字的变量声明。例如,让我们考虑清单 5-9 中的例子,它将消息的加密写入文件。输出如图 5-6 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-6

列表结果 5-9

using System;
using System.Collections.Generic;
using System.Linq;

namespace Declarations
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> encryptedMessageLines = new
                                     List<string>();

            encryptedMessageLines.Add("Option 1 key:
                                  sdkjegiorjgvldmgkA64");
            encryptedMessageLines.Add("This is the message to
                    be encrypted: This is an example of using
                    declarations in C# 8.0.");
            encryptedMessageLines.Add("Option 2 key:
                                  l$klj4grg565j");

            Console.Write("The number of lines skipped: ");
            Console.WriteLine(WriteEncryptedMessages(
               encryptedMessageLines.AsEnumerable<string>())
                                    .ToString());

            Console.ReadKey();
        }

        static int WriteEncryptedMessages(IEnumerable<string>
                                        encryptedMessageLines)
        {
            using var fileWithEncryption = new
             System.IO.StreamWriter("Message.txt");

            //** A note to be done on how we will declare
            //** lines_to_be_skipped after the using
            //** statement.

            int lines_to_be_skipped = 0;

            foreach (string lineMessage in
                     encryptedMessageLines)
            {
                if (!lineMessage.Contains("key"))
                {
                    fileWithEncryption.WriteLine(lineMessage);
                }
                else
                {
                    lines_to_be_skipped++;
                }
            }
            //** Notice how the skipped lines
            //** are the main subject here

            return lines_to_be_skipped;

            //** the file will be disposed once
            //** the compiler reached here
        }
    }
}

Listing 5-9Using Declarations

在图 5-6 中,我们获得了两行,因为列表encryptedMessageLines有两行包含这行代码中提到的字符串key:

if (!lineMessage.Contains("key")) from the WriteEncryptedMessages method

为了检查从encryptedMessageLines开始的两行是否确实被跳过,看一下图 5-7 ,它显示了文本被写入的Message.txt文件的内容。如果没有指定完整路径,那么这个文件可以在项目的bin > Debug > netcoreapp3.1文件夹中找到(如果项目使用的是。网芯 3.1;否则路径是相似的)。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-7

清单 5-9 中使用的文件内容

指数和范围

索引范围为访问序列中的单个元素或范围提供了简短而精确的语法。

  • C# 8.0 提供了对两种新类型和操作符的支持,比如System.Index被定义为序列中的索引。

  • 操作符^末尾的索引指定一个索引在序列的末尾是相对的。

  • System.Range定义一个已声明序列的子范围。

  • 用于范围的运算符,指定操作数范围内的开始和结束。

在清单 5-10 中,我们考虑一个从开始到结束都有索引的数组。

var cryptograms = new string[]
{
                       // beginning index     ending index
    "ghdghdg",         // 0                   ⁹
    "gfhdgfhdgfh",     // 1                   ⁸
    "hsfgd",           // 2                   ⁷
    "dg545ghfd44",     // 3                   ⁶
    "fg435ffdgsdfg",   // 4                   ⁵
    "gdsfg4refgs",     // 5                   ⁴
    "54tgt4gv",        // 6                   ³
    "ge43fsda",        // 7                   ²
    "fdgsdef"          // 8                   ¹
};

Listing 5-10Working with Indexes

如您所见,您可以返回¹索引,如下例所示,列出了 5-11 。

//** this will return the cryptogram value "fdgsdef"
Console.WriteLine($"The last cryptogram (encrypted message) has
                        the following value {cryptograms[¹]}");

Listing 5-11Returning ¹ Index

在清单 5-12 中,我们用密码"gfhdgfhdgfh," "hsfgd,""dg545ghfd44."创建了一个子范围,这包括cryptograms[1]cryptograms[3]。注意,element cryptograms[4]不在这个范围内。

var encryptedTexts = cryptograms[1..4];

Listing 5-12Creating Subranges

在清单 5-13 中,我们使用密码"ge43fsda""fdgsdef."创建了一个子范围,这将包括cryptograms[²]cryptograms[¹]。注意,这个指数是cryptograms[⁰]

var encryptedTexts = cryptograms[²..];

Listing 5-13Another Subrange

在清单 5-14 中,我们为开始、结束或者在某些情况下为两者创建了一个在结束时开放的范围。

//** contains "ghdghdg" through "fdgsdef".
var encryptedTexts = cryptograms[..];

//** contains "ghdghdg" through "dg545ghfd44"
var firstEncryptedText = cryptograms[..4];

//** contains "ghdghdg", "ge43fsda" and "fdgsdef"
var lastEncryptedText = cryptograms[6..];

Listing 5-14Open Range

将所有这些放在一起,我们得到了清单 5-15 中的代码,结果如图 5-8 所示。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-8

指数和范围输出

using System;

namespace IndicesRanges
{
    class Program
    {
        static void Main(string[] args)
        {
            var cryptograms = new string[]
            {
                                    // beginning index     ending index
                "ghdghdg",          // 0                   ⁹
                "gfhdgfhdgfh",      // 1                   ⁸
                "hsfgd",            // 2                   ⁷
                "dg545ghfd44",      // 3                   ⁶
                "fg435ffdgsdfg",    // 4                   ⁵
                "gdsfg4refgs",      // 5                   ⁴
                "54tgt4gv",         // 6                   ³
                "ge43fsda",         // 7                   ²
                "fdgsdef"           // 8                   ¹
            };

            //** this will return the cryptogram value "fdgsdef"
            Console.WriteLine($"The last cryptogram (encrypted message) has the following value { cryptograms[¹]}");

            Console.Write("\n\n" + "Example 1 ~encryptedTexts~: ");
            var encryptedTexts = cryptograms[1..4];
            for (int i=0;i<encryptedTexts.Length;i++)
            {
                Console.Write(encryptedTexts[i] + " ");
            }

            Console.Write("\n\n" + "Example 2 ~encryptedTexts~: ");
            encryptedTexts = cryptograms[²..];
            for (int i = 0; i < encryptedTexts.Length; i++)
            {
                Console.Write(encryptedTexts[i] + " ");
            }

            //** contains "ghdghdg" through "fdgsdef".
            Console.Write("\n\n" + "Example 3 ~encryptedTexts~: ");
            encryptedTexts = cryptograms[..];
            for (int i = 0; i < encryptedTexts.Length; i++)
            {
                Console.Write(encryptedTexts[i] + " ");

            }

            //** contains "ghdghdg" through "dg545ghfd44"
            Console.Write("\n\n" + "Example 4 ~firstEncryptedText~: ");
            var firstEncryptedText = cryptograms[..4];
            for (int i = 0; i < firstEncryptedText.Length; i++)
            {
                Console.Write(firstEncryptedText[i] + " ");
            }

            //** contains "ghdghdg", "ge43fsda" and "fdgsdef"
            Console.Write("\n\n" + "Example 5 ~lastEncryptedText~: ");
            var lastEncryptedText = cryptograms[6..];
            for (int i = 0; i < lastEncryptedText.Length; i++)
            {
                Console.Write(lastEncryptedText[i] + " ");
            }

            Console.ReadKey();
        }
    }
}

Listing 5-15Example of Functional Indices and Ranges

零合并赋值

C# 8.0 提供了一个新特性,可以显著提高表示加密算法的代码的质量和性能。运算符??=(参见清单 5-16 )可用于将右操作数的值赋给左操作数,前提是左操作数的返回输出被评估为null

下面,我们将把所有的东西放在一起,并展示如何将零合并赋值用于加密应用。见清单 5-16 和图 5-9 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-9

列表结果 5-16

using System;
using System.Collections.Generic;

namespace NullCoalescingAssignment
{
    class Program
    {
        static void Main(string[] args)
        {
            List<string> cryptograms = null;
            string val = null;

            cryptograms ??= new List<string>();
            cryptograms.Add(val ??= "fdsfasdf");
            cryptograms.Add(val ??= "dsfasdfads4234");

            //** output: "fdsfasdf" and "fdsfasdf"
            Console.WriteLine(string.Join(" ", cryptograms));

            //** output: "fdsfasdf"
            Console.WriteLine(val);

            Console.ReadKey();
        }
    }
}

Listing 5-16Operator ??=

非托管构造类型

就加密算法和安全解决方案的实现而言,非托管构造类型可能是一个非常有趣的话题。在 C# 7.3 中,构造类型不能是非托管类型(参见清单 5-17 )。当我们使用变量和不同类型来实现加密算法时,这非常有用,特别是当大小在它们的表示中起主要作用时。见清单 5-17 和图 5-10 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-10

列表结果 5-17

using System;

namespace TheUnmanagedTypes
{
    class Program
  {
        static void Main(string[] args)
     {
      ShowTypeVariableSize<CryptographicAlgorithms<int>>();
      ShowTypeVariableSize<CryptographicAlgorithms<double>>();
      Console.ReadKey();
     }

        public struct CryptographicAlgorithms<T>
        {
            public T prvEncKey;
            public T pubEncKey;
        }

private unsafe static void ShowTypeVariableSize<T>()
where T : unmanaged
        {
            Console.WriteLine($"{typeof(T)} represents an
                           unmanaged type and the size is
                           { sizeof(T) } bytes");
        }
    }
    //** The resulted outputed is:
    //** CryptographicAlgorithms`1[System.Int32] is unmanaged.
    //** The size is 8 bytes
    //** CryptographicAlgorithms`1[System.Double] is
    //** unmanaged.
    //** The size is 16 bytes
}

Listing 5-17Unmanaged Type Example (According to C# 7.3)

如果我们处理泛型结构,我们可以处理非托管和非托管构造类型。清单 5-17 中的例子定义了一个通用结构CryptographicAlgorithms<T>并展示了一个非托管构造类型的例子。如果我们想要一个非托管类型的例子,那就是CryptographicAlgorithms<object>.这不是非托管的,因为它有以对象类型为特征的字段,这是非托管的完美例子。如果我们希望所有构造的类型都是非托管类型,那么我们需要使用非托管约束(参见清单 5-18 )。

public struct CryptographicAlgorithms<T> where T : unmanaged
{
    public T prvEncKey;
    public T pubEncKey;
}

Listing 5-18Using an Unmanaged Constraint (According to C# 7.3)

基于清单 5-18 中的例子,CryptographicAlgorithms<T>类型是从 C# 8.0 和更高版本开始的非托管类型。正如你所看到的,对于一些非托管类型,我们可以声明一个指针指向一个声明为这种类型的变量,或者在堆栈上适当分配一个内存块(参见清单 5-19 )。为此,我们需要关注System.Span [2 。输出见图 5-11 。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

图 5-11

清单 5-19 的结果

using System;

namespace MemoryAllocation
{
    class Program
    {
        static void Main(string[] args)
        {
            Random r = new Random();
            int k1 = r.Next(0, 255), k2 = r.Next(0, 255),
                k3 = r.Next(0, 255), k4 = r.Next(0, 255),
                k5 = r.Next(0, 255);

            Span<int> keys = stackalloc[] { k1, k2, k3, k4, k5 };
            Console.Write("The keys are: ");
            for (int i = 0; i < keys.Length; i++)
                Console.Write(keys[i] + " ");
            var ind = keys.IndexOfAny(stackalloc[] { k3, k5});
            Console.WriteLine("\n \n" + ind);  // output: 1

            Console.ReadKey();
        }
    }
}

Listing 5-19Allocation of a Memory Block on the Stack

结论

在本章中,我们介绍了 C# 8.0 最重要的新特性,这些特性可以在加密算法和安全方案的实现过程中使用。我们介绍的新特性集中在加密解决方案的两个主要方面,它们是

  • 代码质量:从传统的源代码转向现代的编写源代码的角度

  • 通过使用高级编程概念提高源代码的性能:经典与现代代码,使用优雅和规范的源代码重写大多数密码原语(如 RSA、AES、DES、Blowfish、Twofish 等)。)关注 lambda 表达式和 LINQ 语言

  • 实施过程中使用的变量大小,并确保分配了适当的大小:分配内存大小并使用适当的大小和类型非常重要,尤其是当应用受到攻击时(软件混淆、缓冲区溢出等)。).这种攻击非常棘手,一旦被利用,会对软件应用造成严重破坏。

文献学

  1. C# 语言版本控制。网上有: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version

  2. 跨度结构。网上有: https://docs.microsoft.com/en-us/dotnet/api/system.span-1?view=netcore-3.1

  3. C# 语言版本控制。网上有: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version

[混合波束成形]基于深度学习的大规模天线阵列混合波束成形设计(Matlab代码、Python代码实现)内容概要:本文介绍了基于深度学习的大规模天线阵列混合波束成形的设计方法,并提供了Matlab和Python代码实现。该设计聚焦于5G及未来通信系统中的关键使能技术——混合波束成形,通过深度神经网络对复杂的信道状态信息(CSI)进行高效估计与波束成形矩阵优化,在保证通信性能的同时降低硬件成本与计算开销。文中详细阐述了算法模型构建、训练流程设计及仿真验证过程,展示了深度学习在通信物理层中的深度融合应用,尤其适用于毫米波大规模MIMO系统场景。; 适合人群:具备通信工程、信号处理或人工智能基础知识的研究生、科研人员及从事5G/6G技术研发的工程师;熟悉Matlab或Python编程,对深度学习和无线通信系统有一定实践经验者更为适宜。; 使用场景及目标:①研究深度学习在无线通信物理层中的应用,特别是CSI反馈压缩与波束成形优化;②复现先进混合波束成形算法,提升系统频谱效率与能效;③为学术论文复现、课题研究或工程项目开发提供可运行的代码参考与技术路线支持。; 阅读建议:建议读者结合文中提供的代码逐模块分析,重点关注神经网络结构设计与通信约束条件的融合方式,同时可扩展尝试不同网络架构或信道模型以深化理解。
STM32电机库无感代码注释无传感器版本龙贝格观测三电阻双AD采样前馈控制弱磁控制斜坡启动内容概要:本文档为一份名为《STM32电机库无感代码注释无传感器版本龙贝格观测三电阻双AD采样前馈控制弱磁控制斜坡启动》的技术资料,主要围绕基于STM32的永磁同步电机(PMSM)无传感器矢量控制系统的实现展开,详细注解了采用龙贝格观测器(Luenberger Observer)进行转子位置与速度估算的控制算法,涵盖三电阻采样、双通道ADC数据采集、电流环前馈补偿、弱磁扩速控制及斜坡启动策略等关键技术模块。该文档不仅提供了完整的控制逻辑说明,还深入解析了底层代码实现,适用于高精度、高性能电机控制系统的开发与学习。; 适合人群:具备一定嵌入式开发基础和电机控制理论知识的电气工程、自动化、机电一体化等相关专业的高校师生、科研人员及从事电机驱动开发的工程师;尤其适合希望深入理解无传感器电机控制算法及STM32平台实现的技术人员。; 使用场景及目标:①学习和掌握基于龙贝格观测器的无传感器电机控制原理与实现方法;②理解三电阻采样、双AD同步采集、前馈控制、弱磁控制和斜坡启动等关键环节的设计思路与代码实现;③用于高校课程设计、毕业设计、科研项目开发或工业级电机控制器的研发参考。; 阅读建议:建议读者结合STM32开发环境和电机控制实验平台进行代码阅读与调试,配合电机控制理论教材逐步理解各模块功能,重点关注观测器设计、坐标变换、PI调节器参数整定及ADC采样时序等核心部分,以实现理论与实践的有效结合。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值