- 在智能合约中其实所有数据都是透明的
- 我这加密合约的作用其实是弥补以前旧合约中有敏感字段调用的时候需要加密不被发现破解
- 合约数据都是透明的(private也一样),但是还是可以阻挡90%的人,不懂技术和技术不深者
- 加密合约需要使用升级合约的目的是升级算法
这是流程图
合约代码
mint合约
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "./interface/IAxie.sol";
import "./interface/ICipherGenes.sol";
import "@openzeppelin442/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin442/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin442/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "./utils/VerifySignatUreupgradeable.sol";
contract Xxx is
Initializable,
AccessControlUpgradeable,
VerifySignatUreupgradeable
{
using AddressUpgradeable for address payable;
IAxie public _axieAddress;
ICipherGenes public _cipherGenesAddress;
// 价格
uint256 public _price;
mapping(bytes => uint256) public _signs;
event WakeupEvent(
bytes signature,
uint256 axieId,
uint256 new_horse_id,
uint256 price,
address owner
);
event ChangePrice(uint256 price);
bytes32 public constant CFO_ROLE = keccak256("CFO_ROLE");
bytes32 public constant OPER_ROLE = keccak256("OPER_ROLE");
function initialize() public initializer {
__AccessControl_init();
__VerifySignature_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(OPER_ROLE, msg.sender);
_changeSignaturer(msg.sender);
}
/**
* @dev 设置 axie合约
*/
function setCoreAddress(IAxie axieAddress)
public
onlyRole(DEFAULT_ADMIN_ROLE)
{
_axieAddress = axieAddress;
}
/**
* @dev 设置加密合约
*/
function setCipherGenesAddress(ICipherGenes cipherGenesAddress)
public
onlyRole(DEFAULT_ADMIN_ROLE)
{
_cipherGenesAddress = cipherGenesAddress;
}
/**
* @dev 设置当前价格
*/
function setPrice(uint256 value) public onlyRole(OPER_ROLE) {
_price = value;
emit ChangePrice(_price);
}
/**
* wiehdraw all amount
*/
function withdraw(address payable to) public onlyRole(CFO_ROLE) {
uint256 amount = address(this).balance;
to.sendValue(amount);
}
// 进行mint
function conduct(
uint256 rawAxieId,
uint256 genes,
uint256 expirationTime,
uint256 nonce,
bytes memory signature,
uint256 v,
uint256 len
) public payable returns (uint256) {
// 一系列判断代码我删了
// 先解密
uint256 decode_genes;
if (v == 1) {
decode_genes = _cipherGenesAddress.decryption(genes);
} else if (v == 2) {
decode_genes = _cipherGenesAddress.decryptionV2(genes, len);
} else if (v == 3) {
decode_genes = _cipherGenesAddress.decryptionV3(genes);
} else {
revert("version is not");
}
// 后验签
require(
verify(rawAxieId, decode_genes, expirationTime, nonce, signature),
"signature is not correct"
);
// 这里你去处理其他事情,调用主体合约mint也好,其他也好
return horse_id;
}
fallback() external payable {}
receive() external payable {}
}
非升级合约写法 CipherGenes.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "@openzeppelin442/contracts/access/AccessControl.sol";
import "../utils/CipherGenesVerifySignature.sol";
/**
* !call的from可以伪造
*/
contract CipherGenes is AccessControl, CipherGenesVerifySignature {
event updateKeyEvent();
event updateType(uint256 t);
uint256 private _key;
uint256 public _type;
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
_setKey();
setType(100001);
_changeSignaturer(msg.sender);
}
// 设置类型,防止_signature丢失可以重新生成一个新的
function setType(uint256 t) public onlyRole(ADMIN_ROLE) {
_type = t;
emit updateType(_type);
}
// 加严
function _stricter() private view returns (uint256) {
return _key % 1e6;
}
// 随机生成一个密码
function _setKey() private {
_key =
(uint256(
keccak256(abi.encodePacked(block.difficulty, block.timestamp))
) +
(uint256(keccak256(abi.encodePacked(block.timestamp))) % 1e10) +
_type +
(uint256(
keccak256(abi.encodePacked(block.difficulty, block.timestamp))
) % 1e8)) / 10000;
emit updateKeyEvent();
}
// 加密
function encryption(uint256 original) public view returns (uint256) {
//进行取反操作
uint256 stricter = _stricter();
uint256 sign = original ^ _key ^ stricter;
return (revertse(sign * 10 + 1) ^ stricter) + stricter;
}
uint256 private _num;
// 解密消耗gas,防止from伪造
function decryption(uint256 sign)
public
onlyRole(ADMIN_ROLE)
returns (uint256)
{
_num += 1;
//进行取反操作
uint256 stricter = _stricter();
uint256 sign2 = (revertse((sign - stricter) ^ stricter) - 1) / 10;
return sign2 ^ _key ^ stricter;
}
function revertse(uint256 x) internal pure returns(uint256)
{
uint256 result = 0;
while(x != 0){
result = result * 10 + x % 10;
x = x / 10;
}
return result;
}
// 验证签名获取秘钥,因为from地址可以伪造,但是签名有秘钥所以不可能伪造,签名、怕调用盲盒或者其他合约有签名数据然后套取key
function (uint256 _nonce, bytes memory _signature)
public
view
onlyRole(ADMIN_ROLE)
returns (uint256)
{
require(verify(_type, _nonce, _signature), "signature is not correct");
return _key;
}
// 更新密钥,不能加参数只能线上更新
function updateKey() public onlyRole(ADMIN_ROLE) {
_setKey();
}
}
升级合约写法 CipherGenesUpgradeable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "@openzeppelin442/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import "@openzeppelin442/contracts-upgradeable/proxy/utils/Initializable.sol";
import "../utils/upgradeable/CipherGenesVerifySignatureUpgradeable.sol";
import "../utils/Uint256s.sol";
/**
* !call的from可以伪造
*/
contract CipherGenesUpgradeable is
Initializable,
AccessControlUpgradeable,
CipherGenesVerifySignatureUpgradeable
{
event updateKeyEvent();
event updateType(uint256 indexed t);
using Uint256s for uint256;
uint256 private _key;
uint256 public _type;
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
function initialize() public initializer {
__AccessControl_init();
__VerifySignature_init();
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
_setKey();
setType(100001);
_changeSignaturer(msg.sender);
}
// 设置类型,防止_signature丢失可以重新生成一个新的
function setType(uint256 t) public onlyRole(ADMIN_ROLE) {
_type = t;
emit updateType(_type);
}
// 加严
function _stricter() private view returns (uint256) {
return _key % 1e6;
}
// 随机生成一个密码
function _setKey() private {
_key =
(uint256(
keccak256(abi.encodePacked(block.difficulty, block.timestamp))
) +
(uint256(keccak256(abi.encodePacked(block.timestamp))) % 1e10) +
_type +
(uint256(
keccak256(abi.encodePacked(block.difficulty, block.timestamp))
) % 1e8)) / 10;
emit updateKeyEvent();
}
// 加密
function encryption(uint256 original) public view returns (uint256) {
//进行取反操作
uint256 stricter = _stricter();
uint256 sign = original ^ _key ^ stricter;
return sign + stricter;
}
bool private a;
// 解密消耗gas,防止from伪造
function decryption(uint256 sign)
public
onlyRole(ADMIN_ROLE)
returns (uint256)
{
//进行取反操作
a = true;
uint256 stricter = _stricter();
uint256 sign2 = sign - stricter;
return sign2 ^ _key ^ stricter;
}
// 加密 v1版本秘钥太长,v2版本需要*10,uint256会溢出,所以秘钥 / 1000
// 基因太长,只反转6位~节省gas,计算整形长度消耗gas所以直接传值
function encryptionV2(uint256 original,uint256 len) public view returns (uint256) {
//进行取反操作
uint256 stricter = _stricter();
uint256 sign = original ^ (_key / 1000) ^ stricter;
return ((sign * 10 + 1).revertse1(len) ^ stricter) + stricter;
}
// 解密消耗gas,防止from伪造
// 基因太长,只反转6位~节省gas,计算整形长度消耗gas所以直接传值
function decryptionV2(uint256 sign, uint256 len)
public
onlyRole(ADMIN_ROLE)
returns (uint256)
{
a = true;
//进行取反操作
uint256 stricter = _stricter();
uint256 sign2 = (((sign - stricter) ^ stricter).revertse2(len) - 1) / 10;
return sign2 ^ (_key / 1000) ^ stricter;
}
// 加密v3
function encryptionV3(uint256 original) public view returns (uint256) {
//进行取反操作
uint256 stricter = _stricter();
uint256 sign = original ^ (_key / 100) ^ stricter;
uint256 iszero = 1;
if((sign % 10) == 0){
iszero = 10;
}
sign = sign.revertse() * iszero;
return (sign ^ getNewKey(sign,_key)) + stricter;
}
// 解密v3
function decryptionV3(uint256 sign)
public
onlyRole(ADMIN_ROLE)
returns (uint256)
{
a = true;
//进行取反操作
uint256 stricter = _stricter();
sign = sign - stricter;
uint256 iszero = 1;
sign = sign ^ getNewKey(sign,_key);
if((sign % 10) == 0){
iszero = 10;
}
sign = (sign).revertse();
sign = sign * iszero;
return sign ^ (_key / 100) ^ stricter;
}
function getNewKey(uint256 original,uint256 key) internal pure returns(uint256)
{
uint256 len = key.getLength() - original.getLength();
if(len > 0){
key /= 10 ** len;
}
return key;
}
// 验证签名获取秘钥,因为from地址可以伪造,但是签名有秘钥所以不可能伪造,签名、怕调用盲盒或者其他合约有签名数据然后套取key
function getKey(uint256 _nonce, bytes memory _signature)
public
view
onlyRole(ADMIN_ROLE)
returns (uint256)
{
require(verify(_type, _nonce, _signature), "signature is not correct");
return _key;
}
// 更新密钥,不能加参数只能线上更新
function updateKey() public onlyRole(ADMIN_ROLE) {
_setKey();
}
}
utils/CipherGenesVerifySignature.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.6;
import "@openzeppelin442/contracts/access/AccessControl.sol";
abstract contract CipherGenesVerifySignature is AccessControl {
address public signaturer;
function changeSignaturer(address value)
public
onlyRole(DEFAULT_ADMIN_ROLE)
{
_changeSignaturer(value);
}
function _changeSignaturer(address value) internal {
signaturer = value;
}
function getMessageHash(
address owner,
address contract_addr,
uint256 t,
uint256 _nonce
) public pure returns (bytes32) {
return keccak256(abi.encodePacked(owner, contract_addr, t, _nonce));
}
function getEthSignedMessageHash(bytes32 _messageHash)
public
pure
returns (bytes32)
{
return
keccak256(
abi.encodePacked(
"\x19Ethereum Signed Message:\n32",
_messageHash
)
);
}
function verify(
uint256 t,
uint256 _nonce,
bytes memory signature
) public view returns (bool) {
bytes32 messageHash = getMessageHash(
signaturer,
address(this),
t,
_nonce
);
bytes32 ethSignedMessageHash = getEthSignedMessageHash(messageHash);
return recoverSigner(ethSignedMessageHash, signature) == signaturer;
}
function recoverSigner(
bytes32 _ethSignedMessageHash,
bytes memory _signature
) public pure returns (address) {
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
return ecrecover(_ethSignedMessageHash, v, r, s);
}
function splitSignature(bytes memory sig)
public
pure
returns (
bytes32 r,
bytes32 s,
uint8 v
)
{
require(sig.length == 65, "invalid signature length");
assembly {
r := mload(add(sig, 32))
s := mload(add(sig, 64))
v := byte(0, mload(add(sig, 96)))
}
}
}
utils/Uint256s.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev String operations.
*/
library Uint256s {
/**
* @dev leng
*/
function getLength(uint256 x) internal pure returns (uint256) {
uint256 len = 0;
while(x != 0){
len++;
x = x / 10;
}
return len;
}
/**
* @dev leng
*/
function revertse(uint256 x) internal pure returns (uint256) {
uint256 result = 0;
while(x != 0){
result = result * 10 + x % 10;
x = x / 10;
}
return result;
}
// 84269 26813 53746 27964
function revertse1(uint256 x,uint256 len) internal pure returns(uint256)
{
uint256 remainder = 6;
uint256 digit = 10;
uint256 result = 0;
for(uint256 i = 0; i < remainder; i++){
result = result * digit + x % digit;
x = x / digit;
}
result = result * (10 ** (len - remainder)) + x;
return result;
}
function revertse2(uint256 x,uint256 len) internal pure returns(uint256)
{
uint256 remainder = 6;
uint256 digit = 10;
uint256 result = 0;
uint256 divisor = 10 ** (len - remainder);
uint256 x2 = x / divisor;
for(uint256 i = 0; i < 6; i++){
result = result * digit + x2 % digit;
x2 = x2 / digit;
}
x = x % divisor;
result = x * (10 ** remainder) + result;
return result;
}
}
服务端代码
签名api
#[Security("is_granted('ROLE_USER')")]
#[Route(path: "/api/signature", name: "signature", methods: ["GET"])]
public function signature(Request $request, ShuShuService $shushu): JsonResponse
{
$uid = $this->getUser()->getId();
$address = $this->getUser()->getAddress();
$token_id = $request->get('token_id');
if (!$token_id) {
return $this->json(['code' => 400, 'message' => 'Missing parameter token_id'], 400);
}
$game_em = $this->getDoctrine()->getManager('DerbyUserData');
$xxService = new XxContractService($game_em);
$lock = Lock::acquireLock("xx_start_" . $this->getUser()->getId(), 5);
if (!$lock) {
return $this->json(['code' => 400, 'message' => 'Operation too frequent!'], 400);
}
try {
$genes = "这是要加密的字段"
$genes = new BN($genes, 16);
$erc721 = Web3Service::getInstance()->getContract('xx');
$expirationTime = time() + WakeupService::WAKEUP_EXPIR_TIME;
$sign = $erc721->soliditySignature($horse_id, $genes, $expirationTime);
$genes_encrypt = CipherGenes::getInstance()->encryptionV2($genes->toString());
return $this->json([
'code' => 200,
'v' => 2,
'expirationTime' => $expirationTime,
'genes_encrypt' => $genes_encrypt,
'signature' => $sign['signature'],
'nonce' => $sign['nonce'],
'len' => strlen($genes_encrypt),
]);
} catch (\Exception $e) {
return $this->json(['code' => $e->getCode(), 'message' => $e->getMessage()], 400);
}
}
加密类 CipherGenes.php
<?php
namespace App\Support;
use App\Service\Web3Service;
use App\Support\BigInteger as SupportBigInteger;
use phpseclib\Math\BigInteger;
class CipherGenes
{
public static $cg_cache_key_key = "cipher_genes_key";
public static $cg_cache_type_key = 'cipher_genes_type';
private $redis = null;
public static function getInstance(): static
{
return new static();
}
public function __construct()
{
$this->redis = new \Predis\Client(
[
'scheme' => 'tcp',
'host' => $_ENV['REDIS_HOST'],
'port' => $_ENV['REDIS_PORT'],
],
[
'prefix' => 'market:' . $_ENV['BLOCKCHAIN'] . ':',
'parameters' => [
'password' => $_ENV['REDIS_PASS'],
'database' => 10,
]
]
);
}
public function getGenesType(): int
{
$type = $this->redis->get(self::$cg_cache_type_key);
return $type ?: $this->updateGenesType();
}
public function updateGenesType($type = false): int
{
$cipherGenes = Web3Service::getInstance()->getContract("CipherGenes");
$type = $type ?: Web3Service::decodeParameter('uint256', $cipherGenes->callMethod('_type'))->toString();
$this->redis->set(self::$cg_cache_type_key, $type);
return $type;
}
public function getGenesKey(): string
{
$key = $this->redis->get(self::$cg_cache_key_key);
return $key ?: $this->updateGenesKey();
}
public function updateGenesKey(): string
{
$type = $this->getGenesType();
$web3Service = Web3Service::getInstance()->getContract("CipherGenes");
list(
'nonce' => $nonce,
'signature' => $signature
) = $web3Service->typeSign($type);
$key = $web3Service->getKey($nonce, $signature);
$this->redis->set(self::$cg_cache_key_key, $key);
return $key;
}
public function encryption(string $genes): string
{
$genes = new BigInteger($genes);
$key = $this->getGenesKey();
$strict = $this->_stricter($key);
return $genes
->bitwise_xor(new BigInteger($key))
->bitwise_xor($strict)
->add($strict)
->toString();
}
public function encryptionV2(string $genes): string
{
$genes = new BigInteger($genes);
$key = $this->getGenesKey();
$strict = $this->_stricter($key);
$key = substr($key, 0, strlen($key) - 3);
$genes = $genes
->bitwise_xor(new BigInteger($key))
->bitwise_xor($strict)
->multiply(new BigInteger(10))
->add(new BigInteger(1))
->toString();
$str = strrev(substr($genes, -6));
$genes = new BigInteger($str . substr($genes,0,-6));
return $genes
->bitwise_xor($strict)
->add($strict)
->toString();
}
public function decryptionV2(string $sign): string
{
$genes = new BigInteger($sign);
$key = $this->getGenesKey();
$strict = $this->_stricter($key);
$key = substr($key, 0, strlen($key) - 3);
$genes = $genes
->subtract($strict)
->bitwise_xor($strict)
->toString();
$str = strrev(substr($genes,0, 6));
$genes = new BigInteger(substr($genes,6) . $str );
$arr = $genes->subtract(new BigInteger(1))->divide(new BigInteger(10));
return $arr[0]
->bitwise_xor(new BigInteger($key))
->bitwise_xor($strict)
->toString();
}
public function encryptionV3(string $genes): string
{
$key = $this->getGenesKey();
$genes = new BigInteger($genes);
$strict = $this->_stricter($key);
$genes = $genes
->bitwise_xor(new BigInteger(substr($key, 0, -2)))
->bitwise_xor($strict)
->toString();
$iszero = 1;
if (substr($genes, -1) == 0) {
$iszero = 10;
$genes = rtrim($genes, '0');
}
$genes = (new BigInteger(strrev($genes)))->multiply(new BigInteger($iszero));
$len = strlen($key) - strlen($genes->toString());
$newKey = $len ? substr($key, 0, strlen($genes->toString())) : $key;
return $genes
->bitwise_xor(new BigInteger($newKey))
->add($strict)
->toString();
}
public function decryptionV3(string $sign): string
{
$key = $this->getGenesKey();
$strict = $this->_stricter($key);
$genes = new BigInteger($sign);
$genes = $genes->subtract($strict);
$len = strlen($key) - strlen($genes->toString());
$newKey = $len ? substr($key, 0, strlen($genes->toString())) : $key;
$genes = $genes->bitwise_xor(new BigInteger($newKey));
$iszero = 1;
if (substr($genes->toString(), -1) == 0) {
$iszero = 10;
}
$genes = new BigInteger(strrev($genes));
return $genes
->multiply(new BigInteger($iszero))
->bitwise_xor(new BigInteger(substr($key, 0, -2)))
->bitwise_xor($strict)
->toString();
}
public function decryption(string $sign): string
{
$key = $this->getGenesKey();
$strict = $this->_stricter($key);
return (new BigInteger($sign))
->subtract($strict)
->bitwise_xor(new BigInteger($key))
->bitwise_xor($strict)
->toString();
}
private function _stricter($key): BigInteger
{
$bi = new SupportBigInteger($key);
$str = $bi->mod(1e6)->toString();
return new BigInteger($str);
}
}