在工程中有时候需要用到随机数函数来模拟一些情况,例如加密系统的密钥来源可以用随机数函数获取。

一般来说随机数函数需要有以下性质:

1:随机性,不存在统计学偏差,是完全散乱的数列。

2:不可预测性:不能从过去的的数列推算出下一个出现的数

3:不可重现性:除非数列保存下来,否则不能重新相同的数列(比较难)。

根据以上三个性质,可以将随机数函数分为“弱伪随机数”,“强伪随机数”,“真随机数”。

其中“真随机数”靠软件无法实现,需要借助物理性质,如量子密钥更具量子的偏振等物理状态生成的比特数据即真随机数,而生成随机数的设备称为“随机数生成器”。而“伪随机数”可以依靠软件来实现,该软件一般统称为“伪随机数生成器”。

本章主要围绕伪随机数进行叙述和论证。

伪随机数生成器,其结构为

例如下列以系统时间为种子实现内部初始化的伪随机数生成器,该函数在stdlib.h中提供。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>/*
伪随机数生成(系统调用)
为提高随机性,rand()函数生成的随机数取第一个字节
data[in, out]: 输入时表示待存随机数的缓存空间,输出时表示生成的随机数
len[in]: 需要生成随机数的大小,单位字节
*/
void prng_genrnd_by_system(unsigned char *data, unsigned int len)
{unsigned int i = 0;unsigned int j = 0;/* 随机数函数初始化,以系统时间为种子 */srand((unsigned int)time(NULL)); for ( i = 0; i < len; i++){j = rand();memcpy(data + i, &j, 1);}
}

一个合格的伪随机数生成器需要具备长周期(避免短数列不断重复)和严谨的算法(验证其具备不可预测性),下面我具体列举一些伪随机数生成器的算法:

线性同余法

如C的rand函数和JAVA的java.util.Random类就是使用线性同余法,其为弱伪随机数算法,公式为:

Rn+1 = ( A x Rn + C )modM

例如第一个伪随机数 R0 = ( A x 种子 + C)modM

其中A、C、M为常量,A<M,C<M

第二个伪随机数R1 = ( A x R0  + C)modM

该算法生成的随机数列范围在0~M-1之间,算法的函数实现为

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>/* A、C、M为常量,A<M,C<M */
#define LINEAR_CONGRUENTIAL_METHOD_A (0x87)
#define LINEAR_CONGRUENTIAL_METHOD_C (0x32)
#define LINEAR_CONGRUENTIAL_METHOD_M (0x91)/*
伪随机数生成(线性同余法)Rn+1 = ( A x Rn + C )modM
为提高随机性,每次产生的随机数取第一个字节
data[in, out]: 输入时表示待存随机数的缓存空间,输出时表示生成的随机数
len[in]: 需要生成随机数的大小,单位字节
*/
void prng_genrnd_by_linear_congruential_method(unsigned char *data, unsigned int len)
{unsigned int i = 0;unsigned int a = LINEAR_CONGRUENTIAL_METHOD_A;unsigned int c = LINEAR_CONGRUENTIAL_METHOD_C;unsigned int m = LINEAR_CONGRUENTIAL_METHOD_M;unsigned int r0 = (unsigned int)time(NULL); // 以系统时间为种子unsigned int r1 = 0;for ( i = 0; i < len; i++){r1 = (r0*a + c)%m;memcpy(data + i, &r1, 1);r0 = r1;}
}

该算法不具备不可预测性,攻击者只要知晓初始化时A、C、M的值,便可以根据当前随机数列推算出下一个随机数列。

单向散列函数法

单向散列函数在之前的篇章中有提过,利用单向散列函数可以对一组数据生成特定的散列值。

在本章中将利用单向散列函数生成具备不可预测性的强伪随机数生成器。该算法的生成器将之前有进一步优化其结构为:

从随机数生成器结构上我们可以清楚的了解到,该算法利用了单向散列函数的强碰撞性和单向性使得伪随机数生成器拥有不可预知性,使得攻击者即便得到算法和当前随机数也无法推算出下一列随机数值,除非攻击者能获得之前所有的随机数。下面利用SHA-1来实现具体的函数:

#include <stdio.h>
#include <stdlib.h>
#define SHA1_ROTL(a,b) (SHA1_tmp=(a),((SHA1_tmp>>(32-b))&(0x7fffffff>>(31-b)))|(SHA1_tmp<<b))
#define SHA1_F(B,C,D,t) ((t<40)?((t<20)?((B&C)|((~B)&D)):(B^C^D)):((t<60)?((B&C)|(B&D)|(C&D)):(B^C^D)))
long SHA1_tmp;
extern char* StrSHA1(const char* str, long long length, char* sha1){/*计算字符串SHA-1参数说明:str         字符串指针length      字符串长度sha1         用于保存SHA-1的字符串指针返回值为参数sha1*/char *pp, *ppend;long l, i, K[80], W[80], TEMP, A, B, C, D, E, H0, H1, H2, H3, H4;H0 = 0x67452301, H1 = 0xEFCDAB89, H2 = 0x98BADCFE, H3 = 0x10325476, H4 = 0xC3D2E1F0;for (i = 0; i < 20; K[i++] = 0x5A827999);for (i = 20; i < 40; K[i++] = 0x6ED9EBA1);for (i = 40; i < 60; K[i++] = 0x8F1BBCDC);for (i = 60; i < 80; K[i++] = 0xCA62C1D6);l = length + ((length % 64 > 56) ? (128 - length % 64) : (64 - length % 64));if (!(pp = (char*)malloc((unsigned long)l))) return 0;for (i = 0; i < length; pp[i + 3 - 2 * (i % 4)] = str[i], i++);for (pp[i + 3 - 2 * (i % 4)] = 128,i++; i < l; pp[i + 3 - 2 * (i % 4)] = 0,i++);*((long*)(pp + l - 4)) = length << 3;*((long*)(pp + l - 8)) = length >> 29;for (ppend = pp + l; pp < ppend; pp += 64){for (i = 0; i < 16; W[i] = ((long*)pp)[i], i++);for (i = 16; i < 80; W[i] = SHA1_ROTL((W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]), 1), i++);A = H0, B = H1, C = H2, D = H3, E = H4;for (i = 0; i < 80; i++){TEMP = SHA1_ROTL(A, 5) + SHA1_F(B, C, D, i) + E + W[i] + K[i];E = D, D = C, C = SHA1_ROTL(B, 30), B = A, A = TEMP;}H0 += A, H1 += B, H2 += C, H3 += D, H4 += E;}free(pp - l);sprintf(sha1, "%08X%08X%08X%08X%08X", H0, H1, H2, H3, H4); return sha1;
}static char *seed_;  //种子
static num_=0;  //计数器void Init(char *seed)
{seed_ = seed;
}void SHA1_Rand(char *buff ,int bufflen)
{int i;char sha1buff[33] = {0};char str[1024]={0};while(bufflen/32!=0){bufflen-=32;sprintf(str, "%s%d", seed_, num_++);StrSHA1(str, strlen(str), sha1buff);sprintf(buff, "%s%s", buff, sha1buff);}sprintf(str, "%s%d", seed_, num_++);StrSHA1(str, strlen(str), sha1buff);strncpy(str, sha1buff, bufflen%32);
}int main()
{char *buff = "hello world";  //种子Init(buff);char key[65] ={0};SHA1_Rand(key, 64);printf("%s\n", key);
}

密码法:

与单向散列法相似,密码法利用加密输出随机数实现随机数的不可预知性,其加密可以采用对称加密AES算法,或者公钥算法其结构为:

密码法的函数实现可以参照单向散列函数,这里不再列写。

此外如果对随机性强度还是不满足,可以了解下ANSI X9.17。一般来说以上三种强伪随机数算法已满足大多数需求。

随机数生成器,基于软件的伪随机数算法相关推荐

  1. Python中的随机数生成器模块(真/伪随机数)

    真随机数发生器(TRNG) 真随机数发生器会生成几乎无法预测的随机数,因为影响结果值变化的因素是物理环境的特征.例如,掷骰子将生成难以预测的随机值.但是骰子的数量限制为1到6.因此,几乎很难预测生成随 ...

  2. ARPA基于BLS的门限签名算法随机数生成器设计

    作者 | ARPA 责编 | 晋兆雨 头图 | 付费下载于视觉中国 随机数已经在密码学.彩票和游戏等众多领域被广泛使用.区块链与随机性也有着紧密的关联,因为它们从随机性中寻求公平.被广泛应用的的工作量 ...

  3. 【算法学习】随机化算法 随机数生成器和mt19937

    文章目录 1. 伪随机数 2. 模运算 3. 乘同余法随机数生成器 (1) 原理 (2) 程序实现 4. 混合同余法 5. mt19937 1. 伪随机数 Treap.跳跃表和随机快速排序等需要用到随 ...

  4. 基于Twitter的Snowflake算法实现的分布式ID生成器

    /*** 基于Twitter的Snowflake算法实现的分布式ID生成器* ------------------------------------------------------------- ...

  5. 基于哈夫曼算法的文件压缩软件

    数据结构课设(一) 作业要求 1.设计并实现一个使用哈夫曼算法对文件进行压缩的工具软件. 2.通过命令行参数指定操作模式(压缩/解压).源文件名.目标文件名. 3.压缩操作将源文件按字节读入并统计字节 ...

  6. 数论练习二之BSGS算法——随机数生成器,Matrix,Lunar New Year and a Recursive Sequence,Fermat‘s Last Theorem

    [SDOI2013] 随机数生成器 description solution 肯定是非常想找一个通项公式来表示第nnn个数的 依据形式,考虑化成等比数列 xi+1+k=a(xi+k)=a⋅xi+b+t ...

  7. 开源Math.NET基础数学类库使用(13)C#实现其他随机数生成器

    原文:[原创]开源Math.NET基础数学类库使用(13)C#实现其他随机数生成器                本博客所有文章分类的总目录:http://www.cnblogs.com/asxiny ...

  8. UA STAT675 统计计算I 随机数生成1 随机数生成器的一般理论

    UA STAT675 统计计算I 随机数生成1 随机数生成器的一般理论 RNG的抽象表示 RNG的质量指标 RNG的统计检测 在统计计算中,从某个分布中进行采样通常分为两个步骤: 生成随机数z1,z2 ...

  9. 香蕉为什么能做随机数生成器?因为,它是水果界的“辐射之王”

    程序员的成长之路 互联网/程序员/技术/资料共享 关注 阅读本文大概需要 5 分钟. 来自:杨净 丰色 发自 凹非寺 量子位 | 公众号 QbitAI 一个香蕉,竟然还能这么用?! 真·随机数生成器, ...

最新文章

  1. ionic + cordova 配置和开发过程中的一些问题
  2. vscode 导入文件_VScode中误报Unableto import'xxx'pylint(import-error)解决方案
  3. python中的语言特性_python自测——语言特性
  4. 记几种解决跨域问题的办法
  5. 深度学习笔记(43) Siamese网络
  6. pytorch1.0神经网络保存、提取、加载
  7. 【心电信号】基于matlab Simulink胎儿心电信号提取【含Matlab源码 1550期】
  8. 基于西储大学的轴承故障诊断系统设计
  9. PHP laravel系列之迷你博客搭建
  10. 基于opendota的dota2战绩查询微信小程序
  11. 网络篇 OSPF的DR与BDR的选举-48
  12. 流程图基础绘制方法和流程图制作软件功能详解
  13. 使用R进行描述性统计分析(连续性变量)
  14. 吾生有涯 而知也无涯
  15. 伽马函数公式 ∫x^ne^{-x}dx=n!
  16. 有谁知道怎么处理微信用户头像过期问题,除了本地保存,因为不会用七牛云远程附件
  17. 学会“狼”的思维(二)
  18. iqn怎么查 linux_Linux下配置iscsi-initiator - 存储资源
  19. 利用C语言打印杨辉三角
  20. PostgreSQL 多维空间几何对象 相交、包含 高效率检索实践 - cube

热门文章

  1. 土法神经网络 Part I:计算图
  2. 6.6折票最后1天 | 2019中国大数据技术大会(BDTC)超强阵容及日程全面揭晓!
  3. 分享软文要注意什么问题
  4. 【数据分析思维】逻辑树分析(费米估算)
  5. 【认证服务】验证码、社交登录、分布式session、单点登录
  6. 【读书笔记】科技自传-小米手机,雷军传:让未来的你,感谢现在努力的自己_2019.05.19
  7. 面试官:给我说说什么是中间人攻击?
  8. Java中Map接口的使用和有关集合的面试知识点补充
  9. 阿里开源的15个顶级Java项目
  10. Linux学习5之文件目录指令对对碰