Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support new circuit #47

Merged
merged 10 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions contracts/Decoder2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
// SPDX-License-Identifier: GPL-3.0
/*
Copyright 2021 0KIMS association.

This file is generated with [snarkJS](https://github.com/iden3/snarkjs).

snarkJS is a free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

snarkJS is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License
along with snarkJS. If not, see <https://www.gnu.org/licenses/>.
*/

pragma solidity >=0.7.0 <0.9.0;

contract Decoder2 {
// Scalar field size
uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
// Base field size
uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583;

// Verification Key data
uint256 constant alphax = 7506542393861712633345351046961518695186434969159573929710445813801252250723;
uint256 constant alphay = 16226065335411284296170178517395602646321797300570911178122732619405801531786;
uint256 constant betax1 = 18085759018360810108311053436144684567975240874798592024271494525670832624248;
uint256 constant betax2 = 14634453066859375398229234242235662432488733031061395747558146261931733463655;
uint256 constant betay1 = 5381338245488965956306749233704530527583477992038243832593582681279872987470;
uint256 constant betay2 = 15883666510464263642223723115318135885418478949233288914773546058946554436604;
uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634;
uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781;
uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531;
uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;
uint256 constant deltax1 = 12835677679493139045269931295051448329793403398705026697877485711464362140790;
uint256 constant deltax2 = 10890565504224301114874433160320698556606628868096993643809081156365267213249;
uint256 constant deltay1 = 4820425325906337717692330783154620996810762479415825588979740850757518563223;
uint256 constant deltay2 = 20093054666161765761327580477678108845241889769892444974271179780900242692838;


uint256 constant IC0x = 21859776616790133348839467181671732914251000215306575824317360595804907051375;
uint256 constant IC0y = 5948124107564618515449715251945373028277412284372620284583980914047280102876;

uint256 constant IC1x = 13848051249459348550101312128361869793110757504010030356060227877295152672978;
uint256 constant IC1y = 2843352445303990663395193579234283885289630212446579533751111323024927786811;

uint256 constant IC2x = 4089481448092447005931769337085619771622618998086375322736520349285250803224;
uint256 constant IC2y = 14358925651341109136062088919672746519297238256782507687342327673962847669860;


// Memory data
uint16 constant pVk = 0;
uint16 constant pPairing = 128;

uint16 constant pLastMem = 896;

function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[2] calldata _pubSignals) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
}

// G1 function to multiply a G1 value(x,y) to value in an address
function g1_mulAccC(pR, x, y, s) {
let success
let mIn := mload(0x40)
mstore(mIn, x)
mstore(add(mIn, 32), y)
mstore(add(mIn, 64), s)

success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64)

if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}

mstore(add(mIn, 64), mload(pR))
mstore(add(mIn, 96), mload(add(pR, 32)))

success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64)

if iszero(success) {
mstore(0, 0)
return(0, 0x20)
}
}

function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk {
let _pPairing := add(pMem, pPairing)
let _pVk := add(pMem, pVk)

mstore(_pVk, IC0x)
mstore(add(_pVk, 32), IC0y)

// Compute the linear combination vk_x

g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0)))

g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32)))


// -A
mstore(_pPairing, calldataload(pA))
mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q))

// B
mstore(add(_pPairing, 64), calldataload(pB))
mstore(add(_pPairing, 96), calldataload(add(pB, 32)))
mstore(add(_pPairing, 128), calldataload(add(pB, 64)))
mstore(add(_pPairing, 160), calldataload(add(pB, 96)))

// alpha1
mstore(add(_pPairing, 192), alphax)
mstore(add(_pPairing, 224), alphay)

// beta2
mstore(add(_pPairing, 256), betax1)
mstore(add(_pPairing, 288), betax2)
mstore(add(_pPairing, 320), betay1)
mstore(add(_pPairing, 352), betay2)

// vk_x
mstore(add(_pPairing, 384), mload(add(pMem, pVk)))
mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32))))


// gamma2
mstore(add(_pPairing, 448), gammax1)
mstore(add(_pPairing, 480), gammax2)
mstore(add(_pPairing, 512), gammay1)
mstore(add(_pPairing, 544), gammay2)

// C
mstore(add(_pPairing, 576), calldataload(pC))
mstore(add(_pPairing, 608), calldataload(add(pC, 32)))

// delta2
mstore(add(_pPairing, 640), deltax1)
mstore(add(_pPairing, 672), deltax2)
mstore(add(_pPairing, 704), deltay1)
mstore(add(_pPairing, 736), deltay2)


let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20)

isOk := and(success, mload(_pPairing))
}

let pMem := mload(0x40)
mstore(0x40, add(pMem, pLastMem))

// Validate that all evaluations ∈ F

checkField(calldataload(add(_pubSignals, 0)))

checkField(calldataload(add(_pubSignals, 32)))

checkField(calldataload(add(_pubSignals, 64)))


// Validate all evaluations
let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem)

mstore(0, isValid)
return(0, 0x20)
}
}
}
54 changes: 48 additions & 6 deletions contracts/EthStorageContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -144,22 +144,64 @@ contract EthStorageContract is StorageContract, Decoder {
uint256 sampleIdxInKv,
address miner,
bytes32 encodedData,
bytes calldata proof
) public view virtual override returns (bool) {
uint256 mask,
bytes calldata inclusiveProof,
bytes calldata decodeProof
) public view virtual returns (bool) {
PhyAddr memory kvInfo = kvMap[idxMap[kvIdx]];
(Proof memory decodeProof, uint256 mask, bytes memory peInput) = abi.decode(proof, (Proof, uint256, bytes));

Proof memory proof = abi.decode(decodeProof, (Proof));
// BLOB decoding check
if (
!decodeSample(decodeProof, uint256(keccak256(abi.encode(kvInfo.hash, miner, kvIdx))), sampleIdxInKv, mask)
!decodeSample(proof, uint256(keccak256(abi.encode(kvInfo.hash, miner, kvIdx))), sampleIdxInKv, mask)
) {
return false;
}

// Inclusive proof of decodedData = mask ^ encodedData
return checkInclusive(kvInfo.hash, sampleIdxInKv, mask ^ uint256(encodedData), peInput);
return checkInclusive(kvInfo.hash, sampleIdxInKv, mask ^ uint256(encodedData), inclusiveProof);
}

function getSampleIdx(
uint256 rows,
uint256 startShardId,
bytes32 hash0
) public view returns (uint256, uint256) {
uint256 parent = uint256(hash0) % rows;
uint256 sampleIdx = parent + (startShardId << (shardEntryBits + sampleLenBits));
uint256 kvIdx = sampleIdx >> sampleLenBits;
uint256 sampleIdxInKv = sampleIdx % (1 << sampleLenBits);
return (kvIdx, sampleIdxInKv);
}

function verifySamples(
uint256 startShardId,
bytes32 hash0,
address miner,
bytes32[] memory encodedSamples,
uint256[] memory masks,
bytes[] calldata inclusiveProofs,
bytes[] calldata decodeProof
) public view virtual override returns (bytes32) {
require(encodedSamples.length == randomChecks, "data length mismatch");
require(masks.length == randomChecks, "masks length mismatch");
require(inclusiveProofs.length == randomChecks, "proof length mismatch");
require(decodeProof.length == randomChecks, "decodeProof length mismatch");

// calculate the number of samples range of the sample check
uint256 rows = 1 << (shardEntryBits + sampleLenBits);

for (uint256 i = 0; i < randomChecks; i++) {
(uint256 kvIdx, uint256 sampleIdxInKv) = getSampleIdx(rows, startShardId, hash0);

require(
decodeAndCheckInclusive(kvIdx, sampleIdxInKv, miner, encodedSamples[i], masks[i], inclusiveProofs[i], decodeProof[i]),
"invalid samples"
);
hash0 = keccak256(abi.encode(hash0, encodedSamples[i]));
}
return hash0;
}

// Write a large value to KV store. If the KV pair exists, overrides it. Otherwise, will append the KV to the KV array.
function putBlob(bytes32 key, uint256 blobIdx, uint256 length) public payable virtual {
bytes32 dataHash = BlobHashGetter.getBlobHash(hashGetter, blobIdx);
Expand Down
60 changes: 60 additions & 0 deletions contracts/EthStorageContract2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./EthStorageContract.sol";
import "./Decoder2.sol";


contract EthStorageContract2 is EthStorageContract, Decoder2 {

constructor(
Config memory _config,
uint256 _startTime,
uint256 _storageCost,
uint256 _dcfFactor,
uint256 _nonceLimit,
address _treasury,
uint256 _prepaidAmount
) EthStorageContract(_config, _startTime, _storageCost, _dcfFactor, _nonceLimit, _treasury, _prepaidAmount) {}

function decodeSample(
uint256[] memory masks,
bytes calldata decodeProof
) public view returns (bool) {
(uint[2] memory pA, uint[2][2] memory pB, uint[2] memory pC) = abi.decode(decodeProof, (uint[2], uint[2][2], uint[2]));
// verifyProof uses the opcode 'return', so if we call verifyProof directly, it will lead to a compiler warning about 'unreachable code'
// and causes the caller function return directly
return this.verifyProof(pA, pB, pC, [masks[0], masks[1]]);
}

function verifySamples(
uint256 startShardId,
bytes32 hash0,
address miner,
bytes32[] memory encodedSamples,
uint256[] memory masks,
bytes[] calldata inclusiveProofs,
bytes[] calldata decodeProof
) public view virtual override returns (bytes32) {
require(encodedSamples.length == randomChecks, "data length mismatch");
require(masks.length == randomChecks, "masks length mismatch");
require(inclusiveProofs.length == randomChecks, "proof length mismatch");
require(decodeProof.length == 1, "decodeProof length mismatch");
// calculate the number of samples range of the sample check
uint256 rows = 1 << (shardEntryBits + sampleLenBits);

for (uint256 i = 0; i < randomChecks; i++) {
(uint256 kvIdx, uint256 sampleIdxInKv) = getSampleIdx(rows, startShardId, hash0);
PhyAddr memory kvInfo = kvMap[idxMap[kvIdx]];

require(
checkInclusive(kvInfo.hash, sampleIdxInKv, masks[i] ^ uint256(encodedSamples[i]), inclusiveProofs[i]),
"invalid samples"
);
hash0 = keccak256(abi.encode(hash0, encodedSamples[i]));
}

require(decodeSample(masks, decodeProof[0]), "decode failed");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is wrong somewhere

  • miner is not used in the decoding and proving (as part of the encodingKey).

return hash0;
}
}
51 changes: 13 additions & 38 deletions contracts/StorageContract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,50 +112,21 @@ abstract contract StorageContract is DecentralizedKV {
return _prepareAppendWithTimestamp(block.timestamp);
}

/*
* Decode the sample and check the decoded sample is included in the BLOB corresponding to on-chain datahashes.
*/
function decodeAndCheckInclusive(
uint256 kvIdx,
uint256 sampleIdx,
address miner,
bytes32 encodedSamples,
bytes calldata inclusiveProof
) public view virtual returns (bool);

/*
* Verify the samples of the BLOBs by the miner (storage provider) including
* - decode the samples
* - check the inclusive of the samples
* - calculate the final hash using
*/
function _verifySamples(
function verifySamples(
uint256 startShardId,
bytes32 hash0,
address miner,
bytes32[] memory encodedSamples,
bytes[] calldata inclusiveProofs
) internal view returns (bytes32) {
require(encodedSamples.length == randomChecks, "data length mismatch");
require(inclusiveProofs.length == randomChecks, "proof length mismatch");
// calculate the number of samples range of the sample check
uint256 rows = 1 << (shardEntryBits + sampleLenBits);

for (uint256 i = 0; i < randomChecks; i++) {
uint256 parent = uint256(hash0) % rows;
uint256 sampleIdx = parent + (startShardId << (shardEntryBits + sampleLenBits));
uint256 kvIdx = sampleIdx >> sampleLenBits;
uint256 sampleIdxInKv = sampleIdx % (1 << sampleLenBits);

require(
decodeAndCheckInclusive(kvIdx, sampleIdxInKv, miner, encodedSamples[i], inclusiveProofs[i]),
"invalid samples"
);

hash0 = keccak256(abi.encode(hash0, encodedSamples[i]));
}
return hash0;
}
uint256[] memory masks,
bytes[] calldata inclusiveProofs,
bytes[] calldata decodeProof
) public view virtual returns (bytes32);

// Obtain the difficulty of the shard
function _calculateDiffAndInitHashSingleShard(
Expand Down Expand Up @@ -208,7 +179,9 @@ abstract contract StorageContract is DecentralizedKV {
address miner,
uint256 nonce,
bytes32[] memory encodedSamples,
bytes[] calldata proofs
uint256[] memory masks,
bytes[] calldata inclusiveProofs,
bytes[] calldata decodeProof
) internal {
// Obtain the blockhash of the block number of recent blocks
require(block.number - blockNumber <= 64, "block number too old");
Expand All @@ -222,7 +195,7 @@ abstract contract StorageContract is DecentralizedKV {

// Check if the data matches the hash in metadata and obtain the solution hash.
bytes32 hash0 = keccak256(abi.encode(miner, bh, nonce));
hash0 = _verifySamples(shardId, hash0, miner, encodedSamples, proofs);
hash0 = verifySamples(shardId, hash0, miner, encodedSamples, masks, inclusiveProofs, decodeProof);

// Check difficulty
uint256 diff = _calculateDiffAndInitHashSingleShard(shardId, mineTs);
Expand All @@ -238,8 +211,10 @@ abstract contract StorageContract is DecentralizedKV {
address miner,
uint256 nonce,
bytes32[] memory encodedSamples,
bytes[] calldata proofs
uint256[] memory masks,
bytes[] calldata inclusiveProofs,
bytes[] calldata decodeProof
) public virtual {
return _mine(blockNumber, shardId, miner, nonce, encodedSamples, proofs);
return _mine(blockNumber, shardId, miner, nonce, encodedSamples, masks, inclusiveProofs, decodeProof);
}
}
Loading