Skip to content

Commit

Permalink
The snark proof with separate public inputs file (#31)
Browse files Browse the repository at this point in the history
* new snark proof

* update host program

* fix the user_data zero in the public_inputs

---------

Co-authored-by: [gavin-ygy] <[[email protected]]>
  • Loading branch information
gavin-ygy and [gavin-ygy] authored Oct 29, 2024
1 parent db996f8 commit 63a2270
Show file tree
Hide file tree
Showing 13 changed files with 358 additions and 75 deletions.
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,10 @@ cd zkm-project-template/host-program
> 2. There are two script programs available: run_local_proving.sh and run_network_proving.sh. These scripts facilitate the
generation of proofs on the local machine and over the proof network, respectively.

> 3. There are three guest programs(sha2-rust, sha2-go, mem-alloc-vec), each capable of generating a SNARK proof on a machine
equipped with an AMD EPYC 7R13 processor and 250GB of memory. The following will use sha2-rust as an example to demonstrate local and network proofs.
> 3. There are four guest programs(sha2-rust, sha2-go, mem-alloc-vec,revme). The following will use sha2-rust and revme as an example to demonstrate local and network proofs.
> 4. If the environmental variable `PROOF_RESULTS_PATH` is not set, the proof results file will be saved in zkm-project-template/contracts/{src, verifier}; if the environmental variable `PROOF_RESULTS_PATH` is set, after the proof is completed, the proof results file needs to be copied from from 'PROOF_RESULTS_PATH'/{src, verifier} to the corresponding zkm-project-template/contracts/{src, verifier}.

> [!WARNING]
> The environmental variable `SEG_SIZE` in the run-xxx_proving.sh affects the final proof generation.
Expand All @@ -124,7 +126,7 @@ equipped with an AMD EPYC 7R13 processor and 250GB of memory. The following will
> When generating proofs on the local machine, if the log shows "!!!*******seg_num: 1", please reduce SEG_SIZE or increase the input. If generating proofs through the proof network, SEG_SIZE must be within the range [65536, 262144].
### Example : `sha2-rust`
### Example 1 : `sha2-rust`

This host program sends the private input pri_input = vec![5u8; 1024] and its hash (hash(pri_input)) to the guest program for verification of the hash value.

Expand Down Expand Up @@ -290,3 +292,29 @@ Sensitive values saved to: /mnt/data/zkm-project-template/contracts/cache/verifi
```

For more details, please refer to [this](contracts/README.md) guide.

### Example 2 : `revme`

The revme guest program takes a block data as input and its running is as same as the sha2-rust. Here, the focus is on explaining how to generate block data(the revme's input).

#### Generating the public input about a specific block

> [!NOTE]
> The local node connects ZKM test chain in the following example. You must use the Eth-Compatible local node.
```sh
cd ~
git clone https://github.com/zkMIPS/revme
cd revme
RPC_URL=http://localhost:8545 CHAIN_ID=1337 BLOCK_NO=244 RUST_LOG=debug SUITE_JSON_PATH=./test-vectors/244.json cargo run --example process
```

If successfully, it will generate `244.json` in the path test-vectors

```sh
cp test-vectors/244.json zkm-project-template/host-program/test-vectors/
```

Next, you need to edit the `JSON_PATH` variable in the [`run-local-proving.sh`](host-program/run-local-proving.sh) or [`run-network-proving.sh`](host-program/run-network-proving.sh) to match the name of the JSON file mentioned above.

Then, you can execute the run-xxx-proving.sh by following the steps outlined in `Example 1: sha2-rust`.
88 changes: 73 additions & 15 deletions contracts/src/verifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ library Pairing {
input[1] = p.Y;
input[2] = s;
bool success;

assembly {
success := staticcall(sub(gas(), 2000), 7, input, 0x80, r, 0x60)
// Use "invalid" to make gas estimation work
switch success case 0 { invalid() }
}

require (success);
}
/// @return the result of computing the pairing check
Expand All @@ -90,13 +90,13 @@ library Pairing {
}
uint[1] memory out;
bool success;

assembly {
success := staticcall(sub(gas(), 2000), 8, add(input, 0x20), mul(inputSize, 0x20), out, 0x20)
// Use "invalid" to make gas estimation work
// switch success case 0 { invalid() }
}

require(success,"no");
return out[0] != 0;
}
Expand Down Expand Up @@ -148,6 +148,10 @@ library Pairing {
}

contract Verifier {
uint256 constant MASK = ~(uint256(0x7) << 253);
uint256 constant EMPTY_HASH = 0x3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855;
uint256 constant CIRCUIT_DIGEST = 17524917735085582509473322861927874526127848298611193781519203348111540784568;

event VerifyEvent(address user);
event Value(uint x, uint y);

Expand All @@ -165,19 +169,19 @@ contract Verifier {
Pairing.G1Point c;
}
function verifyingKey() pure internal returns (VerifyingKey memory vk) {
vk.alpha = Pairing.G1Point(uint256(5238594224415803428903552163224573733888230552897477768815476746088817694665), uint256(16328026879972510425634956651757872870689877162649076255746551787054864220355));
vk.beta = Pairing.G2Point([uint256(20324176648632662611169376759002700320443304453272693285118269429660227814847), uint256(9549073425549497017615537849571476830587596656015613611017956266089308903531)], [uint256(9337569445850381137129018980746968145714905364224388186337838316616854951754), uint256(3513913997312605870476238882256631130522705321741945577205945205501138882378)]);
vk.gamma = Pairing.G2Point([uint256(15161880990256081123123373723003760974001614786036869673944011467642681350273), uint256(9163286039211553980285501179844267362965858818412298332978707992237561271164)], [uint256(8680437061849217529408110466997375226429075645841820069852588072607969726492), uint256(18800549715559362373103731617654666483740554675125608300590590295497678086269)]);
vk.delta = Pairing.G2Point([uint256(5084358276310810830336673597459062196788688825694978068951204319614533728072), uint256(2821074186679041829554082022899130273208453252341587777698126697055071930462)], [uint256(21456200227661305460882352714936824169326675407976258160476432406731382755331), uint256(7296447269627149028431860329913792045260832865974902439493666631626649609193)]);
vk.alpha = Pairing.G1Point(uint256(4982840985977509480812696446748055946734515908139415073223361588673361263746), uint256(8712150437299664934793155504800743464028309588231747319088718049163058504378));
vk.beta = Pairing.G2Point([uint256(14644847491060364109480040637526345932168168023485200270880573723303997401430), uint256(6775420302490570505302079782352798472495089461815319569111358423389688511258)], [uint256(14768767847587643701090831715662879751600874573066085500496772126134950836854), uint256(240437156120544871266428605167538236442109586608972230783814470863300438827)]);
vk.gamma = Pairing.G2Point([uint256(7262210795700233819627126529411641564304118216220826693309624003838669118557), uint256(17968365474447290552942753834244607172785018962023497431395501373062750769088)], [uint256(20236512178005743879072938503706731346788846934024160084859279719418824582905), uint256(21482178354445909306461993182701005930359221724872119005518668975905484364020)]);
vk.delta = Pairing.G2Point([uint256(1429989016433393031270355281347460626641102112248176356804534174800828327904), uint256(8658924682454037491287711579335854754277930237325482595536833570576568002546)], [uint256(6666320311792476308297678246169834119738677804991811576981285704354255423405), uint256(17225692118650814592746316412064011994785803400777901648568774307469594781516)]);
vk.gamma_abc = new Pairing.G1Point[](3);
vk.gamma_abc[0] = Pairing.G1Point(uint256(12714166869634051746888443609265681012145928347211427641836759112149836905420), uint256(11793561626188782503504016672377056451459939677293717125670005645761619823785));
vk.gamma_abc[1] = Pairing.G1Point(uint256(12843888235824976460769557467680522067504783112310502594161600686576288283623), uint256(21500613568509565203375400055914065701770933353363264002526901521910619984442));
vk.gamma_abc[2] = Pairing.G1Point(uint256(8046476541142506270894150739369274117716896582126953035714106843523496457093), uint256(11973219905447798721811213848944330597161079598635743680895679571487377395568));
vk.gamma_abc[0] = Pairing.G1Point(uint256(658688055398885923946239798304191006171364785528162641914664772011403932614), uint256(16627251529150893079116090723842709162209343897331682563491207763133727729949));
vk.gamma_abc[1] = Pairing.G1Point(uint256(17533717551801610611963983357502065482287525214778437011670149217505961606170), uint256(6945694641534038337990336721326850919360048910929658061971010569206119522556));
vk.gamma_abc[2] = Pairing.G1Point(uint256(13525035671734603893608933762469327796081853408677259439579741391855268192799), uint256(10191107221118371707862430176671506476078342119397430622030687829974682775664));

}
function verify(uint[2] memory input, Proof memory proof, uint[2] memory proof_commitment) public view returns (uint) {
uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;

VerifyingKey memory vk = verifyingKey();
require(input.length + 1 == vk.gamma_abc.length);
// Compute the linear combination vk_x
Expand All @@ -201,13 +205,67 @@ contract Verifier {

return 0;
}
function verifyTx(Proof memory proof, uint[2] memory input,uint[2] memory proof_commitment) public returns (bool r) {
function verifyTx(
Proof memory proof, uint[2] memory input
,uint[2] memory proof_commitment) public returns (bool r) {

if (verify(input, proof , proof_commitment) == 0) {
emit VerifyEvent(msg.sender);
return true;
} else {
return false;
}

}
}

function calculatePublicInput(
bytes memory _userData,
uint32[8] memory _memRootBefore,
uint32[8] memory _memRootAfter
) public pure returns (uint256) {
bytes32 userData = sha256(_userData);

uint256 memRootBefore = 0;
for (uint256 i = 0; i < 8; i++) {
memRootBefore |= uint256(_memRootBefore[i]) << (32 * (7 - i));
}
uint256 memRootAfter = 0;
for (uint256 i = 0; i < 8; i++) {
memRootAfter |= uint256(_memRootAfter[i]) << (32 * (7 - i));
}

bytes memory dataToHash = abi.encodePacked(
memRootBefore,
memRootAfter,
userData,
CIRCUIT_DIGEST,
getConstantSigmasCap()
);

uint256 hash_o = uint256(sha256(dataToHash)) & MASK;
uint256 hashValue = uint256(sha256(abi.encodePacked(EMPTY_HASH,hash_o))) & MASK;

return hashValue;
}

function getConstantSigmasCap() public pure returns (uint256[16] memory) {
return [
91383584712019272681377229182172954852761112840230485576576219640999915415908,
59255968443781732618398964440087269720283395714373383774650673994811543257891,
43522785206513529710314565972458653794534948943367780523535399673207256542667,
40342750684549940679043033475171365072773076053340772573915667403010979823501,
27317612392857105781687183282424868606341901129358521256675721204392832410439,
43307034001377032728710254791751651528006774034804994236242404941502133194788,
96847759610594182728575775013319360940143540443603110434763689062442262276056,
103816866397357498456560831382884881537689393646419658130688223819092141266482,
92927370392150370847456421756552282870716539874859278967093815334673659047245,
48196270063118112994752430351531600491056188761932189573202142214229711823214,
72300508929423173342535162393269108469073018007670992928238766269813213409236,
96435373004420944780577491829986863106913456501189307806899876787207854460461,
49751597273171012664300923220213149590083424576410050544981754459509775460226,
34852111753877916137017959036830401094053286275843684490553560491310958812859,
50803581021794237060724898598173476602507622641970514917690126680609140114800,
97509144034546411327314284027738859064756953812076402994654732676369028259664
];
}
}
42 changes: 42 additions & 0 deletions contracts/test/verifier.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct VerifierProof {
PairingG1Point C ;
}


contract VerifierTest is Test {
using stdJson for string;

Expand Down Expand Up @@ -119,4 +120,45 @@ contract VerifierTest is Test {

}

function test_ValidPublicInputs() public view {
string memory root = vm.projectRoot();
string memory path1 = string.concat(root, "/verifier/snark_proof_with_public_inputs.json");
string memory json1 = vm.readFile(path1);
bytes memory publicWitness = json1.parseRaw(".PublicWitness");
string[] memory pubwit = abi.decode(publicWitness, ( string[]));
uint256 [2] memory input;
for (uint256 i = 0; i < pubwit.length; i++ ){
input[i] = vm.parseUint(pubwit[i]); //--> uint256
}

string memory path = string.concat(root, "/verifier/public_inputs.json");
string memory json = vm.readFile(path);

bytes memory rootBefore = json.parseRaw(".roots_before.root");
uint32[] memory rootBe = abi.decode(rootBefore, ( uint32[]));
uint32[8] memory rootb;
for (uint256 i = 0; i < rootBe.length; i++ ){
rootb[i] = rootBe[i];
}

bytes memory rootAfter = json.parseRaw(".roots_after.root");
uint32[] memory rootAf = abi.decode(rootAfter, ( uint32[]));
uint32[8] memory roota;
for (uint256 i = 0; i < rootAf.length; i++ ){
roota[i] = rootAf[i];
}

bytes memory userdata = json.parseRaw(".userdata");
uint8[] memory dataU = abi.decode(userdata, ( uint8[]));
bytes memory data = new bytes(dataU.length);
for (uint256 i = 0; i < data.length; i++) {
data[i] = bytes1(dataU[i]);
}


uint256 returnNum = verifier.calculatePublicInput(data, rootb, roota);
assert(returnNum == input[0]);

}

}
Loading

0 comments on commit 63a2270

Please sign in to comment.