// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;
//哈希签名的验证和逆向恢复(不同平台加密逻辑不同,这个只针对小狐狸平台
contract haxiyanzheng {
//首先,哈希签名的验证,分为四个步骤
//第一个步骤:将信息加密
//第二个步骤:将信息进行哈希
//第三个步骤:将哈希后的值和私钥进行再次签名哈希 为什么要两次哈希呢?因为一次可以破解了
//第四个步骤:将加密后的数据进行解密
//ecrecover(hash(哈希之后的源数据), v, r, s) == 源数据的地址
//ecrecover(hash(哈希之后的源数据), 私钥) == 源数据的地址
//1.先建一个验证函数,
function yanzheng(
address qianmingrendizhi,
string memory yuanxinxi,
bytes memory qianming
) external pure returns (bool){
//6.
bytes32 diyici \= diyicijiami(yuanxinxi);
bytes32 dierci \= diyicijiami2(diyici);
return jiemi(dierci, qianming) \== qianmingrendizhi;
}
//2.建一个步骤一的信息加密,先加密,后续再用验证函数去解密
//因为要调用所以要用public,并且加密后固定长度是32
function diyicijiami(string memory message) public pure returns (bytes32){
return keccak256(abi.encodePacked(message));
}
//3. 再次加密,把第一次加密的结果再次加密,因为一次加密已经可以被破解
//并且在加密的时候,可以添加一个口令类似其他语言中的盐
//特别注意,这一步,不是在合约中进行,而是链外进行签名
function diyicijiami2(bytes32 message2) public pure returns (bytes32){
return keccak256(abi.encodePacked("I am salt",message2));
}
//4.把签名分割为RSV,非对称性加密,不知道签名是多长,所以不定长声明,并且会返回三个rSV
//不需要公开,内部调用即可 小知识,return返回的变量名相同就可以隐式返回
function fenggeRSV(bytes memory qianmingde) internal pure returns (bytes32 r,bytes32 s ,uint8 v){
//首先,确认签名长度
//这里解释一下,为什么是65位长度,bytes32 就占32位,uint数字,只占一位,所以是32+32+1,我们是bytes,所以uint只是一字节
/* 数字范围:uint8 表示的是无符号整数,即只能表示非负数。其取值范围是从 0 到 255。
占几位:uint8 表示的数据占用 8 位,也就是 1 个字节(byte)。
具体到二进制表示,uint8 可以表示的范围是 00000000 到 11111111,对应的十进制值是 0 到 255。*/
require(qianmingde.length \== 65,"wu xiao de qian ming");
//开始分割
//这里使用的是内联汇编去分割,说的是分割,其实是solidity中的装配变量的内置函数
//签名的原理,实际上是r+s+v拼接而成,这里要注意最后一个uint,虽然bytes是1 但是还是要以32一隔,32一隔这样去装配
//byte(0,mload(add(qianmingde,96))) 因为uint8 只占一位,所以使用字节0来获取数,不然取到很多无效值
assembly{
r := mload(add(qianmingde,32))
s := mload(add(qianmingde,64))
v := byte(0,mload(add(qianmingde,96)))
}
}
//5.解密,接受二次加密的结果和签名,返回的是一个地址,这个地址不是合约地址,也不是调用者地址,而是返回的链外者参与签名的地址
function jiemi(bytes32 ercijiamihoude,bytes memory qianming)public pure returns (address){
//返回的是链外者参与签名的地址
//ecrecover(hash(哈希之后的源数据), v, r, s)
(bytes32 r,bytes32 s, uint8 v) \= fenggeRSV(qianming);
//这里注意,只能使用vrs顺序
return ecrecover(ercijiamihoude, v, r, s);
}
}