信息安全数学基础实验

实验一

1.1 求最大公因数

#include <stdio.h>
int gcd1(int a,int b){
    return b==0?a:gcd1(b,a%b);
}
int gcd2(int a,int b){
    int r;
    while(b!=0){
        r=a%b;
        a=b;
        b=r;
    }
    return a;
}
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    int x=gcd2(a,b);
    printf("%d\n",x);
    printf("%d",a*b/x);
}

1.2 求s、t,满足(a,b)=sa+tb(扩展欧几里得算法)

https://oi-wiki.org/math/number-theory/gcd/

#include <stdio.h>
void extended_gcd1(int a,int b,int *x0,int *y0){
    int r=0,q=0;
    int x1=0,y1=1,x2=0,y2=0;
    *x0=1;*y0=0;
    while(b!=0){
        q=a/b;
        r=a-q*b;
        x2=*x0-x1*q;
        y2=*y0-y1*q;
        a=b;b=r;
        *x0=x1;*y0=y1;
        x1=x2;y1=y2;
    }
}
void extended_gcd2(int a,int b,int *x,int *y){
    if(b==0){
        *x=1;
        *y=0;
        return ;
    }
    extended_gcd2(b,a%b,y,x);
    *y-=a/b*(*x);
}
int main(){
    int a,b;
    scanf("%d%d",&a,&b);
    int a1=a,b1=b;
    int x0,y0;
    extended_gcd2(a,b,&x0,&y0);

    printf("%d=%d*",a,a1);
    if(x0<0)
        printf("(%d)",x0);
    else printf("%d",x0);
    printf("+%d*",b1);
    if(y0<0)
        printf("(%d)",y0);
    else printf("%d",y0);
}

1.3 求二元一次不定方程的解 a x + b y = c ax+by=c ax+by=c

这个可以求一个特解

#include <stdio.h>
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
void extended_gcd(int a,int b,int *x,int *y){
    if(b==0){
        *x=1;
        *y=0;
        return ;
    }
    extended_gcd(b,a%b,y,x);
    *y-=a/b*(*x);
}

int main(){
    int a,b,c,a1,b1,g,x0,y0;
    scanf("%d%d%d",&a,&b,&c);
    int m=gcd(gcd(a,b),c);
    if(m!=1){    //方程化简,等号两边约掉公因数
        a=a/m;
        b=b/m;
        c=c/m;
    }
    g=gcd(a,b);
    if(c%g==0){
        printf("方程有解\n");
        a1=a/g;
        b1=b/g;
        extended_gcd(a,b,&x0,&y0);
        printf("%d %d\n",x0,y0);
        printf("x=%d-(%dt), y=%d+(%dt)",x0*c,b1,y0*c,a1);
    }
    else {
        printf("无解");
    }
}

1.4 厄拉多塞筛法求素数

import java.util.*;

public class Main{
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        int[] primeList=new int[n+1];
        boolean[] isPrimeList=new boolean[n+1];
        for(int i=2;i<n;i++)       //初试化都为true,但是0和1为false
            isPrimeList[i]=true;
        int p=0;
        for(int i=2;i<=n;i++){
            if(isPrimeList[i])
                primeList[p++]=i;
            //因为2到i-1的倍数已经筛过了,这里直接从i的倍数开始
            if(i*i<=n)
                for(int j=i*i;j<=n;j+=i)
                    isPrimeList[j]=false;
        }
        for(int i=0;i<p;i++){
            System.out.print(primeList[i]+" ");
        }
    }
}

实验二

2.1 给定a、m和n,计算 a m ( m o d   n ) a^m(mod\ n) am(mod n)(模重复平方算法)

将m写成二进制: m = m 0 + m 1 ∗ 2 + m 2 ∗ 2 2 + . . . + m k ∗ 2 k m=m_0+m_1*2+m_2*2^2+...+m_k*2^k m=m0+m12+m222+...+mk2k。其中 m ∈ { 0 , 1 } , i = 0 , 1 , . . , k m\in \{0,1\}, i=0,1,..,k m{0,1},i=0,1,..,k,则有
a m ≡ a m 0 ( a 2 ) m 1 . . . ( a 2 k − 1 ) m k − 1 ( a 2 k ) m k ( m o d   n ) a^m\equiv a^{m_0}(a^2)^{m_1}...(a^{2^{k-1}})^{m_{k-1}}(a^{2^k})^{m_k}(mod\ n) amam0(a2)m1...(a2k1)mk1(a2k)mk(mod n)

#include <stdio.h>
int Square_and_Multiply(int a,int m,int n){
    int a1=a;
    int res=1;
    while(m>0){
        if(m%2==1)
            res=res*a1%n;
        a1=a1*a1%n;
        m/=2;
    }
    return res;
}
int main(){
    int a,m,n;        //幂次m,模n
    scanf("%d%d%d",&a,&m,&n);
    printf("%d",Square_and_Multiply(a,m,n));
}

2.2 设计算法求解一次同余式 a x ≡ b ( m o d   m ) ax\equiv b(mod\ m) axb(mod m)

#include <stdio.h>

int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
//扩展欧几里得算法
void extended_gcd(int a,int b,int *x,int *y){       
    if(b==0){
        *x=1;
        *y=0;
        return ;
    }
    extended_gcd(b,a%b,y,x);
    *y-=a/b*(*x);
}
int main(){
    int a,b,m;
    scanf("%d%d%d",&a,&b,&m);
    int d=gcd(a,m);
    
    int a1,b1,m1;
    int s,t;
    int x0;
    if(b%d==0){
        a1=a/d;
        b1=b/d;
        m1=m/d;
        printf("同余式的解数为%d\n",d);
        extended_gcd(a,m,&s,&t);
        x0=s*b1%m;
        printf("同余式的一个特解为x0=%d\n",x0);
        printf("同余式的全部解为:\n");
        for(int i=0;i<d;i++){
            int t=x0+m1*i%m;
            printf("x%d=%d(mod %d)\n",i+1,t,m);
        }
    }
    else {
        printf("同余式无解\n");
        return 0;
    }
    
}

RSA公钥密码算法

RSA密码机制

  1. 选择两个大素数p和q,计算 n = p q n=pq n=pq
  2. 随机选取整数e和d,满足 e d ≡ 1 ( m o d φ ( n ) ) ed\equiv1(mod \varphi(n)) ed1(modφ(n)),其中 φ ( n ) \varphi(n) φ(n)为n的欧拉函数。
  3. 发布e和n为公钥,d为私钥。
  4. 设明文为m,加密函数为 c ≡ E ( m ) ≡ m e ( m o d   n ) c\equiv E(m) \equiv m^e(mod \ n) cE(m)me(mod n),其中 1 < m , c < n 1<m,c<n 1<m,c<n
  5. 解密函数为 m ≡ D ( c ) ≡ c d ( m o d   n ) m\equiv D(c) \equiv c^d(mod \ n) mD(c)cd(mod n)

证明

由于 c ≡ m e ( m o d   n ) c\equiv m^e(mod \ n) cme(mod n),因此
c d ≡ m e d ( m o d   n ) c^d\equiv m^{ed}(mod \ n) cdmed(mod n)
即证 m e d ≡ m ( m o d   n ) m^{ed} \equiv m(mod\ n) medm(mod n)
( m , n ) = 1 (m,n)=1 (m,n)=1时,由欧拉定理知
m φ ( n ) ≡ 1 ( m o d   n ) m^{\varphi (n)}\equiv 1(mod \ n) mφ(n)1(mod n)
而由条件2知
e d ≡ 1 ( m o d   φ ( n ) ) ed\equiv1(mod\ \varphi(n)) ed1(mod φ(n))
即存在整数k,使得
e d = k φ ( n ) + 1 ed=k\varphi(n)+1 ed=kφ(n)+1
因此
m e d ≡ m k φ ( n ) + 1 ≡ m ( m o d   n ) m^{ed}\equiv m^{k\varphi(n)+1}\equiv m(mod\ n) medmkφ(n)+1m(mod n)
( m , n ) ≠ 1 (m,n)\not =1 (m,n)=1时,由于 n = p q n=pq n=pq,因此
( m , n ) = p  或  ( m , n ) = q (m,n)=p \ 或 \ (m,n)=q (m,n)=p  (m,n)=q
即p|m,或q|m。若p|m,则显然 m e d ≡ m k φ ( n ) + 1 ≡ m ≡ 0 ( m o d   p ) m^{ed}\equiv m^{k\varphi(n)+1}\equiv m\equiv0(mod\ p) medmkφ(n)+1m0(mod p)
p ∤ m p \not | m pm,则由费马小定理知 m p − 1 ≡ 1 ( m o d   p ) m^{p-1}\equiv 1(mod \ p) mp11(mod p)
于是 m k φ ( n ) + 1 ≡ m k ( p − 1 ) ( q − 1 ) + 1 ≡ m ( m o d   p ) m^{k\varphi(n)+1}\equiv m^{k(p-1)(q-1)+1}\equiv m(mod\ p) mkφ(n)+1mk(p1)(q1)+1m(mod p)
因此,对任意 m , m e d ≡ m k φ ( n ) + 1 ≡ m ( m o d   p ) m,m^{ed}\equiv m^{k\varphi(n)+1}\equiv m(mod\ p) m,medmkφ(n)+1m(mod p)成立。
同理可证,对任意 m , m e d ≡ m k φ ( n ) + 1 ≡ m ( m o d   q ) m,m^{ed}\equiv m^{k\varphi(n)+1}\equiv m(mod\ q) m,medmkφ(n)+1m(mod q)成立。因此 m e d ≡ m ( m o d      n ) m^{ed}\equiv m(\mod \ n) medm(mod n)成立。

代码实现

实验三

3.1 欧拉函数的计算

#include <stdio.h>
#include <math.h>
int eular(int n){
    int res=n;
    for(int i=2;i*i<=n;i++){   //判断n是否为质数
        if(n%i==0)
            res=res/i*(i-1);    //res=res*(1-1/i) 先进行除法防止溢出
        while(n%i==0){
            n/=i;
        }
    }
    if(n>1)
        res=res/n*(n-1);
    return res;
}
int main(){
    int n;
    scanf("%d",&n);
    printf("%d",eular(n));
    return 0;
}

3.2 勒让德符号的计算

#include <stdio.h>
#include <math.h>
int L_FAST(int a,int p){
    int s,a1=a;
    if(a==0)
        return 0;
    else if(a==1)
        return 1;
    else {
        int e=0;
        while(a%2==0){
            a=a/2;
            e++;
        }
        if(e%2==0)
            s=1;
        else {
            if(p%8==1||p%8==7)
                s=1;
            if(p%8==3||p%8==5)
                s=-1;
        }
        if(p%4==3&&a1%4==3)
            s=-s;
        int p1=p%a1;
        if(a1==1)
            return s;
        else return s*L_FAST(p1,a1);
    }
}
int main(){
    int a,p,L;
    printf("请依次输入整数a,奇素数p>=3,且0<=a<p:");
    scanf("%d %d",&a,&p);
    printf("Legendre符号为:%d\n",L_FAST(a,p));
}

3.3 求原根

import java.util.Scanner;

public class Main{

    private static boolean[] primes = new boolean[32170];

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        setPrime();
        for (int i = 2; i < n; i++)
            if (quickPow(i, n - 1, n) == 1)
                if (isPrimeRoot(i, n - 1)) {
                    System.out.println(i);
                    return;
                }
    }
    //判断是否为原根
    private static boolean isPrimeRoot(int g, int P) {
        for (int i = 2; i < P; i++) {
            if (!primes[i] && quickPow(P, 1, i) == 0)
                if (quickPow(g, P / i, P + 1) == 1)
                    return false;
            while (P % i == 0) P /= i;
        }
        return true;
    }
    //筛法求素数
    private static void setPrime() {
        for (int i = 2; i < 32170; i++)
            if (!primes[i])
                for (int j = i * 2; j < 32170; j += i)
                    primes[j] = true;
    }
    //快速幂
    private static int quickPow(int a, int b, int c) {
        int ans = 1;
        for (; b != 0; b /= 2) {
            if (b % 2 == 1)
                ans = (ans * a) % c;
            a = (a * a) % c;
        }
        return ans;
    }
}

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

能饮一杯吴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值