diff --git a/beacon-light-client/circom/scripts/validator_balances/test.ts b/beacon-light-client/circom/scripts/validator_balances/test.ts index dced09be5..a75502827 100644 --- a/beacon-light-client/circom/scripts/validator_balances/test.ts +++ b/beacon-light-client/circom/scripts/validator_balances/test.ts @@ -12,7 +12,7 @@ import { verifyMerkleProof } from '../../../../libs/typescript/ts-utils/ssz-util ); const beaconStateSZZ = await fetch( - `http://unstable.prater.beacon-api.nimbus.team/eth/v2/debug/beacon/states/5794336`, + `http://testing.mainnet.beacon-api.nimbus.team/eth/v2/debug/beacon/states/6616005`, { headers: { Accept: 'application/octet-stream', @@ -24,8 +24,19 @@ import { verifyMerkleProof } from '../../../../libs/typescript/ts-utils/ssz-util const beaconState = ssz.capella.BeaconState.deserialize(beaconStateSZZ); - console.log(beaconState.balances.length); - console.log(beaconState.validators.length); + console.log( + BigInt( + '0x' + + bytesToHex( + ssz.phase0.Validator.hashTreeRoot(beaconState.validators[0]), + ), + ) + .toString(2) + .padStart(256, '0') + .split('') + .map(x => `"${x.toString()}"`) + .join(','), + ); // const beaconStateView = ssz.capella.BeaconState.toViewDU(beaconState); // const beaconStateTree = new Tree(beaconStateView.node); diff --git a/beacon-light-client/plonky2/Commitment_Mapper.md b/beacon-light-client/plonky2/Commitment_Mapper.md new file mode 100644 index 000000000..50626d6c7 --- /dev/null +++ b/beacon-light-client/plonky2/Commitment_Mapper.md @@ -0,0 +1,17 @@ +# Optimizing ZK Proofs for Validator Balances + +## Objective + +Our goal is to confirm the total of a certain collection of validator balances on-chain, aiming to diminish the amount of required on-chain Merkle proofs. Our current strategy utilizes one zk-proof validation on-chain to ensure that a specific validator set exhibits a certain balance total for a designated beacon state root. + +The primary obstacle encountered is the lack of zk-friendliness in the SHA-256 hash function, which is presently employed in our Merkle proofs. The performance deficiency due to the significant computational burden of the SHA-256 makes it unsuitable for our requirements. To illustrate, a single Merkle proof for a validator demands about 43 hashes, whereas the balance tree calls for 39 hashes. + +## Suggested Approach + +### Handling Validators + +We propose to create a commitment mapping from the validators' root (a SHA-256 Merkle tree comprising all validators) to a Poseidon root of validators. This process would involve generating a proof that a given SHA-256 Merkle tree of validators matches a corresponding Poseidon Merkle tree of validators. Given the sheer number of validators, this tree will be formed using recursive proofs. Since only a small fraction of validators changes per epoch, we can economically update and reuse the proofs. The Poseidon hash function, being more zk-friendly, could then be used to validate that a specific validator belongs to the tree in a more cost-effective manner. + +### Dealing with Balances + +The complexity with balances lies in their tendency to alter with each epoch. Consequently, adopting a similar approach as the one for validators would not be feasible. This is due to the need for recalculating the proofs for all balances from the ground up for each epoch. diff --git a/beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts b/beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts new file mode 100644 index 000000000..15f922588 --- /dev/null +++ b/beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts @@ -0,0 +1,86 @@ +import { writeFileSync, readFileSync, existsSync } from 'fs'; +import { sleep } from '../../../libs/typescript/ts-utils/common-utils'; + +(async () => { + const { ssz } = await import('@lodestar/types'); + + let prevSlot = 0; + + while (true) { + const beaconStateSZZ = await fetch( + `https://floral-chaotic-sea.discover.quiknode.pro/c1133f4fcc19bbe54fa6e4caf0c05ac79ec7d300/eth/v2/debug/beacon/states/head`, + { + headers: { + Accept: 'application/octet-stream', + }, + }, + ) + .then(response => response.arrayBuffer()) + .then(buffer => new Uint8Array(buffer)); + + const beaconState = ssz.capella.BeaconState.deserialize(beaconStateSZZ); + + if (!existsSync('prev_beacon_state.ssz')) { + console.log('prev_beacon_state.ssz does not exist. Creating it.'); + + prevSlot = beaconState.slot; + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + await sleep(12000); + continue; + } + + console.log(beaconState.slot); + + if (prevSlot >= beaconState.slot) { + console.log('Waiting for the next epoch.'); + await sleep(12000); + continue; + } + + const prevBeaconStateSSZ = new Uint8Array( + readFileSync('prev_beacon_state.ssz'), + ); + + const prevBeaconState = + ssz.capella.BeaconState.deserialize(prevBeaconStateSSZ); + + const balances = beaconState.balances; + const prevBalances = prevBeaconState.balances; + + const balancesWithIndices = balances.map((balance, index) => ({ + balance: balance, + index, + })); + + const changedBalances = balancesWithIndices.filter( + ({ balance, index }) => + prevBalances[index] === undefined || balance !== prevBalances[index], + ); + + // TODO: push the changed validators to the tree + + console.log('#changedBalances', changedBalances.length); + + console.log( + 'changed indices', + changedBalances.map(({ index }) => index), + ); + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + prevSlot = beaconState.slot; + + // wait for the next slot + await sleep(12000); + } +})(); diff --git a/beacon-light-client/plonky2/circuits/Cargo.lock b/beacon-light-client/plonky2/circuits/Cargo.lock new file mode 100644 index 000000000..975927032 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/Cargo.lock @@ -0,0 +1,949 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "const-random", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "circuits" +version = "0.1.0" +dependencies = [ + "plonky2", + "plonky2_sha256", + "sha2 0.9.9", +] + +[[package]] +name = "const-random" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +dependencies = [ + "const-random-macro", + "proc-macro-hack", +] + +[[package]] +name = "const-random-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +dependencies = [ + "getrandom", + "once_cell", + "proc-macro-hack", + "tiny-keccak", +] + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", + "rayon", + "serde", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "keccak-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2bd4c29270e724d3eaadf7bdc8700af4221fc0ed771b855eadcd1b98d52851" +dependencies = [ + "primitive-types 0.10.1", + "tiny-keccak", +] + +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types 0.12.1", + "tiny-keccak", +] + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "maybe_rayon" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "rayon", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "plonky2" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "ahash", + "anyhow", + "hashbrown", + "itertools", + "keccak-hash 0.8.0", + "log", + "maybe_rayon", + "num", + "plonky2_field", + "plonky2_util", + "rand", + "rand_chacha", + "serde", + "static_assertions", + "unroll", +] + +[[package]] +name = "plonky2_field" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "anyhow", + "itertools", + "num", + "plonky2_util", + "rand", + "serde", + "static_assertions", + "unroll", +] + +[[package]] +name = "plonky2_sha256" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2-sha256?branch=main#06d128e78ed8d29b21d58294b069e852c1866f8d" +dependencies = [ + "anyhow", + "env_logger", + "itertools", + "keccak-hash 0.10.0", + "log", + "plonky2", + "plonky2_field", + "plonky2_u32", + "plonky2_util", + "rand", + "sha2 0.10.6", +] + +[[package]] +name = "plonky2_u32" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "anyhow", + "itertools", + "num", + "plonky2", +] + +[[package]] +name = "plonky2_util" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash 0.7.0", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash 0.8.0", + "uint", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "rustix" +version = "0.37.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unroll" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/beacon-light-client/plonky2/circuits/Cargo.toml b/beacon-light-client/plonky2/circuits/Cargo.toml new file mode 100644 index 000000000..4dcec7a8d --- /dev/null +++ b/beacon-light-client/plonky2/circuits/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "circuits" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +plonky2 = { git = "https://github.com/polymerdao/plonky2", rev = "4cb0b48df1d227d5461a4c28ed025aaea64e2e62" } +plonky2_sha256 = { git = "https://github.com/polymerdao/plonky2-sha256", branch = "main" } +sha2 = "0.9" diff --git a/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs b/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs new file mode 100644 index 000000000..3b648ba0b --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs @@ -0,0 +1,25 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_sha256::circuit::make_circuits; + +pub fn hash_tree_root, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + leaves: &Vec<[bool; 256]>, +) { + for i in 0..leaves.len() - 1 { + let hasher = make_circuits(builder, 512); + + for j in 0..256 { + pw.set_bool_target(hasher.message[i], leaves[i][j]); + } + + for j in 0..256 { + pw.set_bool_target(hasher.message[i + 256], leaves[i + 1][j]); + } + } +} diff --git a/beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs b/beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs new file mode 100644 index 000000000..ddb9ecd28 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs @@ -0,0 +1,68 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; + +use plonky2_sha256::circuit::{array_to_bits, make_circuits, Sha256Targets}; + +use sha2::{Digest, Sha256}; + +use crate::utils::hash_values; + +pub fn is_valid_merkle_branch, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + root: &[bool; 256], + leaf: &[bool; 256], + branch: &[[bool; 256]], + index: &u64, +) { + let mut leaf = leaf.clone(); + + let mut index = index.clone(); + + for (i, sibling) in branch.iter().enumerate() { + let is_right = index % 2 == 1; + let mut lhs = leaf.clone(); + let mut rhs = sibling.clone(); + + if is_right { + std::mem::swap(&mut lhs, &mut rhs); + } + + let hasher = make_circuits(builder, 512); + + for i in 0..256 { + pw.set_bool_target(hasher.message[i], lhs[i]); + } + + for i in 0..256 { + pw.set_bool_target(hasher.message[i + 256], rhs[i]); + } + + leaf = hash_values(lhs, rhs); + + // constraint the root + if i == branch.len() - 1 { + assert_hasher(root, builder, hasher) + } + + index /= 2; + } +} + +fn assert_hasher, const D: usize>( + result: &[bool; 256], + builder: &mut CircuitBuilder, + hasher: Sha256Targets, +) { + for i in 0..256 { + if result[i] { + builder.assert_one(hasher.digest[i].target); + } else { + builder.assert_zero(hasher.digest[i].target); + } + } +} diff --git a/beacon-light-client/plonky2/circuits/src/main.rs b/beacon-light-client/plonky2/circuits/src/main.rs new file mode 100644 index 000000000..62df128e5 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/main.rs @@ -0,0 +1,8 @@ +mod hash_tree_root; +mod is_valid_merkle_branch; +mod utils; +mod validator_hash_tree_root; + +fn main() { + println!("Hello, world!"); +} diff --git a/beacon-light-client/plonky2/circuits/src/utils.rs b/beacon-light-client/plonky2/circuits/src/utils.rs new file mode 100644 index 000000000..8f89a73c9 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/utils.rs @@ -0,0 +1,25 @@ +use plonky2_sha256::circuit::array_to_bits; +use sha2::{Sha256, Digest}; + +pub fn hash_values(lhs: [bool; 256], rhs: [bool; 256]) -> [bool; 256] { + let bytes: Vec = [lhs, rhs] + .concat() + .chunks(8) + .map(|chunk| { + let mut byte = 0u8; + for (i, &bit) in chunk.iter().enumerate() { + if bit { + byte |= 1u8 << (7 - i); + } + } + byte + }) + .collect(); + + let mut hasher = Sha256::default(); + hasher.update(&bytes); + + let finalized = hasher.finalize(); + + array_to_bits(finalized.as_slice()).try_into()?; +} diff --git a/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs b/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs new file mode 100644 index 000000000..03cabfbda --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs @@ -0,0 +1,37 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_sha256::circuit::{array_to_bits, make_circuits, Sha256Targets}; + +pub struct Validator { + pubkey: [bool; 256], + withdrawal_credentials: [bool; 256], + effective_balance: [bool; 256], + slashed: [bool; 256], + activation_eligibility_epoch: [bool; 256], + activation_epoch: [bool; 256], + exit_epoch: [bool; 256], + withdrawable_epoch: [bool; 256], +} + + +pub fn hash_tree_root_validator_sha256, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + validator: &Validator, +) { + let hasher = make_circuits(builder, 512); + + for i in 0..256 { + pw.set_bool_target(hasher.message[i], validator.pubkey[i]); + } + + for i in 0..256 { + pw.set_bool_target(hasher.message[i + 256], validator.withdrawal_credentials[i]); + } + + +} diff --git a/beacon-light-client/plonky2/tsconfig.json b/beacon-light-client/plonky2/tsconfig.json new file mode 100644 index 000000000..3c326b5ba --- /dev/null +++ b/beacon-light-client/plonky2/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "files": [ + "./hardhat.config.ts" + ], + "compilerOptions": { + "moduleResolution": "nodenext" + } +} diff --git a/beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs b/beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs new file mode 100644 index 000000000..3cd2d07ff --- /dev/null +++ b/beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs @@ -0,0 +1,26 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_sha256::circuit::make_circuits; + +pub fn hash_tree_root, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + leaves: &Vec<[bool; 256]>, +) { + let + for i in 0..leaves.len() - 1 { + let hasher = make_circuits(builder, 512); + + for j in 0..256 { + pw.set_bool_target(hasher.message[i], leaves[i][j]); + } + + for j in 0..256 { + pw.set_bool_target(hasher.message[i + 256], leaves[i + 1][j]); + } + } +} diff --git a/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts b/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts new file mode 100644 index 000000000..175be1885 --- /dev/null +++ b/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts @@ -0,0 +1,94 @@ +import { writeFileSync, readFileSync, existsSync } from 'fs'; +import { sleep } from '../../../libs/typescript/ts-utils/common-utils'; + +(async () => { + const { ssz } = await import('@lodestar/types'); + + let prevSlot = 0; + + while (true) { + const beaconStateSZZ = await fetch( + `https://floral-chaotic-sea.discover.quiknode.pro/c1133f4fcc19bbe54fa6e4caf0c05ac79ec7d300/eth/v2/debug/beacon/states/head`, + { + headers: { + Accept: 'application/octet-stream', + }, + }, + ) + .then(response => response.arrayBuffer()) + .then(buffer => new Uint8Array(buffer)); + + const beaconState = ssz.capella.BeaconState.deserialize(beaconStateSZZ); + + if (!existsSync('prev_beacon_state.ssz')) { + console.log('prev_beacon_state.ssz does not exist. Creating it.'); + + prevSlot = beaconState.slot; + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + await sleep(384000); + continue; + } + + console.log(beaconState.slot); + + if (prevSlot >= beaconState.slot) { + console.log('Waiting for the next epoch.'); + await sleep(384000); + continue; + } + + const prevBeaconStateSSZ = new Uint8Array( + readFileSync('prev_beacon_state.ssz'), + ); + + const prevBeaconState = + ssz.capella.BeaconState.deserialize(prevBeaconStateSSZ); + + const validators = beaconState.validators; + const prevValidators = prevBeaconState.validators; + + const validatorsWithIndies = validators.map((validator, index) => ({ + validator, + index, + })); + + const changedValidators = validatorsWithIndies.filter( + ({ validator, index }) => + prevValidators[index] === undefined || + validator.pubkey.some( + (byte, i) => byte !== prevValidators[index].pubkey[i], + ) || + validator.withdrawalCredentials.some( + (byte, i) => byte !== prevValidators[index].withdrawalCredentials[i], + ) || + validator.effectiveBalance !== prevValidators[index].effectiveBalance || + validator.slashed !== prevValidators[index].slashed || + validator.activationEligibilityEpoch !== + prevValidators[index].activationEligibilityEpoch || + validator.activationEpoch !== prevValidators[index].activationEpoch || + validator.exitEpoch !== prevValidators[index].exitEpoch || + validator.withdrawableEpoch !== prevValidators[index].withdrawableEpoch, + ); + + // TODO: push the changed validators to the tree + + console.log('#changedValidators', changedValidators.length); + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + prevSlot = beaconState.slot; + + // wait for the next epoch + await sleep(384000); + } +})();