【密码学】一文读懂基于Elgamal的数字签名

简介: 本文来先填一下之前挖的坑,简单介绍一个实际的数字签名的方案,给自己挖的坑总是要自己来填的。

一文读懂基于Elgaml的数字签名


6JQ5NHU1M)MD@WQYI)2L9]C.jpg基于Elgamal的数字签名方案

本文来先填一下之前挖的坑,简单介绍一个实际的数字签名的方案,给自己挖的坑总是要自己来填的。


知识回顾

在介绍具体的签名算法之前,首先来回顾一下之前讲过的离散对数和数论相关的知识,对于素数p, 如果是p的原根,那么对于取模p之后的值是不同的,然后,我们可以得到下面两个结论。

  • 对于任意的整数m,  , 当且仅当
  • 对于任意整数i, j,, 当且仅当


密钥选择

如果读者看过我之前聊过的基于elgamal的加密,理解后面这些内容相对来说会轻松不少,不过要是没看过也没有关系,我尽量也是把每个细节聊清楚。

基于Elgamal的数字签名,全局元素是p和  , 其中  是p的原根,然后根据下面的方法生成公私钥对。

  • 生成随机整数 , 使得
  • 计算
  • A的私钥是, A的公钥是


签名过程

如果用户A需要对消息M进行签名,则按照如下的步骤进行处理

  • 计算消息M的哈希值m = H(M),其中 m 在
  • 随机选择一个整数K, 使  并且 , 也就是K和p-1互素
  • 计算
  • 计算, 这里可不是普通的指数运算,而是求逆运算这也就是前面要求互素的原因, 因为不互素是没有逆的。
  • 计算
  • 最终生成的签名(, )


签名验证过程

对于任意的用户, 都能按照如下的方式对签名进行验证

image.png

如果, 说明签名有效。

接下来,简单证明一下,为什么上面, 就可以说明签名是有效的吧, 假设这个等式成立,则有。

image.png

代码实现

好久没给出具体的实现了,这篇文章回归一下,来用rust简单的实现一下这个数字签名算法。

use std::ops::{Mul, Sub};
use num_bigint::{BigInt, RandBigInt, ToBigInt};
use num_traits::{zero, one};
pub struct Elgamal {}
pub struct PublicKey {
    alpha: BigInt,
    p: BigInt,
    y: BigInt,
}
pub struct PrivateKey {
    alpha: BigInt,
    p: BigInt,
    x: BigInt,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ElGamalSign {
    s1: BigInt,
    s2: BigInt,
}
pub fn mod_inv(u: &BigInt, v: &BigInt) -> BigInt {
    let mut q: BigInt;
    let mut t1: BigInt;
    let mut t3: BigInt;
    let (mut u1, mut u3, mut v1, mut v3) =
        (BigInt::from(1u8), u.clone(), BigInt::from(0u8), v.clone());
    let mut iter: i8 = 1;
    while &v3 != &zero() {
        q = &u3 / &v3;
        t3 = &u3 % &v3;
        t1 = &u1 + &q * &v1;
        u1 = v1;
        v1 = t1;
        u3 = v3;
        v3 = t3;
        iter = -iter;
    }
    if &u3 != &one() {
        return zero();
    }
    if iter < 0 {
        return v - u1;
    }
    u1
}
impl Elgamal {
    fn sign(m: &BigInt, sk: &PrivateKey) -> ElGamalSign {
        let mut rng = rand::thread_rng();
        let mut k = rng.gen_bigint_range(&BigInt::from(1u8), &(&sk.p - BigInt::from(1u8)));
        let p_sub_one = &sk.clone().p.clone().sub(1.to_bigint().unwrap());
        let mut key_inv = mod_inv(&k, p_sub_one);
        while key_inv.eq(&zero()) {
            k = rng.gen_bigint_range(&BigInt::from(1u8), &(&sk.p - BigInt::from(1u8)));
            key_inv = mod_inv(&k, p_sub_one);
        }
        let s1 = sk.alpha.modpow(&k, &sk.p) % &sk.p;
        let s2 = key_inv.mul(m.sub(&sk.clone().x.clone().mul(&s1))) % &sk.clone().p.clone().sub(1.to_bigint().unwrap()) % (&sk.clone().p.clone().sub(1.to_bigint().unwrap()));
        ElGamalSign {
            s1: s1.clone(),
            s2,
        }
    }
    fn verify(m: &BigInt, s1: &BigInt, s2: &BigInt, pk: &PublicKey) -> bool {
        let v1 = pk.alpha.modpow(&m, &pk.p);
        let v2 = pk.y.modpow(&s1, &pk.p).mul(s1.modpow(&s2, &pk.p)) % &pk.p;
        v1.eq(&v2)
    }
}
#[cfg(test)]
mod test {
    use num_bigint::BigInt;
    use crate::elgamal_sign::{PublicKey, PrivateKey, Elgamal};
    #[test]
    fn test() {
        let p = BigInt::from(19u8);
        let alpha = BigInt::from(10u8);
        let x = BigInt::from(5u8);
        let y = alpha.modpow(&x, &p);
        let pk = PublicKey {
            p: p.clone(),
            alpha: alpha.clone(),
            y,
        };
        let sk = PrivateKey {
            p: p.clone(),
            alpha: alpha.clone(),
            x,
        };
        let m = BigInt::from(17u8);
        let sign = Elgamal::sign(&m, &sk);
        println!("{:?}", sign);
        let result = Elgamal::verify(&m, &sign.s1, &sign.s2, &pk);
        println!("{:?}", result);
    }
}


相关文章
|
Rust 算法 数据安全/隐私保护
【密码学】一文读懂XTEA加密
本篇文章,我们来看一下上一次讲过的TEA加密算法的一个升级版XTEA, 相比于TEA, XTEA的安全性显然是更高的,其中的过程要比TEA稍微复杂一点点。
1251 0
【密码学】一文读懂XTEA加密
|
Rust 算法 安全
【密码学】一文读懂HMAC
本文将来聊一聊基于哈希函数的消息认证码,在此之前,先来科普一下什么是 「消息认证码」 (MAC), 先来看一个简单的栗子
1626 0
【密码学】一文读懂HMAC
|
Rust 算法 Go
【密码学】一文读懂MurMurHash3
本文应该是MurMurHash算法介绍的最后一篇,来一起看一下最新的MurMurHash算法的具体过程,对于最新的算法来说,整个流程和之前的其实也比较相似,这里从维基百科当中找到了伪代码,也就不贴出来Google官方给出的推荐代码了,先来看一下维基百科给出的伪代码,这里只有32位的伪代码。
2086 0
【密码学】一文读懂MurMurHash3
|
Rust 算法 安全
【密码学】一文读懂MurMurHash2
上次我们聊过了一代的MurMurHash算法,是的,我又来水文章了,今天呢,接着来聊一下二代的MurMurHash算法,二代算法的整体结构实际上和一代算法差不太多,只是对于每一轮数据的处理过程当中的运算有一些差异,算法的来源依然是来自于Google官网给提供的源码,对着源码看的结构,对于这个算法呢,有两个版本,一个是32位的,一个是64位的,对于32位的算法和64位的算法,区别在于两个初始的魔数不同,整体运算过程还是十分相似的。
2146 0
【密码学】一文读懂MurMurHash2
|
Rust 算法 网络安全
【密码学】一文读懂CMAC
介于上一篇文章比较水,然后这个和上一篇也比较相似,CMAC是为了解决DAA当中安全性不足的问题而出现的,这个算法一共有三个密钥,K, K1, K2, 其中K1和K2可以由K导出,接下来就来一起看一下CMAC的具体过程吧,这一篇文章其实也不长。
3618 0
【密码学】一文读懂CMAC
|
Web App开发 Rust 算法
【密码学】一文读懂ChaCha20
好久没写新的加密算法的原理了, 这次所选取的加密算法结构比较简单, 一起来看一下吧。
7458 0
【密码学】一文读懂ChaCha20
|
算法 数据安全/隐私保护
【密码学】一文读懂Whirlpool
首先呢,祝大家今晚节日快乐,Whirlpool是由Vincent Rijmen(高级加密标准的联合创始人)和Paulo S.L.M.Barreto设计的,后者于2000年首次提出了它。
1086 0
【密码学】一文读懂Whirlpool
|
算法 安全 Go
【密码学】一文读懂HKDF
我这又来水一篇文章,来聊一下HKDF(基于HMAC的密钥导出函数)。密钥派生函数是密钥管理的组成部分,他的目标是通过一些初始的数据派生出来密码学安全的随机密钥。
3050 1
【密码学】一文读懂HKDF
|
算法 安全 数据安全/隐私保护
【密码学】 一篇文章讲透数字签名
数字签名(又称公钥数字签名)是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。它是一种类似写在纸上的普通的物理签名,但是在使用了公钥加密领域的技术来实现的,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。数字签名是非对称密钥加密技术与数字摘要技术的应用。数字签名可以识别消息是否被篡改, 并验证消息的可靠性, 也可以防止否认。
710 0
【密码学】 一篇文章讲透数字签名
|
算法 数据安全/隐私保护
【密码学】一文读懂SHA-1
SHA-1(Secure Hash Algorithm 1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦资料处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。
1194 1
【密码学】一文读懂SHA-1