Skip to content

Commit cac2d1b

Browse files
committed
Seperate public data proof to standalone library contract
1 parent 1c2f254 commit cac2d1b

File tree

3 files changed

+132
-112
lines changed

3 files changed

+132
-112
lines changed

contracts/PublicDataProof.sol

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
library PublicDataProof {
5+
enum HashType {
6+
SHA256,
7+
RESERVED,
8+
KECCAK256,
9+
RESERVED_1
10+
}
11+
12+
function calcDataProof(bytes32 dataMixedHash, bytes32 nonce, uint32 index, bytes16[] calldata m_path, bytes calldata leafdata, bytes32 noise) public pure returns(bytes32,bytes32) {
13+
//先验证index落在MixedHash包含的长度范围内
14+
require(index < (lengthFromMixedHash(dataMixedHash) >> 10) + 1, "invalid index");
15+
16+
//验证leaf_data+index+path 和 dataMixedHash是匹配的,不匹配就revert
17+
18+
HashType hashType = hashTypeFromMixedHash(dataMixedHash);
19+
20+
bytes32 dataHash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType,leafdata));
21+
//验证leaf_data+index+path 和 dataMixedHash是匹配的,不匹配就revert
22+
// 只比较后192位
23+
require(dataHash & bytes32(uint256((1 << 192) - 1)) == dataMixedHash & bytes32(uint256((1 << 192) - 1)), "mixhash mismatch");
24+
25+
// 不需要计算插入位置,只是简单的在Leaf的数据后部和头部插入,也足够满足我们的设计目的了?
26+
bytes32 new_root_hash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType, bytes.concat(leafdata, nonce)));
27+
bytes32 pow_hash = bytes32(0);
28+
29+
if(noise != 0) {
30+
//Enable PoW
31+
pow_hash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType, bytes.concat(noise, leafdata, nonce)));
32+
}
33+
34+
return (new_root_hash, pow_hash);
35+
}
36+
37+
function lengthFromMixedHash(bytes32 dataMixedHash) public pure returns (uint64) {
38+
return uint64(uint256(dataMixedHash) >> 192 & ((1 << 62) - 1));
39+
}
40+
41+
// hash的头2bits表示hash算法,00 = sha256, 10 = keccak256
42+
function hashTypeFromMixedHash(bytes32 dataMixedHash) public pure returns (HashType) {
43+
return HashType(uint8(uint256(dataMixedHash) >> 254));
44+
}
45+
46+
function _merkleRoot(HashType hashType,bytes16[] calldata proof, uint32 leaf_index,bytes16 leaf_hash) internal pure returns (bytes32) {
47+
if (hashType == HashType.SHA256) {
48+
// sha256
49+
return _merkleRootWithSha256(proof, leaf_index, leaf_hash);
50+
} else if (hashType == HashType.KECCAK256) {
51+
// keccak256
52+
return _merkleRootWithKeccak256(proof, leaf_index, leaf_hash);
53+
} else {
54+
revert("invalid hash type");
55+
}
56+
}
57+
58+
function _hashLeaf(HashType hashType,bytes memory leafdata) internal pure returns (bytes16) {
59+
if (hashType == HashType.SHA256) {
60+
// sha256
61+
return _bytes32To16(sha256(leafdata));
62+
} else if (hashType == HashType.KECCAK256) {
63+
// keccak256
64+
return _bytes32To16(keccak256(leafdata));
65+
} else {
66+
revert("invalid hash type");
67+
}
68+
}
69+
70+
// from openzeppelin`s MerkleProof.sol
71+
function _efficientKeccak256(bytes16 a, bytes16 b) private pure returns (bytes32 value) {
72+
/// @solidity memory-safe-assembly
73+
assembly {
74+
mstore(0x00, a)
75+
mstore(0x10, b)
76+
value := keccak256(0x00, 0x20)
77+
}
78+
}
79+
80+
function _bytes32To16(bytes32 b) private pure returns (bytes16) {
81+
return bytes16(uint128(uint256(b)));
82+
}
83+
84+
function _merkleRootWithKeccak256(bytes16[] calldata proof, uint32 leaf_index,bytes16 leaf_hash) internal pure returns (bytes32) {
85+
bytes16 currentHash = leaf_hash;
86+
bytes32 computedHash = bytes32(0);
87+
for (uint32 i = 0; i < proof.length; i++) {
88+
if (proof[i] != bytes32(0)) {
89+
if (leaf_index % 2 == 0) {
90+
computedHash = _efficientKeccak256(currentHash, proof[i]);
91+
} else {
92+
computedHash = _efficientKeccak256(proof[i], currentHash);
93+
}
94+
}
95+
currentHash = _bytes32To16(computedHash);
96+
97+
//require(leaf_index >= 2, "invalid leaf_index");
98+
leaf_index = leaf_index / 2;
99+
}
100+
101+
return computedHash;
102+
}
103+
104+
// sha256要比keccak256贵,因为它不是一个EVM内置操作码,而是一个预置的内部合约调用
105+
// 当hash 1kb数据时,sha256要贵160,当hash 两个bytes32时,sha256要贵400
106+
function _merkleRootWithSha256(bytes16[] calldata proof, uint32 leaf_index, bytes16 leaf_hash) internal pure returns (bytes32) {
107+
bytes16 currentHash = leaf_hash;
108+
bytes32 computedHash = 0;
109+
for (uint32 i = 0; i < proof.length; i++) {
110+
if (leaf_index % 2 == 0) {
111+
computedHash = sha256(bytes.concat(currentHash, proof[i]));
112+
} else {
113+
computedHash = sha256(bytes.concat(proof[i], currentHash));
114+
}
115+
currentHash = _bytes32To16(computedHash);
116+
//require(leaf_index >= 2, "invalid leaf_index");
117+
leaf_index = leaf_index / 2;
118+
}
119+
120+
return computedHash;
121+
}
122+
}

contracts/public_data_storage.sol

Lines changed: 7 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
pragma solidity ^0.8.0;
33
import "./gwt.sol";
44
import "./sortedlist.sol";
5-
import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
5+
import "./PublicDataProof.sol";
66

77
import "hardhat/console.sol";
88

@@ -125,10 +125,6 @@ contract PublicDataStorage {
125125
}
126126
}
127127

128-
function lengthFromMixedHash(bytes32 dataMixedHash) public pure returns (uint64) {
129-
return uint64(uint256(dataMixedHash) >> 192 & ((1 << 62) - 1));
130-
}
131-
132128
function _verifyBlockNumber(bytes32 dataMixedHash, uint256 blockNumber) internal pure returns(bool) {
133129
// (blockNumber xor dataMixedHash) % 64 == 0
134130
return uint256(bytes32(blockNumber) ^ dataMixedHash) % 64 == 0;
@@ -184,7 +180,7 @@ contract PublicDataStorage {
184180
require(publicDataInfo.maxDeposit == 0, "public data already exists");
185181

186182
// get data size from data hash
187-
uint64 dataSize = lengthFromMixedHash(dataMixedHash);
183+
uint64 dataSize = PublicDataProof.lengthFromMixedHash(dataMixedHash);
188184
// 区分质押率和最小时长。最小时长是系统参数,质押率depositRatio是用户参数
189185
// 质押率影响用户SHOW数据所需要冻结的质押
190186
// minAmount = 数据大小*最小时长*质押率,
@@ -281,7 +277,7 @@ contract PublicDataStorage {
281277
}
282278

283279
function _getLockAmount(bytes32 dataMixedHash) internal view returns(uint256) {
284-
uint64 dataSize = lengthFromMixedHash(dataMixedHash);
280+
uint64 dataSize = PublicDataProof.lengthFromMixedHash(dataMixedHash);
285281
return _dataSizeToGWT(dataSize) * sysMinDepositRatio * sysMinLockWeeks;
286282
}
287283

@@ -299,112 +295,13 @@ contract PublicDataStorage {
299295
emit SupplierBalanceChanged(supplierAddress, supplierInfo.avalibleBalance, supplierInfo.lockedBalance);
300296
}
301297

302-
function _verifyDataProof(bytes32 dataMixedHash,uint256 nonce_block_high, uint32 index, bytes16[] calldata m_path, bytes calldata leafdata, bytes32 noise) private view returns(bytes32,bytes32) {
298+
function _verifyDataProof(bytes32 dataMixedHash,uint256 nonce_block_high, uint32 index, bytes16[] calldata m_path, bytes calldata leafdata) private view returns(bytes32,bytes32) {
303299
require(nonce_block_high < block.number, "invalid nonce_block_high");
304300
require(block.number - nonce_block_high < 256, "nonce block too old");
305301

306302
bytes32 nonce = blockhash(nonce_block_high);
307303

308-
//先验证index落在MixedHash包含的长度范围内
309-
require(index < (lengthFromMixedHash(dataMixedHash) >> 10) + 1, "invalid index");
310-
311-
//验证leaf_data+index+path 和 dataMixedHash是匹配的,不匹配就revert
312-
// hash的头2bits表示hash算法,00 = sha256, 10 = keccak256
313-
uint8 hashType = uint8(uint256(dataMixedHash) >> 254);
314-
315-
bytes32 dataHash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType,leafdata));
316-
//验证leaf_data+index+path 和 dataMixedHash是匹配的,不匹配就revert
317-
// 只比较后192位
318-
require(dataHash & bytes32(uint256((1 << 192) - 1)) == dataMixedHash & bytes32(uint256((1 << 192) - 1)), "mixhash mismatch");
319-
320-
// 不需要计算插入位置,只是简单的在Leaf的数据后部和头部插入,也足够满足我们的设计目的了?
321-
bytes memory new_leafdata = bytes.concat(leafdata, nonce);
322-
bytes32 new_root_hash = _merkleRoot(hashType,m_path,index, _hashLeaf(hashType,new_leafdata));
323-
bytes32 pow_hash = bytes32(0);
324-
325-
if(noise != 0) {
326-
//Enable PoW
327-
pow_hash = _hashLeaf(hashType, bytes.concat(noise, leafdata, nonce));
328-
}
329-
330-
return (new_root_hash, pow_hash);
331-
}
332-
333-
function _merkleRoot(uint8 hashType,bytes16[] calldata proof, uint32 leaf_index,bytes16 leaf_hash) internal pure returns (bytes32) {
334-
if (hashType == 0) {
335-
// sha256
336-
return _merkleRootWithSha256(proof, leaf_index, leaf_hash);
337-
} else if (hashType == 2) {
338-
// keccak256
339-
return _merkleRootWithKeccak256(proof, leaf_index, leaf_hash);
340-
} else {
341-
revert("invalid hash type");
342-
}
343-
}
344-
345-
function _hashLeaf(uint8 hashType,bytes memory leafdata) internal pure returns (bytes16) {
346-
if (hashType == 0) {
347-
// sha256
348-
return _bytes32To16(sha256(leafdata));
349-
} else if (hashType == 2) {
350-
// keccak256
351-
return _bytes32To16(keccak256(leafdata));
352-
} else {
353-
revert("invalid hash type");
354-
}
355-
}
356-
357-
// from openzeppelin`s MerkleProof.sol
358-
function _efficientKeccak256(bytes16 a, bytes16 b) private pure returns (bytes32 value) {
359-
/// @solidity memory-safe-assembly
360-
assembly {
361-
mstore(0x00, a)
362-
mstore(0x10, b)
363-
value := keccak256(0x00, 0x20)
364-
}
365-
}
366-
367-
function _bytes32To16(bytes32 b) private pure returns (bytes16) {
368-
return bytes16(uint128(uint256(b)));
369-
}
370-
371-
function _merkleRootWithKeccak256(bytes16[] calldata proof, uint32 leaf_index,bytes16 leaf_hash) internal pure returns (bytes32) {
372-
bytes16 currentHash = leaf_hash;
373-
bytes32 computedHash = bytes32(0);
374-
for (uint32 i = 0; i < proof.length; i++) {
375-
if (proof[i] != bytes32(0)) {
376-
if (leaf_index % 2 == 0) {
377-
computedHash = _efficientKeccak256(currentHash, proof[i]);
378-
} else {
379-
computedHash = _efficientKeccak256(proof[i], currentHash);
380-
}
381-
}
382-
currentHash = _bytes32To16(computedHash);
383-
384-
//require(leaf_index >= 2, "invalid leaf_index");
385-
leaf_index = leaf_index / 2;
386-
}
387-
388-
return computedHash;
389-
}
390-
391-
// sha256要比keccak256贵,因为它不是一个EVM内置操作码,而是一个预置的内部合约调用
392-
// 当hash 1kb数据时,sha256要贵160,当hash 两个bytes32时,sha256要贵400
393-
function _merkleRootWithSha256(bytes16[] calldata proof, uint32 leaf_index, bytes16 leaf_hash) internal pure returns (bytes32) {
394-
bytes16 currentHash = leaf_hash;
395-
bytes32 computedHash = 0;
396-
for (uint32 i = 0; i < proof.length; i++) {
397-
if (leaf_index % 2 == 0) {
398-
computedHash = sha256(bytes.concat(currentHash, proof[i]));
399-
} else {
400-
computedHash = sha256(bytes.concat(proof[i], currentHash));
401-
}
402-
currentHash = _bytes32To16(computedHash);
403-
//require(leaf_index >= 2, "invalid leaf_index");
404-
leaf_index = leaf_index / 2;
405-
}
406-
407-
return computedHash;
304+
return PublicDataProof.calcDataProof(dataMixedHash, nonce, index, m_path, leafdata, bytes32(0));
408305
}
409306

410307
function showData(bytes32 dataMixedHash, uint256 nonce_block, uint32 index, bytes16[] calldata m_path, bytes calldata leafdata) public {
@@ -444,7 +341,7 @@ contract PublicDataStorage {
444341

445342
// 如果不是新的show,判定为对上一个show的挑战,要检查nonce_block_high是否一致
446343
require(is_new_show || publicDataInfo.nonce_block_high == nonce_block, "nonce_block_high not match");
447-
(bytes32 root_hash,) = _verifyDataProof(dataMixedHash,nonce_block,index,m_path,leafdata,bytes32(0));
344+
(bytes32 root_hash,) = _verifyDataProof(dataMixedHash,nonce_block,index,m_path,leafdata);
448345

449346
if(is_new_show) {
450347
publicDataInfo.nonce_block_high = nonce_block;
@@ -478,7 +375,7 @@ contract PublicDataStorage {
478375
CycleInfo storage cycleInfo = cycle_infos[_cycleNumber()];
479376
CycleDataInfo storage dataInfo = cycleInfo.data_infos[dataMixedHash];
480377
if (is_new_show) {
481-
dataInfo.score += lengthFromMixedHash(dataMixedHash);
378+
dataInfo.score += PublicDataProof.lengthFromMixedHash(dataMixedHash);
482379

483380
// insert supplier into last_showers
484381
if (dataInfo.shower_index >= 5) {
@@ -577,7 +474,6 @@ contract PublicDataStorage {
577474
// 设置已取标志
578475
dataInfo.withdraw_status |= withdrawUser;
579476

580-
581477
emit WithdrawAward(dataMixedHash, msg.sender, reward);
582478
}
583479
}

test/test_public_data.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ describe("PublicDataStorage", function () {
1717

1818
async function deployContracts() {
1919
let listLibrary = await (await hre.ethers.getContractFactory("SortedScoreList")).deploy();
20+
let proofLibrary = await (await hre.ethers.getContractFactory("PublicDataProof")).deploy();
2021

2122
dmcToken = await (await ethers.deployContract("DMCToken", [ethers.parseEther("10000000")])).waitForDeployment()
2223
gwtToken = await (await ethers.deployContract("GWTToken", [await dmcToken.getAddress()])).waitForDeployment()
2324

2425
// nftContract = await (await hre.ethers.deployContract("FakeNFTContract")).waitForDeployment();
2526
contract = await (await hre.ethers.deployContract("PublicDataStorage", [await gwtToken.getAddress()], {libraries: {
26-
SortedScoreList: await listLibrary.getAddress()
27+
SortedScoreList: await listLibrary.getAddress(),
28+
PublicDataProof: await proofLibrary.getAddress()
2729
}})).waitForDeployment();
2830

2931
await (await gwtToken.enableTransfer([await contract.getAddress()])).wait();

0 commit comments

Comments
 (0)