hash算法原理详解
散列方法的主要思想是根据结点的关键码值来确定其存储地址:以关键码值K为自变量,通过一定的函数关系h(K)(称为散列函数),计算出对应的函数值来,把这个值解释为结点的存储地址,将结点存入到此存储单元中。检索时,用同样的方法计算地址,然后到相应的单元里去取要找的结点。通过散列方法可以对结点进行快速检索。散列(hash,也称“哈希”)是一种重要的存储方式,也是一种常见的检索方法。
按散列存储方式构造的存储结构称为散列表(hash table)。散列表中的一个位置称为槽(slot)。散列技术的核心是散列函数(hash function)。 对任意给定的动态查找表DL,如果选定了某个“理想的”散列函数h及相应的散列表HT,则对DL中的每个数据元素X。函数值h(X.key)就是X在散列表HT中的存储位置。插入(或建表)时数据元素X将被安置在该位置上,并且检索X时也到该位置上去查找。由散列函数决定的存储位置称为散列地址。 因此,散列的核心就是:由散列函数决定关键码值(X.key)与散列地址h(X.key)之间的对应关系,通过这种关系来实现组织存储并进行检索。
一般情况下,散列表的存储空间是一个一维数组HT[M],散列地址是数组的下标。设计散列方法的目标,就是设计某个散列函数h,0
在以下的讨论中,我们假设处理的是值为整型的关键码,否则我们总可以建立一种关键码与正整数之间的一一对应关系,从而把该关键码的检索转化为对与其对应的正整数的检索;同时,进一步假定散列函数的值落在0到M-1之间。散列函数的选取原则是:运算尽可能简单;函数的值域必须在散列表的范围内;尽可能使得结点均匀分布,也就是尽量让不同的关键码具有不同的散列函数值。需要考虑各种因素:关键码长度、散列表大小、关键码分布情况、记录的检索频率等等。下面我们介绍几种常用的散列函数。
顾名思义,除余法就是用关键码x除以M(往往取散列表长度),并取余数作为散列地址。除余法几乎是最简单的散列方法,散列函数为: h(x) = x mod M。
使用此方法时,先让关键码key乘上一个常数A (0
由于整数相除的运行速度通常比相乘要慢,所以有意识地避免使用除余法运算可以提高散列算法的运行时间。平方取中法的具体实现是:先通过求关键码的平方值,从而扩大相近数的差别,然后根据表长度取中间的几位数(往往取二进制的比特位)作为散列函数值。因为一个乘积的中间几位数与乘数的每一数位都相关,所以由此产生的散列地址较为均匀。
假设关键字集合中的每个关键字都是由 s 位数字组成 (u1, u2, …, us),分析关键字集中的全体,并从中提取分布均匀的若干位或它们的组合作为地址。数字分析法是取数据元素关键字中某些取值较均匀的数字位作为哈希地址的方法。即当关键字的位数很多时,可以通过对关键字的各位进行分析,丢掉分布不均匀的位,作为哈希值。它只适合于所有关键字值已知的情况。通过分析分布情况把关键字取值区间转化为一个较小的关键字取值区间。
举个例子:要构造一个数据元素个数n=80,哈希长度m=100的哈希表。不失一般性,我们这里只给出其中8个关键字进行分析,8个关键字如下所示:
K1=61317602 K2=61326875 K3=62739628 K4=61343634
K5=62706815 K6=62774638 K7=61381262 K8=61394220
分析上述8个关键字可知,关键字从左到右的第1、2、3、6位取值比较集中,不宜作为哈希地址,剩余的第4、5、7、8位取值较均匀,可选取其中的两位作为哈希地址。设选取最后两位作为哈希地址,则这8个关键字的哈希地址分别为:2,75,28,34,15,38,62,20。
此法适于:能预先估计出全体关键字的每一位上各种数字出现的频度。
将关键码值看成另一种进制的数再转换成原来进制的数,然后选其中几位作为散列地址。
例Hash(80127429)=(80127429)13=8 137+0 136+1 135+2 134+7 133+4 132+2*131+9=(502432641)10如果取中间三位作为哈希值,得Hash(80127429)=432
为了获得良好的哈希函数,可以将几种方法联合起来使用,比如先变基,再折叠或平方取中等等,只要散列均匀,就可以随意拼凑。
有时关键码所含的位数很多,采用平方取中法计算太复杂,则可将关键码分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位)作为散列地址,这方法称为折叠法。
分为:
尽管散列函数的目标是使得冲突最少,但实际上冲突是无法避免的。因此,我们必须研究冲突解决策略。冲突解决技术可以分为两类:开散列方法( open hashing,也称为拉链法,separate chaining )和闭散列方法( closed hashing,也称为开地址方法,open addressing )。这两种方法的不同之处在于:开散列法把发生冲突的关键码存储在散列表主表之外,而闭散列法把发生冲突的关键码存储在表中另一个槽内。
(1)拉链法
开散列方法的一种简单形式是把散列表中的每个槽定义为一个链表的表头。散列到一个特定槽的所有记录都放到这个槽的链表中。图9-5说明了一个开散列的散列表,这个表中每一个槽存储一个记录和一个指向链表其余部分的指针。这7个数存储在有11个槽的散列表中,使用的散列函数是h(K) = K mod 11。数的插入顺序是77、7、110、95、14、75和62。有2个值散列到第0个槽,1个值散列到第3个槽,3个值散列到第7个槽,1个值散列到第9个槽。
闭散列方法把所有记录直接存储在散列表中。每个记录关键码key有一个由散列函数计算出来的基位置,即h(key)。如果要插入一个关键码,而另一个记录已经占据了R的基位置(发生碰撞),那么就把R存储在表中的其它地址内,由冲突解决策略确定是哪个地址。
闭散列表解决冲突的基本思想是:当冲突发生时,使用某种方法为关键码K生成一个散列地址序列d0,d1,d2,... di ,...dm-1。其中d0=h(K)称为K的基地址地置( home position );所有di(0
形成探查的方法不同,所得到的解决冲突的方法也不同。下面是几种常见的构造方法。
(1)线性探测法
将散列表看成是一个环形表,若在基地址d(即h(K)=d)发生冲突,则依次探查下述地址单元:d+1,d+2,......,M-1,0,1,......,d-1直到找到一个空闲地址或查找到关键码为key的结点为止。当然,若沿着该探查序列检索一遍之后,又回到了地址d,则无论是做插入操作还是做检索操作,都意味着失败。 用于简单线性探查的探查函数是: p(K,i) = i
例9.7 已知一组关键码为(26,36,41,38,44,15,68,12,06,51,25),散列表长度M= 15,用线性探查法解决冲突构造这组关键码的散列表。 因为n=11,利用除余法构造散列函数,选取小于M的最大质数P=13,则散列函数为:h(key) = key%13。按顺序插入各个结点: 26: h(26) = 0,36: h(36) = 10, 41: h(41) = 2,38: h(38) = 12, 44: h(44) = 5。 插入15时,其散列地址为2,由于2已被关键码为41的元素占用,故需进行探查。按顺序探查法,显然3为开放的空闲地址,故可将其放在3单元。类似地,68和12可分别放在4和13单元中.
(2)二次探查法
二次探查法的基本思想是:生成的后继散列地址不是连续的,而是跳跃式的,以便为后续数据元素留下空间从而减少聚集。二次探查法的探查序列依次为:12,-12,22 ,-22,...等,也就是说,发生冲突时,将同义词来回散列在第一个地址的两端。求下一个开放地址的公式为:
(3)随机探查法
理想的探查函数应当在探查序列中随机地从未访问过的槽中选择下一个位置,即探查序列应当是散列表位置的一个随机排列。但是,我们实际上不能随机地从探查序列中选择一个位置,因为在检索关键码的时候不能建立起同样的探查序列。然而,我们可以做一些类似于伪随机探查( pseudo-random probing )的事情。在伪随机探查中,探查序列中的第i个槽是(h(K) + ri) mod M,其中ri是1到M - 1之间数的“随机”数序列。所有插入和检索都使用相同的“随机”数。探查函数将是 p(K,i) = perm[i - 1], 这里perm是一个长度为M - 1的数组,它包含值从1到M – 1的随机序列。
例子:
例如,已知哈希表长度m=11,哈希函数为:H(key)= key % 11,则H(47)=3,H(26)=4,H(60)=5,假设下一个关键字为69,则H(69)=3,与47冲突。如果用线性探测再散列处理冲突,下一个哈希地址为H1=(3 + 1)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 + 2)% 11 = 5,还是冲突,继续找下一个哈希地址为H3=(3 + 3)% 11 = 6,此时不再冲突,将69填入5号单元,参图8.26 (a)。如果用二次探测再散列处理冲突,下一个哈希地址为H1=(3 + 12)% 11 = 4,仍然冲突,再找下一个哈希地址为H2=(3 - 12)% 11 = 2,此时不再冲突,将69填入2号单元,参图8.26 (b)。如果用伪随机探测再散列处理冲突,且伪随机数序列为:2,5,9,……..,则下一个哈希地址为H1=(3 + 2)% 11 = 5,仍然冲突,再找下一个哈希地址为H2=(3 + 5)% 11 = 8,此时不再冲突,将69填入8号单元,参图8.26 (c)。
(4)双散列探查法
伪随机探查和二次探查都能消除基本聚集——即基地址不同的关键码,其探查序列的某些段重叠在一起——的问题。然而,如果两个关键码散列到同一个基地址,那么采用这两种方法还是得到同样的探查序列,仍然会产生聚集。这是因为伪随机探查和二次探查产生的探查序列只是基地址的函数,而不是原来关键码值的函数。这个问题称为二级聚集( secondary clustering )。
为了避免二级聚集,我们需要使得探查序列是原来关键码值的函数,而不是基位置的函数。双散列探查法利用第二个散列函数作为常数,每次跳过常数项,做线性探查。
币安链上怎么发币
1、进入区块链浏览器:
2、输入合约地址,搜索目标合约
该tab页下的Code、Read Contract都不需要连接钱包,只有 Write Contract需要连接钱包。
3、选项 Write Contract 页签,连接metamask钱包
metamask钱包连接成功后:
点击 Write 按钮后会弹出metamask钱包,提示需要消耗BNB,授权确认消耗BNB即可。
执行完成后,区块链浏览器上可以查询到执行结果。
发币完成后必须开源合约,并且验证合约代码完全匹配ABI和bytecode 。因此需要上传代币的相关信息到BSC区块链浏览器上,包括:合约名称、编译器版本、license、构造函数参数等。
以下为开源合约代码的操作步骤:
1、发币完成后记录合约的 transaction hash:0x545fa6f1cf9b2a77db4f4b7727c4fa996b55086182ea1fe03204b13057843f9c
在BSC区块链浏览器上查询该hash详情:
代码的合约地址为:0xd04798e39236b9d2e5356533788cbb65f847d91685
2、BSC区块链浏览器上查看合约详情
进入合约详情页面,选择contract TAB页签
3、点击 “Verify and Publish ” 上传代币信息到BSC区块链浏览器
4、选择合约创建时相关的信息,填写如下表单
I、合约地址是自动带出来的
II、编译器类型选择:如果合约代码是由多个文件组成的就选择:Solidity (Multi-Part files) ,如果是单个文件的合约就选择: Solidity (Single file)
III、编译器版本:要根据合约代码中的编译器版本确定,必须和合约代码编译时的版本保持一致。本示例合约编译时版本为:pragma solidity ^0.6.12,因此此处选择V0.6.12+commit.27d51765
IIIV、license授权类型:合约代码中是MIT授权,此处选择MIT即可,这个地方实际上可以随便选择。
5、以上信息配置完成后,上传合约代码文件
选择组成合约代码的所有文件,点击 “Click to Upload selected files”
点击 “Click to Upload selected files” 上传合约代码文件到区块链浏览器,上传完成后截图如下:
6、继续选择后面的配置信息,完成合约代码开源
构造函数传入参数是合约部署时输入的,确认没有问题即可。
本示例没有调用合约类库,因此合约类库地址可以不填。
交易所提币和钱包提币的哈希值有啥区别
哈希函数在区块链中起着至关重要的作用。它的做法是将复杂的交易信息加密压缩成一个简单的固定字节的哈希值,它成为了区块链的标识,保证了交易信息在区块链的不被篡改。这种算法还用于一些重要的环节,如连接相邻块、构建merkle树、交易验证、数字签名等。
1.概念
Hash: Hash,一般翻译为“Hash”,或者直接音译为“Hash”,是通过哈希算法将任意长度的输入转换为固定长度的输出,输出为哈希值.简单地说,它是将任意长度的消息压缩成某个固定长度的消息摘要的函数。我们常说的哈希算法和哈希函数通常是一个意思。
2.原理
基于密码学中的一个单向哈希函数,在业界通常用y=hash(x)来表示。这个哈希函数可以通过运算x计算出一个哈希值Y .这种函数很容易被验证,但是却很难破解.从x计算出Y很容易,但是从Y推导出x很难.也就是只有加密过程,没有解密过程。
3.特点
(1)加密过程是不可逆的,也就是说我们无法通过输出的哈希值推断出原始明文是什么。
(2)输入明文和输出哈希值是一一对应的。任何输入信息的改变都必然导致最终输出哈希值的改变。
(3)对于任何大小的输入,最终计算出的哈希值的长度都很小,而且是固定长度。
(4)很难使两个内容不同的明文的哈希值相同。也就是说,对于任意两个不同的数据块,相同哈希值的可能性极小。
4.SHA256算法
常用的哈希算法包括MD5、SHA-1、SHA-256、SHA-384和SHA-512。在区块链,SHA-256算法通常用于块加密。对于任何长度的任何消息,SHA-256都会生成一个256bit的哈希值,这个哈希值叫做消息摘要.这个抽象相当于一个长度为32字节的数组,通常用长度为64的十六进制字符串表示,就是我们看到的64个字符。
区块链利用这种算法在一个交易区块中进行交易信息进行加密,并将压缩的信息转化为由一串数字和字母组成的散列(哈希)字符串。区块链的哈希值可以唯一准确地标识一个块,任何节点都可以通过简单的哈希计算获得这个块的哈希值。计算出的哈希值没有改变,这意味着块中的信息没有被篡改。
下面是一个将明文加密成哈希值的例子。
然后把句号改成感叹号,哈希值就完全变了。
5.哈希指针(Hash Pointer)
哈希指针意味着这个变量的值是从实际数据计算出来的,并且指向实际数据的位置。也就是说,哈希指针既可以表示实际数据的存储位置,也可以表示实际数据内容(某个时间戳的数据哈希值)。
综上所述,从哈希指针的角度看区块链的结构,可以说区块链是一个以哈希指针按时间顺序连接数据块的链表。指针实际上是一串数据的哈希值,一串数据的哈希值是这串数据的“指纹”和抽象,所以可以用这个哈希值指向这串数据。
区块链中每个块都有一个hash指针对应自己的块,除了创建块(即第一个块),其他每个块都存储前一个块的hash指针,这样就形成了一个如下图的链,即区块链。
这样的数据结构可以保证数据不被篡改,因为任何一个块的数据一旦被篡改,对应的hash指针就会出错,所以后面的块的hash指针就无法匹配数据被篡改后该块生成的hash指针,所以一旦发生恶意篡改就可以检查出来。
2022-05-06_Redisson分布式锁hash中key的创建分析
20220506_Redisson分布式锁hash中key的创建分析
Redisson对象依赖connectionManager,当构建Redisson对象,通过配置创建 connectionManager
connectionManager里面有个id属性,由uuid生成。
hash的key为:goods:add:00001
field为:当前RedissonLock的uuid:当前线程的值,即1ea0b24e-e1f6-4a1b-88fc-f31f2a909bdc:51
value为:默认为1(支持可重入,累加)
线程A如果已经释放锁,则线程加锁成功,否则等待指定的时间。
hash的key为:goods:add:00001
field为:当前RedissonLock的uuid:当前线程的值,即1ea0b24e-e1f6-4a1b-88fc-f31f2a909bdc:52
value为:默认为1(支持可重入,累加)
公钥、私钥、哈希、加密算法基础概念
生活中我们对文件要签名,签名的字迹每个人不一样,确保了独特性,当然这还会有模仿,那么对于重要文件再加盖个手印,指纹是独一无二的,保证了这份文件是我们个人所签署的。
那么在区块链世界里,对应的就是数字签名,数字签名涉及到公钥、私钥、哈希、加密算法这些基础概念。
首先加密算法分为对称加密算法、非对称加密算法、哈希函数加密算法三类。
所谓非对称加密算法,是指加密和解密用到的公钥和私钥是不同的,非对称加密算法依赖于求解一数学问题困难而验证一数学问题简单。
非对称加密系统,加密的称为公钥,解密的称为私钥,公钥加密,私钥解密、私钥签名,公钥验证。
比特币加密算法一共有两类:非对称加密算法(椭圆曲线加密算法)和哈希算法(SHA256,RIMPED160算法)
举一个例子来说明这个加密的过程:A给B发一个文件,B怎么知道他接收的文件是A发的原始文件?
A可以这样做,先对文件进行摘要处理(又称Hash,常见的哈希算法有MD5、SHA等)得到一串摘要信息,然后用自己的私钥将摘要信息加密同文件发给B,B收到加密串和文件后,再用A的公钥来解密加密串,得到原始文件的摘要信息,与此同时,对接收到的文件进行摘要处理,然后两个摘要信息进行对比,如果自己算出的摘要信息与收到的摘要信息一致,说明文件是A发过来的原始文件,没有被篡改。否则,就是被改过的。
数字签名有两个作用:
一是能确定消息确实是由发送方签名并发出来的;
二是数字签名能确定消息的完整性。
私钥用来创建一个数字签名,公钥用来让其他人核对私人密钥,
而数字签名做为一个媒介,证明你拥有密码,同时并不要求你将密码展示出来。
以下为概念的定义:
哈希(Hash):
二进制输入数据的一种数字指纹。
它是一种函数,通过它可以把任何数字或者字符串输入转化成一个固定长度的输出,它是单向输出,即非常难通过反向推导出输入值。
举一个简单的哈希函数的例子,比如数字17202的平方根是131.15639519291463,通过一个简单的哈希函数的输出,它给出这个计算结果的后面几位小数,如后几位的9291463,通过结果9291463我们几乎不可能推算出它是哪个输入值的输出。
现代加密哈希比如像SHA-256,比上面这个例子要复杂的多,相应它的安全性也更高,哈希用于指代这样一个函数的输出值。
私钥(Private key):
用来解锁对应(钱包)地址的一串字符,例如5J76sF8L5jTtzE96r66Sf8cka9y44wdpJjMwCxR3tzLh3ibVPxh+。
公钥(Public keycryptography):
加密系统是一种加密手段,它的每一个私钥都有一个相对应的公钥,从公钥我们不能推算出私钥,并且被用其中一个密钥加密了的数据,可以被另外一个相对应的密钥解密。这套系统使得你可以先公布一个公钥给所有人,然后所有人就可以发送加密后的信息给你,而不需要预先交换密钥。
数字签名(Digital signature):
Digital signature数字签名是这样一个东西,它可以被附着在一条消息后面,证明这条消息的发送者就是和某个公钥相对应的一个私钥的所有人,同时可以保证私钥的秘密性。某人在检查签名的时候,将会使用公钥来解密被加密了的哈希值(译者注:这个哈希值是数据通过哈希运算得到的),并检查结果是否和这条信息的哈希值相吻合。如果信息被改动过,或者私钥是错误的话,哈希值就不会匹配。在比特币网络以外的世界,签名常常用于验证信息发送者的身份 – 人们公布他们自己的公钥,然后发送可以被公钥所验证的,已经通过私钥加密过的信息。
加密算法(encryption algorithm):
是一个函数,它使用一个加密钥匙,把一条信息转化成一串不可阅读的看似随机的字符串,这个流程是不可逆的,除非是知道私钥匙的人来操作。加密使得私密数据通过公共的因特网传输的时候不需要冒严重的被第三方知道传输的内容的风险。
哈希算法的大致加密流程
1、对原文进行补充和分割处理(一般分给为多个512位的文本,并进一步分割为16个32位的整数)。
2、初始化哈希值(一般分割为多个32位整数,例如SHA256就是256位的哈希值分解成8个32位整数)。
3、对哈希值进行计算(依赖于不同算法进行不同轮数的计算,每个512位文本都要经过这些轮数的计算)。
区块链中每一个数据块中包含了一次网络交易的信息,产生相关联数据块所使用的就是非对称加密技术。非对密加密技术的作用是验证信息的有效性和生成下一个区块,区块链上网络交易的信息是公开透明的,但是用户的身份信息是被高度加密的,只有经过用户授权,区块链才能得到该身份信息,从而保证了数据的安生性和个人信息的隐私性。
公钥和私钥在非对称加密机制里是成对存在的,公钥和私钥可以去相互验证对方,那么在比特币的世界里面,我们可以把地址理解为公钥,可以把签名、输密码的过程理解为私钥的签名。
每个矿工在拿到一笔转账交易时候都可以验证公钥和私钥到底是不是匹配的,如果他们是匹配的,这笔交易就是合法的,这样每一个人只需要保管好TA自己的私钥,知道自己的比特币地址和对方的比特币地址就能够安全的将比特币进行转账,不需要一个中心化的机构来验证对方发的比特币是不是真的。