diff --git a/.circleci/config.yml b/.circleci/config.yml index 032b8fb0b2..9201883360 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -181,6 +181,19 @@ jobs: command: make citest fork=eip7002 - store_test_results: path: tests/core/pyspec/test-reports + test-whisk: + docker: + - image: circleci/python:3.9 + working_directory: ~/specs-repo + steps: + - restore_cache: + key: v3-specs-repo-{{ .Branch }}-{{ .Revision }} + - restore_pyspec_cached_venv + - run: + name: Run py-tests + command: make citest fork=whisk + - store_test_results: + path: tests/core/pyspec/test-reports table_of_contents: docker: - image: circleci/node:10.16.3 @@ -307,6 +320,9 @@ workflows: - test-eip7002: requires: - install_pyspec_test + - test-whisk: + requires: + - install_pyspec_test - table_of_contents - codespell - lint: diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 998a1e0fc4..f32311fa5a 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -71,7 +71,7 @@ jobs: needs: [preclear,lint,codespell,table_of_contents] strategy: matrix: - version: ["phase0", "altair", "bellatrix", "capella", "deneb", "eip6110", "eip7002"] + version: ["phase0", "altair", "bellatrix", "capella", "deneb", "eip6110", "eip7002", "whisk"] steps: - name: Checkout this repo uses: actions/checkout@v3.2.0 @@ -111,4 +111,4 @@ jobs: ls -la ./ rm -rf ./* || true rm -rf ./.??* || true - ls -la ./ \ No newline at end of file + ls -la ./ diff --git a/presets/mainnet/trusted_setups/curdleproofs_crs.json b/presets/mainnet/trusted_setups/curdleproofs_crs.json new file mode 100644 index 0000000000..25c7ae0e2f --- /dev/null +++ b/presets/mainnet/trusted_setups/curdleproofs_crs.json @@ -0,0 +1,140 @@ +{ + "vec_G": [ + "0xa44aae199242e24a4d00b8e5c96e318793eeeb2e154423ca6dcac20043387323dea3216a69bc13e9a3507ff842da544d", + "0x8dff68d38281daa552c587d073e498d1ed311986967192cba052827b07f194a936809ea3de921511db45d15234754993", + "0xad0ff210542fc069d065b53b2cd4228a0f097facebe089a83b989fd3344c53e440ded5da26bc6115299d9d464e1a9f28", + "0xb638e703f852d2ac49595141f7688c52a95dcc0b00f82a8548b14d823ebffe8657557ed7dab6bee44b17d39d742f69aa", + "0x9377c7771e07a1a9b9368796ce1a1b93d560d7726afde02627b424ee1dcddb3761ed49f2e1ae5279dca050935bd4a6dd", + "0x8d1be282936392c0c61c94745cfb29da0f3334272c9b37fe43c8b869640eb1ea88c8aaf5ff797bd90daf3d6ebeb4efb3", + "0xb3b55847d3bcf98b587c4441b0703939b5984bac91b00aabb5f3a45b38445405b61127bc6ee9f6b4b9e88c7a29c3aaa3", + "0xafb61afb9f92c37ec21220c02edf14876d2a08eab8ad3c2bc1f3bfe5036abfd23a4a7216616fa1953e14340bf0acab37", + "0xa94133ee96e00465fe5423e0ea52404e0f624ee8cc9d69b4cf94e7d73635dfa2087cd2d2596ac4a75504aac5ef6a02d4", + "0xa4b93e670e7ee926ffb4ea4e07b87346e5d33c76520912f8a7937cdc3290a4c054586e175c39826b7fafbe777d14e4f4", + "0xa57540f7c906d9e70ef90580967562f8c06398ac2d77612045dce0ea6fbc2fedcfdbeb3f6ad3bb717e1295d9539ede63", + "0x8504de35cb15935580dab4ae521aede9a6764731a687d23ed213859545065fae9ba915f33f05c5417d91801d2e70098c", + "0x976674e04ccfe0530db2a3723a36760949857f56b77df698d6b8c88a1152ca4ee2f0dad4fac413a34e0aaef9684fb547", + "0xa7aee20d139d52043203c05ce128a7b17d0e37cfd92370aecc2a777339f03558bbe9cb4bae5c42557be50d6be381537c", + "0xaea7520f557b33f6dbbf244f3c7e5784ce727ff18396dc7c200818333b0e946c1bd8c2e464646ca7b43a857e09b23bc5", + "0xb15a797f9a56e5511f73a02cc6a94ca3e6b4a50e8166151cba087d1bc051486b1771054ab1a76cea9045c961b989dad3", + "0x90458a1852cc7581b8dbf82e7ce16407542b30ca8d7b13ba86707a57e25996545cf2dc2ce03af35c4465129f1441dc2c", + "0x8975b5a131cdcebb1a7716e766dd829acaf1bb49e245e765b968f67de81be679937485c84193eb466033fedff89f117f", + "0x86a8d7b004b32f4a00b520b35701cd64df833827e37ff5ccff01f1f9ed72cd6a95cc6de5313085aa0f16d537413cf3f8", + "0x881dbeff4ac65d1be0bb462480ecfe299003042c4190a5c68201981e08868e3f056f1e35a5117488db6633d567c9930e", + "0xa70b2ea517b3c51cd02f6b6677d926ac648fa605330be36c7a475b4dfacbdad035c02d1124350fb67a6e9eef9db858b8", + "0xaab1475f7a085a35253adf0a5c5c968f8a44e119e92f69ceff1fb46a62e161ac2c65358310a64128c8a87573646712f7", + "0x94cafc40ecbd04ec8976ae399b820c3a0717dee37b2a8338724042cb7465a18ea29d76068b82bff1bc2147776a7f44c1", + "0xb936bf0248d8df624185c9176d2edc9c6cbf7a4624c942f50011ae83ca2212ea2453c07cf8db96294bb010b18cfabc48", + "0xaf0a2894d762325816d6a35485612eaa173b4fc31ff112b6e20dbab722692f58230b17c038212098fed7998eb2fa23a4", + "0xa6caa65c5483318cb4e47fa186353c565517a03018a6eb04baf5aaa8844379b09ab998e568cfc2af976e44cd1cb15395", + "0x924c94856f92e5212215636fe3ccc5de9e952293be6fe2369250d6aec62d481977b7d2815d72ccca28d0be18918c8d63", + "0x91c764d72eb782e2957a39eca43107069d28dd2e33f39484c55201f685714269672c191ee42d27237bb9055612eca176", + "0x8af8de9f36eac06547468021c040e020b284f517b8a4ef99f0909962c2fed60a0c7955f9763258dc4839dbaafe8f9365", + "0x9864fc53cbf30454f8ce1d9094d70f4c974e841c7d69815d73eb1b5efa0b063b511cac62ded138e75a7a0440f6b332d4", + "0x83cbf72e944cc0bd81fa18eda658c9c668f3f17c06b1936d7646aef0d7f5d35004709dbb04a811cade784bb5a89f96ad", + "0x93c9e4b3a4f477723410f30134fe16184df889ef021aaafbd8c562929b90031fb22b1b4e806287703f12287fbb0e99af", + "0x99fb0257c487a9801d7af55179f8eba20d90e673f57791948a35caf7dbdc08ee6069d2d1b9751c7d1b831918bdceb7db", + "0xadc24c2c32ce6a7ae62fac5fcd87f5658071a01e86d18bd8366c50a6414caec5fcd067168b9359b2cdb07b70f7f21f11", + "0xaaf509c0687bab09c61f36202e81c21f8ad01276dee9c8035457fd1bf550afc2eacdaa93a9a7b53c60120ac07594261e", + "0xb30b3bfc59f53f15adaca94304eaf9df1c85ceb8f2f3831fc7472e9aab4ed62454655930ab7c924d744ae49919db7b9e", + "0x887e2559ea7fe8012bff545cf77b51f149f18ea6dfba90e60aa4bca704aec4f79e628b73fcb9f55d38071cbca322853d", + "0xb7fed350264b85c1c167f8763e6b4ef23bd65a1d611daa5e3ee8de5df399603f206f7b81cc061019bedc694243cc23b6", + "0xa83210d7c9c7858b047a866f672e6cdec26d73fc4815f28636cca898ff349970163819869500769208e74bc5a484845a", + "0xb08abbcda10f77e83b1f267c29ab192d4324d890834b2b44847a412a48cdb65e91a97c9a2fbc768034bceec55324a15f", + "0xad67e686bd0159f8ed762916211b5b0884a40df62518b8035edb5b7091dec05ec0a28ed147f3d6b2ee6aaf52d94bff31", + "0x8f324349647ccbaefb906d6790c314487b66a472ed1f8e02579b0658f2967185fe16227ad97802652941d23b5d2f67d1", + "0x96f41b8f53b08fe484f9df8880ed95a5d239ac541c9bb4ebbf7351c36ab191a3be33982c6bbdd099610cd0d96406aece", + "0xb1b79d46dd8a0dac9e9f555ce082cdf30f968263557dcccdeb54294f953f83f333c3af785c91e117de3ce70f79edcc66", + "0x81cf46a6962ba9d4a4f5bf2e63828b3f11bc9f35b2d126f80d9c547f53cec1539f303f22b91750660af46a17fcdf92a7", + "0xb7228f3497afba6c316d65eab6f3307bd88c01c49a881e649a67c89b88d5743ff74a8a7cb59e1b6e0f0ce32541c78dac", + "0x8fb76e5fc58d3c7e20805e8ae8a9d2b9359470c1a8c90017744abcee7e86f09b53838d34b56b6c95ed8f3bd4a4d06022", + "0x8ddfa7be366374d6fb55c6ab88c1a3b0b61edd87ef1069b492b38124e68a901da691702bef9ea3ad66019b59148d9285", + "0xa137a4405d6ea2b9b6a124b7bd073bc57a5b62f6b7dc70f6ee1da1d6103da22e19368cc6c804853998901fb9a5508723", + "0x86fc4a0481122463dea3fed7ba1671b41200edad47d1b16f90a0055e10ea46f1db64efe7c052aaded4e9ebcc00e811ee", + "0xa21a5cf22c6e5d8c95a0cf4b0a28be314534bee6bf1b342551edfff8a594664f75a95531d176f54bc8a1b3780dd56a00", + "0x9324572f9dbcbf9732eeb796089e902361e1d638fb83d4ad3bbd4b46bc169b23ce5e79ac066961ea6c096b5e219351eb", + "0xb048c3ac9604adbf3aad2ecf66485cb1fe90c0d767f0fc6f050a8d1fc3ea5620a88e46e32e30154f2fdf0990dffb350d", + "0x8a38fddb1a0a9de438aecf09cd0b2860a77491adfc2f47c485bd6e550d8f37e3accf0acd631743d855c830c20ffc4eae", + "0xab0ba1ec519d872ef5f768c940135f26bd8586ae530c48e45e2a25229e8a740ba17c93b3dd6761ba6c81a1929878866a", + "0x830b63ccc9713075ac618c64b870d8375d5bed64fd3701ec0caed47afe5ab3f567b3a1a981c302540ed0010c8aa48148", + "0xacb93bff4d4640d5c25291fc93d159360828481c6339baac50aa861def7088afa5909b735d1d4a12e3e2a23e303b6399", + "0xb398803308ffcd86e7b6df0ba952d95e7f417b73afed81e23eff09a4bd0a7ed1ab651beb206834d2c883ac4417f49032", + "0x9756aa1c5173a38e831f5cadae27fb0ee8ed850e2a846718f0f5419cc90beb9518dc31e4e8fefe4a9a40e54917fe120b", + "0xaeb4cbd4c463752a695e9c2d66188d015dd6220754130579c9bfa2d3b7c3c6c3fc7ec49fcf0009aba9bd5074dcb3f95e", + "0xa1e3c0889f0657ddda6816c1e4e1e43e457a5a388f60cea410c048023ac227db4e3e6d2a7f0222f499a89137605210e3", + "0xad96ad5fc3e43e68bc238e1267ccd81636e9e0ab035890185c4294705534a7bd25bb1c15a60786f35a829473d49781ea", + "0xa36db550a04a4676ac760a32e3734f5f17f8b7b912d9c560e9c148a706a2492d8b5a146b4188c66e3f4d5272777ddd58", + "0xaf47ec208a81bd7003cfccc1a1db8d2065f1c984f42abb430a903c9a643d1cc9fb981d55a01380bf7b74721275aaaa62", + "0xa979361a25434641c217ef285c4c81974bc2fe3a856781beab30a883b95d1b93de1fc21872723737cc93e028c5d3d147", + "0xb67ff15cc11b431c47fd1c136ea18c34224741c147eb584c6a3d253af826babe76dac4f7f7b847e7cd674730c3cf4956", + "0xa1638a24170fda842334a68c3a3939ac24b1de7b124d184244405b26419ccf7a5ceb090a4f1755bc07a5fa6637165255", + "0xb1ed9cf1516dca2a38b00694847809d8a172968b61a26d0615c5b2ab80363acda6a9af632fed703299d964a3736a7103", + "0x99319462b880885aa5db0070f151e205bf8288bf993d434fc99081bffdc1528265d5e252e2666d0947fdeafa48625513", + "0x8f5707ce471989512e497385171f9a5f462b0e987ffd8a696c602248155e9639b9597bbdd8b6cbd6685975136b52a40c", + "0x87465b2c5dd27e13a0892c30e7e2ff6819489db9b53487265a23fe764b6b4eca3b2338de672e6ea4ab3f8736c9feef56", + "0x89ddb3632add71b62e324fa6265600e809b29e4904d68c5fefd59a36f66cbd3741e03245aa4f015521d946e777d0c195", + "0xa270e76ffa82fad0a4408aa2e45235dbbd18304eb470e51411ae4ddd16b142666bfe37d9510eea9e69ed04e799788e0c", + "0x8983d57179a62eb563d3f7453672a5940b958a27df321bde6589056c1ea542c419e4116765a457c9b529b1014c3b3f68", + "0xab405480f4d5001e4c43b52f095896a3c8e394bff02c14f57facbe539c04210b4b589903bd94d0ca58b78e8c82745a22", + "0x82377e25d1f00987908d21ee2620a6653af77c72e038bb394c72d0b1d9b9a4930c6a2bb06ca091b8c4c19e62830268d6", + "0xab94d4848d372c00e205c64a6c7386a4078cb1860989c99e0313776d0518b056f6608ea3b4d12f50e0a8678dbfa0c73c", + "0x977ff883fc1217d4ef5220c74e06c3ce002cb691f191a1e31f46082fa2400236a5879d5dd4bd1d2421b991bb394c5e17", + "0x95bac7596af12ba4c11226ecd0ed0828c98eb60c8f142477872b401e2d7af5f3b04204508cf40a88f29d2235125a1b65", + "0x813e6c95f967f1371d0df1144bf73993947a6cd98e31f127db9239d69a8e97c1a41394890a2a2be85240c9b36ec74906", + "0xb44194edd26a519267d4ca212540bbe114976f28be9082c77a308c1731159c8b0fabb25b590dc445053585df0e555797", + "0xb7bf875591b4c4859154bbb9081fcb82b28fe87121fb866b598a5baad601478acbac0cb13d0cd14402368cee767b4231", + "0xa7bce1268dd1ba7d2e3e24e9d3fd44d0f7664e658dc27e9bee4aff75d76ea920bc34f25d14fe96a02c96cbb6692b544c", + "0x973194c2280380f42070200c9c729b3f651336379da482c5229ad321f29423bc6d1ccc1a5ced594806ce73b3ce437d12", + "0x978b88b3a66934790fba6bd2fec74410e18fab319b6c8a828dc32c3c8ffc23014e26f6c42835b58440bad6201ba790a2", + "0x8445283a55cd40ac99a710e4ebeca19b4042f89a9dbc0cb22cf62b6312edc7a4d4366efb169e1c0de8bacb8a1f2ff2ca", + "0x85bfaa05173114a0f3a2276671846db99a8f858b279a868e236cd9d974f69171501198cfcdec3dca093e5439a88199be", + "0xa3aab6d03e5c0cdd38096d7c97935913dbd24953e49eee341603ed434a067e1ac2270e6b74b45737ae1e79e9c248f15c", + "0xaf36fb1566ffeb6f0673640853b6c576330bb32751454b83835f0f26f50cd5d5ebb6658f6b1e9eeb9dcdb879745c9c7d", + "0xb216eb3d9d28c1ba93a57e82cc03469a9f40156266fcc96134a66da8a61aff3b78b783221fda5b23526fed2f91345418", + "0xb74637cfe60f5e7c116ab4be75bcfdfb08ba29ecc7b2363f547a2236bc170346388dd9fbaa1670ce1e45d4c96069717b", + "0x823a3cc16cfae5317b293fe905b8af7d7d2733c24f96cc66522aff2a376b5340dbcca8429f4082edb562da157c051c80", + "0xadf3b83761df2ca910900775e5d65e29bfd274cbb0cdd9614115aceaaa019b0e38a3e3b11777fff99d2b3b8c22de490c", + "0x8ef121f237356ed3dce22ec6e6b8a8085b71db20974483242d1280c18c51ba4f4438200cb4137e25f447e1a713f8894b", + "0xaec4690276f929c9cd2fedef923e1d2324a6b5f273f5c938b9e971b93d0762f181013e2cef334bf3ba70f1795fafcf23", + "0x91099cdfbe5ec822474b397366cba936c997bbe17169334bf94730c689b1e27943793f96e4825e0d96df577af77ad06f", + "0x94ac37115fd458fb690177ac88e6fc7f11bafb231fdc20e2995fddab695494a4bc86b1fcf53f7259843749f55ae40b92", + "0x832d99b9e3f910e8e19bee53dcf1ae0fcd7713e642cfebbdd891c59325bc50894a812ff53edbfbb38aca8cc5d97aea06", + "0x96373b775b1eafe66113b1bddad0e4ae9ba26f2c32393a29a2fa3660979eac480748d05deda7a68cf44c64fa38c7a03d", + "0xa0f960d2e4c4a6b75ded6207b686d3e943b675f5eaed6820d676889bd0625554753db4de8bc8d0c3cad475ee411e39b5", + "0x97d86db51837301ebb10e4867a8d71ed6f82b152e6b9d4256d15e0807d7e461dbfceeeabfc2ab9d5bb5789f3d9c30779", + "0x892bb178f0f2bdd2f6a027ba426396e610cd0803f6a1365ef6caf5508ddc5349f30f363e15cf19b2e700374b6d871830", + "0xa1271b15e75da127dbb44e2765c879ec037479edcfe52a3b7b607c114509e03a057a6d685223c3f4a0fd9e734469378a", + "0x8863d29a686a040514661be853c4cbdc28cbe7fe8c401aad01644f0a892ee4c4005148e40c2fdce642e690be9d8eef2f", + "0xb567760e8dbf7a61ba5a77d4b07c4a879b580863894f3c4fd9d652cf1ca53b9a0aebd6d8f559c5665fdf5cab5b9242c9", + "0x99bb4f6d41b33039c9443ba90203ca47eb6e79b126ec3e92e61495833d59c8464002cedc74bc33795d5a5e5d4772610d", + "0x94cf97bf6f28e38b2e6f4cbc58a6fbe1f031ecd8a9cc66b62835698ea88e9fe6419a80b57ffa19bf77dc048e39c11f41", + "0x8dc24197a96bbed35f779bd64cf9104975b68f310b82c2f03a587b522102cfecf061383108d7628e8b46359c06f41726", + "0x86ed177c05f473eb8bad7f79238d911c11cc3c7378e24dd70aa83659888f4915f9e13e3563617d369e8217e1ba77c01f", + "0x82b7176c8a6609cc286bb8f3f8d72a707aae630cb05510cba5a5cba711acd472d60beb2a413e45aef8265026d79fe576", + "0x875085a20d7390d92385ff1e4c112195198f7763cebde5d13ffac243f0a96be7a2a57ab9ec105f99187bd13e00cbf2f9", + "0xb14d2a2395677a2beb3b90bda389c67a7a4a8361ce353c8710a13aa59c08d2aea8d0197beb0db31b0e92fbde16bb9606", + "0xb7f222ee1e25115ece1b098b1c0261b326dfc454380d07e99bf498bbd8aafb209da4b5ff64c6a481cdcafc5d205de296", + "0x8bc66bbfb988913fd3b1c56d36ae3eb06b6219c8c278bdc8422d07e01e48e44239eca14255a43e1038f80322b2969156", + "0x906d257ada831ab1db57a7511d10d33c43f84947a2cbb8e9401010c9de542edaaa39d2ce329c33fe1a99c0bd03779acf", + "0x80373467a36d5e99aafde2875dc9caf6b1242bb4a285c6879f11d30ec4eaedea54327237eb02cf221d660ead62875948", + "0x9081a5170a70333cd9d6bd638772c2012e9c095800d3cdaf77a7ca98a1413c109686b42b9fef681250eb93b715702d1d", + "0x899427b7eca7c24e0760a6928f688ce91f7bc725b70c456c1ad7995effaac3edae2b41067e39cf8e2310a7201a4af55b", + "0x8d5ea173aa180ed6940d9577898271a21faaddfaf5afbc46c66ac29039ab35946952217545f5e7b816873e97df6e294e", + "0xa8af63310ce64f772410f18f29d60f9f1c5c49a858ed1971089673c1e0c8d85c8235617ea8bd919e542b238a63b1be07", + "0xad591bb5842e0d6132c573ab747d391a698332637452bdd262b0a6ea2ca29b346c7405348593228769459f5e1f156a07", + "0xb38395b34871fbc0c3a4d5e50c7e62a08ee58d2e19051ce269d2a56615f1f679e7eefe47e99ebe1e53a9bae9013c9de7", + "0x87affdb63f3d5bd9f4e95da4dac365ba3f853be767b5c09c4fbc24162744566ab20544a61657374e4122f36a2cfcc8c2", + "0x80cd960856a511cf957bf5bd4a4c3c6bc65c0fb5e785dc51560aa34ce56ddec6838f73e6bf257cfd273e05c7d719c098" + ], + "vec_H": [ + "0x8a135f527bcc420b9a4dae226c237012346c2356abbf20b60c26eb513ff0745153ff20dd94286d96fe679b1a22cbff5d", + "0xa5c64c216db68e10b32ee5c8fd29b1a3dce6238273ec141ca7d8d8dcbdf7b992c4ddf576633cd4f828244527e05e3461", + "0xab0a28fa68ad7d91c40b49e277e25ebdef5b689dbeae3be297161e44df940c02d2594e5d76b6be1547780d8ffc3cf9de", + "0x8532adc9d2fac12f65261fd17a57f231f7246feb60babc9c7beaeb628c0e1ad207e17252d736a7965542c3d7ebeb7fc2" + ], + "H": "0xaeb2d25680cbf2be736d999a01d73472e2779229a8ee2a8701b5cea2a93898fdf2150d467247f23a7761f650d38bdf6f", + "G_t": "0xa4e53147e355879fdb62f185ab7b8569925f356503a2ea67d4a13380f2a1bb82be57112893584834f1965cc8a4061d2f", + "G_u": "0xa693bce513d30e072ef71b7dfd03966cba8b11b0af9dbc0585b92514175772a81d083d7ff48e0adf3e3bee88823db240", + "G_sum": "0xa0181ccd048b494d5b35463e180408dc9c3325573f8639bf6bcd9447accfc093336158a0859fe3b3021ad141936da977", + "H_sum": "0xa6dbebe99ca5ddf836d4d1fe64479de04d8370dea2c36c3409b83706d58ec58150eba667d1d60471299b494162fcb6c1" +} + diff --git a/presets/minimal/trusted_setups/curdleproofs_crs.json b/presets/minimal/trusted_setups/curdleproofs_crs.json new file mode 100644 index 0000000000..b9b6ad5b9c --- /dev/null +++ b/presets/minimal/trusted_setups/curdleproofs_crs.json @@ -0,0 +1,20 @@ +{ + "vec_G": [ + "0xa44aae199242e24a4d00b8e5c96e318793eeeb2e154423ca6dcac20043387323dea3216a69bc13e9a3507ff842da544d", + "0x8dff68d38281daa552c587d073e498d1ed311986967192cba052827b07f194a936809ea3de921511db45d15234754993", + "0xad0ff210542fc069d065b53b2cd4228a0f097facebe089a83b989fd3344c53e440ded5da26bc6115299d9d464e1a9f28", + "0xb638e703f852d2ac49595141f7688c52a95dcc0b00f82a8548b14d823ebffe8657557ed7dab6bee44b17d39d742f69aa" + ], + "vec_H": [ + "0x9377c7771e07a1a9b9368796ce1a1b93d560d7726afde02627b424ee1dcddb3761ed49f2e1ae5279dca050935bd4a6dd", + "0x8d1be282936392c0c61c94745cfb29da0f3334272c9b37fe43c8b869640eb1ea88c8aaf5ff797bd90daf3d6ebeb4efb3", + "0xb3b55847d3bcf98b587c4441b0703939b5984bac91b00aabb5f3a45b38445405b61127bc6ee9f6b4b9e88c7a29c3aaa3", + "0xafb61afb9f92c37ec21220c02edf14876d2a08eab8ad3c2bc1f3bfe5036abfd23a4a7216616fa1953e14340bf0acab37" + ], + "H": "0xa94133ee96e00465fe5423e0ea52404e0f624ee8cc9d69b4cf94e7d73635dfa2087cd2d2596ac4a75504aac5ef6a02d4", + "G_t": "0xa4b93e670e7ee926ffb4ea4e07b87346e5d33c76520912f8a7937cdc3290a4c054586e175c39826b7fafbe777d14e4f4", + "G_u": "0xa57540f7c906d9e70ef90580967562f8c06398ac2d77612045dce0ea6fbc2fedcfdbeb3f6ad3bb717e1295d9539ede63", + "G_sum": "0xa0d97028d7194094fe1c4f00189e360ae362eca4aa9dc8f92eabb8dcf0d93140a81953d4505cd7dc592504710d696ef9", + "H_sum": "0xaf415fddfb82e7cbb91fae0c443425c51dbb68e05f0324bd2d79e40b923ecb4f806e96e9993eabadd1c39ac4e12e74bf" +} + diff --git a/pysetup/spec_builders/whisk.py b/pysetup/spec_builders/whisk.py index e9cd4a67da..c892a1c081 100644 --- a/pysetup/spec_builders/whisk.py +++ b/pysetup/spec_builders/whisk.py @@ -1,3 +1,4 @@ +from typing import Dict from .base import BaseSpecBuilder from ..constants import WHISK @@ -9,6 +10,8 @@ class WhiskSpecBuilder(BaseSpecBuilder): def imports(cls, preset_name: str): return f''' from eth2spec.capella import {preset_name} as capella +import curdleproofs +import json ''' @classmethod @@ -17,4 +20,13 @@ def hardcoded_custom_type_dep_constants(cls, spec_object) -> str: return { 'WHISK_MAX_SHUFFLE_PROOF_SIZE': spec_object.preset_vars['WHISK_MAX_SHUFFLE_PROOF_SIZE'].value, 'WHISK_MAX_OPENING_PROOF_SIZE': spec_object.preset_vars['WHISK_MAX_OPENING_PROOF_SIZE'].value, + 'WHISK_VALIDATORS_PER_SHUFFLE': spec_object.preset_vars['WHISK_VALIDATORS_PER_SHUFFLE'].value, + 'CURDLEPROOFS_N_BLINDERS': spec_object.preset_vars['CURDLEPROOFS_N_BLINDERS'].value, } + + @classmethod + def hardcoded_ssz_dep_constants(cls) -> Dict[str, str]: + constants = { + 'EXECUTION_PAYLOAD_INDEX': 'GeneralizedIndex(41)', + } + return {**super().hardcoded_ssz_dep_constants(), **constants} diff --git a/setup.py b/setup.py index b46423bdc1..4c92d505d7 100644 --- a/setup.py +++ b/setup.py @@ -124,12 +124,28 @@ def _load_kzg_trusted_setups(preset_name): return trusted_setup_G1, trusted_setup_G2, trusted_setup_G1_lagrange, roots_of_unity +def _load_curdleproofs_crs(preset_name): + """ + NOTE: File generated from https://github.com/asn-d6/curdleproofs/blob/8e8bf6d4191fb6a844002f75666fb7009716319b/tests/crs.rs#L53-L67 + """ + file_path = str(Path(__file__).parent) + '/presets/' + preset_name + '/trusted_setups/curdleproofs_crs.json' + + with open(file_path, 'r') as f: + json_data = json.load(f) + + return json_data + ALL_KZG_SETUPS = { 'minimal': _load_kzg_trusted_setups('minimal'), 'mainnet': _load_kzg_trusted_setups('mainnet') } +ALL_CURDLEPROOFS_CRS = { + 'minimal': _load_curdleproofs_crs('minimal'), + 'mainnet': _load_curdleproofs_crs('mainnet'), +} + def _get_eth2_spec_comment(child: LinkRefDef) -> Optional[str]: _, _, title = child._parse_info @@ -257,6 +273,13 @@ def get_spec(file_name: Path, preset: Dict[str, str], config: Dict[str, str], pr if any('KZG_SETUP' in name for name in constant_vars): _update_constant_vars_with_kzg_setups(constant_vars, preset_name) + if any('CURDLEPROOFS_CRS' in name for name in constant_vars): + constant_vars['CURDLEPROOFS_CRS'] = VariableDefinition( + None, + 'curdleproofs.CurdleproofsCrs.from_json(json.dumps(' + str(ALL_CURDLEPROOFS_CRS[str(preset_name)]).replace('0x', '') + '))', + "noqa: E501", None + ) + return SpecObject( functions=functions, protocols=protocols, diff --git a/specs/_features/whisk/beacon-chain.md b/specs/_features/whisk/beacon-chain.md index ce149a1ef1..9c2cb389a3 100644 --- a/specs/_features/whisk/beacon-chain.md +++ b/specs/_features/whisk/beacon-chain.md @@ -34,7 +34,7 @@ This document details the beacon chain additions and changes of to support the Whisk SSLE. -*Note:* This specification is built upon [Capella](../../capella/beacon-chain.md) and is under active development. +*Note:* This specification is built upon [capella](../../capella/beacon-chain.md) and is under active development. ## Constants @@ -89,14 +89,14 @@ def bytes_to_bls_field(b: Bytes32) -> BLSFieldElement: TODO: Deneb will introduces this helper too. Should delete it once it's rebased to post-Deneb. """ field_element = int.from_bytes(b, ENDIANNESS) - assert field_element < BLS_MODULUS - return BLSFieldElement(field_element) + return BLSFieldElement(field_element % BLS_MODULUS) ``` -| Name | Value | -| ------------------ | ------------------------------------------------------------------------------- | -| `BLS_G1_GENERATOR` | `bls.G1_to_bytes48(bls.G1)` | -| `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | +| Name | Value | +| --------------------- | ------------------------------------------------------------------------------- | +| `BLS_G1_GENERATOR` | `BLSG1Point('0x97f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb') # noqa: E501` | +| `BLS_MODULUS` | `52435875175126190479447740508185965837690552500527637822603658699938581184513` | +| `CURDLEPROOFS_CRS` | TBD | ### Curdleproofs and opening proofs @@ -105,14 +105,17 @@ Note that Curdleproofs (Whisk Shuffle Proofs), the tracker opening proofs and al ```python def IsValidWhiskShuffleProof(pre_shuffle_trackers: Sequence[WhiskTracker], post_shuffle_trackers: Sequence[WhiskTracker], - M: BLSG1Point, shuffle_proof: WhiskShuffleProof) -> bool: """ Verify `post_shuffle_trackers` is a permutation of `pre_shuffle_trackers`. Defined in https://github.com/nalinbhardwaj/curdleproofs.pie/blob/dev/curdleproofs/curdleproofs/whisk_interface.py. """ - # pylint: disable=unused-argument - return True + return curdleproofs.IsValidWhiskShuffleProof( + CURDLEPROOFS_CRS, + pre_shuffle_trackers, + post_shuffle_trackers, + shuffle_proof, + ) ``` ```python @@ -123,8 +126,7 @@ def IsValidWhiskOpeningProof(tracker: WhiskTracker, Verify knowledge of `k` such that `tracker.k_r_G == k * tracker.r_G` and `k_commitment == k * BLS_G1_GENERATOR`. Defined in https://github.com/nalinbhardwaj/curdleproofs.pie/blob/dev/curdleproofs/curdleproofs/whisk_interface.py. """ - # pylint: disable=unused-argument - return True + return curdleproofs.IsValidWhiskOpeningProof(tracker, k_commitment, tracker_proof) ``` ## Epoch processing @@ -282,7 +284,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None: #### `BeaconBlockBody` ```python -class BeaconBlockBody(capella.BeaconBlockBody): +class BeaconBlockBody(Container): randao_reveal: BLSSignature eth1_data: Eth1Data # Eth1 data vote graffiti: Bytes32 # Arbitrary data @@ -295,13 +297,11 @@ class BeaconBlockBody(capella.BeaconBlockBody): sync_aggregate: SyncAggregate # Execution execution_payload: ExecutionPayload - # Capella operations bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # Whisk whisk_opening_proof: WhiskTrackerProof # [New in Whisk] whisk_post_shuffle_trackers: Vector[WhiskTracker, WHISK_VALIDATORS_PER_SHUFFLE] # [New in Whisk] whisk_shuffle_proof: WhiskShuffleProof # [New in Whisk] - whisk_shuffle_proof_M_commitment: BLSG1Point # [New in Whisk] whisk_registration_proof: WhiskTrackerProof # [New in Whisk] whisk_tracker: WhiskTracker # [New in Whisk] whisk_k_commitment: BLSG1Point # k * BLS_G1_GENERATOR [New in Whisk] @@ -328,7 +328,6 @@ def process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None if shuffle_epoch + WHISK_PROPOSER_SELECTION_GAP + 1 >= WHISK_EPOCHS_PER_SHUFFLING_PHASE: # Require trackers set to zero during cooldown assert body.whisk_post_shuffle_trackers == Vector[WhiskTracker, WHISK_VALIDATORS_PER_SHUFFLE]() - assert body.whisk_shuffle_proof_M_commitment == BLSG1Point() assert body.whisk_shuffle_proof == WhiskShuffleProof() else: # Require shuffled trackers during shuffle @@ -337,7 +336,6 @@ def process_shuffled_trackers(state: BeaconState, body: BeaconBlockBody) -> None assert IsValidWhiskShuffleProof( pre_shuffle_trackers, body.whisk_post_shuffle_trackers, - body.whisk_shuffle_proof_M_commitment, body.whisk_shuffle_proof, ) # Shuffle candidate trackers @@ -351,12 +349,9 @@ def is_k_commitment_unique(state: BeaconState, k_commitment: BLSG1Point) -> bool ``` ```python -def process_whisk(state: BeaconState, body: BeaconBlockBody) -> None: - process_shuffled_trackers(state, body) - - # Overwrite all validator Whisk fields (first Whisk proposal) or just the permutation commitment (next proposals) - proposer = state.validators[get_beacon_proposer_index(state)] - if proposer.whisk_tracker.r_G == BLS_G1_GENERATOR: # first Whisk proposal +def process_whisk_registration(state: BeaconState, body: BeaconBlockBody) -> None: + proposer_index = get_beacon_proposer_index(state) + if state.whisk_trackers[proposer_index].r_G == BLS_G1_GENERATOR: # first Whisk proposal assert body.whisk_tracker.r_G != BLS_G1_GENERATOR assert is_k_commitment_unique(state, body.whisk_k_commitment) assert IsValidWhiskOpeningProof( @@ -364,26 +359,25 @@ def process_whisk(state: BeaconState, body: BeaconBlockBody) -> None: body.whisk_k_commitment, body.whisk_registration_proof, ) - proposer.whisk_tracker = body.whisk_tracker - proposer.whisk_k_commitment = body.whisk_k_commitment + state.whisk_trackers[proposer_index] = body.whisk_tracker + state.whisk_k_commitments[proposer_index] = body.whisk_k_commitment else: # next Whisk proposals assert body.whisk_registration_proof == WhiskTrackerProof() assert body.whisk_tracker == WhiskTracker() assert body.whisk_k_commitment == BLSG1Point() - assert body.whisk_shuffle_proof_M_commitment == BLSG1Point() ``` ```python def process_block(state: BeaconState, block: BeaconBlock) -> None: process_block_header(state, block) - if is_execution_enabled(state, block.body): - process_withdrawals(state, block.body.execution_payload) - process_execution_payload(state, block.body.execution_payload, EXECUTION_ENGINE) + process_withdrawals(state, block.body.execution_payload) + process_execution_payload(state, block.body, EXECUTION_ENGINE) process_randao(state, block.body) process_eth1_data(state, block.body) process_operations(state, block.body) process_sync_aggregate(state, block.body.sync_aggregate) - process_whisk(state, block.body) # [New in Whisk] + process_shuffled_trackers(state, block.body) # [New in Whisk] + process_whisk_registration(state, block.body) # [New in Whisk] ``` ### Deposits diff --git a/tests/core/pyspec/eth2spec/test/conftest.py b/tests/core/pyspec/eth2spec/test/conftest.py index 3026b48eb7..e8478050f8 100644 --- a/tests/core/pyspec/eth2spec/test/conftest.py +++ b/tests/core/pyspec/eth2spec/test/conftest.py @@ -1,6 +1,6 @@ from eth2spec.test import context from eth2spec.test.helpers.constants import ( - ALL_PHASES, + ALL_PHASES, ALLOWED_TEST_RUNNER_FORKS ) from eth2spec.utils import bls as bls_utils @@ -54,10 +54,10 @@ def pytest_addoption(parser): def _validate_fork_name(forks): for fork in forks: - if fork not in set(ALL_PHASES): + if fork not in set(ALLOWED_TEST_RUNNER_FORKS): raise ValueError( f'The given --fork argument "{fork}" is not an available fork.' - f' The available forks: {ALL_PHASES}' + f' The available forks: {ALLOWED_TEST_RUNNER_FORKS}' ) diff --git a/tests/core/pyspec/eth2spec/test/context.py b/tests/core/pyspec/eth2spec/test/context.py index 7289fdf0fa..84c5c636bd 100644 --- a/tests/core/pyspec/eth2spec/test/context.py +++ b/tests/core/pyspec/eth2spec/test/context.py @@ -9,6 +9,7 @@ from eth2spec.capella import mainnet as spec_capella_mainnet, minimal as spec_capella_minimal from eth2spec.deneb import mainnet as spec_deneb_mainnet, minimal as spec_deneb_minimal from eth2spec.eip6110 import mainnet as spec_eip6110_mainnet, minimal as spec_eip6110_minimal +from eth2spec.whisk import mainnet as spec_whisk_mainnet, minimal as spec_whisk_minimal from eth2spec.eip7002 import mainnet as spec_eip7002_mainnet, minimal as spec_eip7002_minimal from eth2spec.utils import bls @@ -16,9 +17,11 @@ from .helpers.constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, + WHISK, MINIMAL, MAINNET, ALL_PHASES, ALL_FORK_UPGRADES, + ALLOWED_TEST_RUNNER_FORKS, LIGHT_CLIENT_TESTING_FORKS, ) from .helpers.forks import is_post_fork @@ -85,6 +88,7 @@ class ForkMeta: DENEB: spec_deneb_minimal, EIP6110: spec_eip6110_minimal, EIP7002: spec_eip7002_minimal, + WHISK: spec_whisk_minimal, }, MAINNET: { PHASE0: spec_phase0_mainnet, @@ -94,6 +98,7 @@ class ForkMeta: DENEB: spec_deneb_mainnet, EIP6110: spec_eip6110_mainnet, EIP7002: spec_eip7002_mainnet, + WHISK: spec_whisk_mainnet, }, } @@ -434,12 +439,12 @@ def with_all_phases(fn): return with_phases(ALL_PHASES)(fn) -def with_all_phases_from(earliest_phase): +def with_all_phases_from(earliest_phase, all_phases=ALL_PHASES): """ A decorator factory for running a tests with every phase except the ones listed """ def decorator(fn): - return with_phases([phase for phase in ALL_PHASES if is_post_fork(phase, earliest_phase)])(fn) + return with_phases([phase for phase in all_phases if is_post_fork(phase, earliest_phase)])(fn) return decorator @@ -565,6 +570,7 @@ def wrapper(*args, spec: Spec, **kw): with_deneb_and_later = with_all_phases_from(DENEB) with_eip6110_and_later = with_all_phases_from(EIP6110) with_eip7002_and_later = with_all_phases_from(EIP7002) +with_whisk_and_later = with_all_phases_from(WHISK, all_phases=ALLOWED_TEST_RUNNER_FORKS) class quoted_str(str): diff --git a/tests/core/pyspec/eth2spec/test/helpers/block.py b/tests/core/pyspec/eth2spec/test/helpers/block.py index 270bc4be15..84770623e3 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/block.py +++ b/tests/core/pyspec/eth2spec/test/helpers/block.py @@ -1,9 +1,28 @@ from eth2spec.test.helpers.execution_payload import build_empty_execution_payload -from eth2spec.test.helpers.forks import is_post_altair, is_post_bellatrix -from eth2spec.test.helpers.keys import privkeys +from eth2spec.test.helpers.forks import is_post_whisk, is_post_altair, is_post_bellatrix +from eth2spec.test.helpers.keys import privkeys, whisk_ks_initial, whisk_ks_final from eth2spec.utils import bls from eth2spec.utils.bls import only_with_bls from eth2spec.utils.ssz.ssz_impl import hash_tree_root +from curdleproofs import ( + GenerateWhiskTrackerProof, + WhiskTracker, + GenerateWhiskShuffleProof, +) +from py_ecc.optimized_bls12_381.optimized_curve import G1, multiply +from py_ecc.typing import Optimized_Field, Optimized_Point3D +from py_ecc.bls.g2_primitives import ( + G1_to_pubkey as py_ecc_G1_to_bytes48, + pubkey_to_G1 as py_ecc_bytes48_to_G1, +) +from eth2spec.test.helpers.whisk import ( + compute_whisk_tracker_and_commitment, + is_first_proposal, + resolve_known_tracker +) +from py_arkworks_bls12381 import Scalar + +PointProjective = Optimized_Point3D[Optimized_Field] def get_proposer_index_maybe(spec, state, slot, proposer_index=None): @@ -24,10 +43,9 @@ def get_proposer_index_maybe(spec, state, slot, proposer_index=None): @only_with_bls() -def apply_randao_reveal(spec, state, block, proposer_index=None): +def apply_randao_reveal(spec, state, block, proposer_index): assert state.slot <= block.slot - proposer_index = get_proposer_index_maybe(spec, state, block.slot, proposer_index) privkey = privkeys[proposer_index] domain = spec.get_domain(state, spec.DOMAIN_RANDAO, spec.compute_epoch_at_slot(block.slot)) @@ -72,7 +90,7 @@ def apply_empty_block(spec, state, slot=None): return transition_unsigned_block(spec, state, block) -def build_empty_block(spec, state, slot=None): +def build_empty_block(spec, state, slot=None, proposer_index=None): """ Build empty block for ``slot``, built upon the latest block header seen by ``state``. Slot must be greater than or equal to the current slot in ``state``. @@ -87,13 +105,14 @@ def build_empty_block(spec, state, slot=None): spec.process_slots(state, slot) state, parent_block_root = get_state_and_beacon_parent_root_at_slot(spec, state, slot) + proposer_index = get_beacon_proposer_to_build(spec, state, proposer_index) empty_block = spec.BeaconBlock() empty_block.slot = slot - empty_block.proposer_index = spec.get_beacon_proposer_index(state) + empty_block.proposer_index = proposer_index empty_block.body.eth1_data.deposit_count = state.eth1_deposit_index empty_block.parent_root = parent_block_root - apply_randao_reveal(spec, state, empty_block) + apply_randao_reveal(spec, state, empty_block, proposer_index) if is_post_altair(spec): empty_block.body.sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY @@ -101,11 +120,99 @@ def build_empty_block(spec, state, slot=None): if is_post_bellatrix(spec): empty_block.body.execution_payload = build_empty_execution_payload(spec, state) + if is_post_whisk(spec): + # Whisk opening proof + ####### + + # Create valid whisk opening proof + # TODO: Use k_initial or k_final to handle first and subsequent proposals + k_initial = whisk_ks_initial(proposer_index) + + # Sanity check proposer is correct + proposer_k_commitment = state.whisk_k_commitments[proposer_index] + k_commitment = py_ecc_G1_to_bytes48(multiply(G1, int(k_initial))) + if proposer_k_commitment != k_commitment: + raise Exception("k proposer_index not eq proposer_k_commitment", proposer_k_commitment, k_commitment) + + proposer_tracker = state.whisk_proposer_trackers[state.slot % spec.WHISK_PROPOSER_TRACKERS_COUNT] + if not is_whisk_proposer(proposer_tracker, k_initial): + raise Exception("k proposer_index does not match proposer_tracker") + + empty_block.body.whisk_opening_proof = GenerateWhiskTrackerProof(proposer_tracker, Scalar(k_initial)) + + # Whisk shuffle proof + ####### + + shuffle_indices = spec.get_shuffle_indices(empty_block.body.randao_reveal) + pre_shuffle_trackers = [state.whisk_candidate_trackers[i] for i in shuffle_indices] + + post_trackers, shuffle_proof = GenerateWhiskShuffleProof(spec.CURDLEPROOFS_CRS, pre_shuffle_trackers) + empty_block.body.whisk_post_shuffle_trackers = post_trackers + empty_block.body.whisk_shuffle_proof = shuffle_proof + + # Whisk registration proof + ####### + + # Branching logic depending if first proposal or not + if is_first_proposal(spec, state, proposer_index): + # Register new tracker + k_final = whisk_ks_final(proposer_index) + # TODO: Actual logic should pick a random r, but may need to do something fancy to locate trackers quickly + r = 2 + tracker, k_commitment = compute_whisk_tracker_and_commitment(k_final, r) + empty_block.body.whisk_registration_proof = GenerateWhiskTrackerProof(tracker, Scalar(k_final)) + empty_block.body.whisk_tracker = tracker + empty_block.body.whisk_k_commitment = k_commitment + + else: + # Subsequent proposals, just leave empty + empty_block.body.whisk_registration_proof = spec.WhiskTrackerProof() + empty_block.body.whisk_tracker = spec.WhiskTracker() + empty_block.body.whisk_k_commitment = spec.BLSG1Point() + return empty_block -def build_empty_block_for_next_slot(spec, state): - return build_empty_block(spec, state, state.slot + 1) +def is_whisk_proposer(tracker: WhiskTracker, k: int) -> bool: + return py_ecc_G1_to_bytes48(multiply(py_ecc_bytes48_to_G1(tracker.r_G), k)) == tracker.k_r_G + + +def get_beacon_proposer_to_build(spec, state, proposer_index=None): + if is_post_whisk(spec): + if proposer_index is None: + return find_whisk_proposer(spec, state) + else: + return proposer_index + else: + return spec.get_beacon_proposer_index(state) + + +def find_whisk_proposer(spec, state): + proposer_tracker = state.whisk_proposer_trackers[state.slot % spec.WHISK_PROPOSER_TRACKERS_COUNT] + + # Check record of known trackers + # During the first shuffling phase (epoch < WHISK_EPOCHS_PER_SHUFFLING_PHASE) + # proposer trackers are those inserted on the genesis state, and have not gone + # through any shuffling. We cache those initial trackers and use `resolve_known_tracker` + # to check if the tracker is known, and skip the need to actually find the matching tracker + proposer_index = resolve_known_tracker(proposer_tracker) + if proposer_index is not None: + return proposer_index + + print("proposer_tracker", proposer_tracker) + # # First attempt direct equality with trackers + # for i, validator in enumerate(state.validators): + # # # This is insanely slow + # # if validator.whisk_tracker == proposer_tracker: + # if True: + # return i + # # In Whisk where to get proposer from? + # raise Exception("proposer_tracker not matched") + raise Exception("proposer not known without heavy math") + + +def build_empty_block_for_next_slot(spec, state, proposer_index=None): + return build_empty_block(spec, state, state.slot + 1, proposer_index) def get_state_and_beacon_parent_root_at_slot(spec, state, slot): diff --git a/tests/core/pyspec/eth2spec/test/helpers/constants.py b/tests/core/pyspec/eth2spec/test/helpers/constants.py index 82e4f9d0a5..9dcaa65480 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/constants.py +++ b/tests/core/pyspec/eth2spec/test/helpers/constants.py @@ -18,6 +18,7 @@ DAS = SpecForkName('das') EIP6110 = SpecForkName('eip6110') EIP7002 = SpecForkName('eip7002') +WHISK = SpecForkName('whisk') # # SpecFork settings @@ -27,6 +28,8 @@ MAINNET_FORKS = (PHASE0, ALTAIR, BELLATRIX, CAPELLA) LATEST_FORK = MAINNET_FORKS[-1] # The forks that pytest can run with. +# Note: when adding a new fork here, all tests from previous forks with decorator `with_X_and_later` +# will run on the new fork. To skip this behaviour, add the fork to `ALLOWED_TEST_RUNNER_FORKS` ALL_PHASES = ( # Formal forks *MAINNET_FORKS, @@ -38,7 +41,9 @@ # The forks that have light client specs LIGHT_CLIENT_TESTING_FORKS = (*[item for item in MAINNET_FORKS if item != PHASE0], DENEB) # The forks that output to the test vectors. -TESTGEN_FORKS = (*MAINNET_FORKS, DENEB, EIP6110) +TESTGEN_FORKS = (*MAINNET_FORKS, DENEB, EIP6110, WHISK) +# Forks allowed in the test runner `--fork` flag, to fail fast in case of typos +ALLOWED_TEST_RUNNER_FORKS = (*ALL_PHASES, WHISK) ALL_FORK_UPGRADES = { # pre_fork_name: post_fork_name diff --git a/tests/core/pyspec/eth2spec/test/helpers/forks.py b/tests/core/pyspec/eth2spec/test/helpers/forks.py index 492af47fe3..9640f95853 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/forks.py +++ b/tests/core/pyspec/eth2spec/test/helpers/forks.py @@ -1,10 +1,12 @@ from .constants import ( PHASE0, ALTAIR, BELLATRIX, CAPELLA, DENEB, - EIP6110, EIP7002, + EIP6110, EIP7002, WHISK, ) def is_post_fork(a, b): + if a == WHISK: + return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, WHISK] if a == EIP7002: return b in [PHASE0, ALTAIR, BELLATRIX, CAPELLA, EIP7002] if a == EIP6110: @@ -44,3 +46,7 @@ def is_post_eip6110(spec): def is_post_eip7002(spec): return is_post_fork(spec.fork, EIP7002) + + +def is_post_whisk(spec): + return is_post_fork(spec.fork, WHISK) diff --git a/tests/core/pyspec/eth2spec/test/helpers/genesis.py b/tests/core/pyspec/eth2spec/test/helpers/genesis.py index e55bdef5ce..597e7e2ac7 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/genesis.py +++ b/tests/core/pyspec/eth2spec/test/helpers/genesis.py @@ -1,13 +1,14 @@ from eth2spec.test.helpers.constants import ( - ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, + ALTAIR, BELLATRIX, CAPELLA, DENEB, EIP6110, EIP7002, WHISK, ) from eth2spec.test.helpers.execution_payload import ( compute_el_header_block_hash, ) from eth2spec.test.helpers.forks import ( - is_post_altair, is_post_bellatrix, is_post_capella, is_post_eip6110, is_post_eip7002, + is_post_altair, is_post_bellatrix, is_post_capella, is_post_eip6110, is_post_eip7002, is_post_whisk, ) from eth2spec.test.helpers.keys import pubkeys +from eth2spec.test.helpers.whisk import compute_whisk_initial_tracker_cached, compute_whisk_initial_k_commitment_cached def build_mock_validator(spec, i: int, balance: int): @@ -93,6 +94,9 @@ def create_genesis_state(spec, validator_balances, activation_threshold): elif spec.fork == EIP7002: previous_version = spec.config.CAPELLA_FORK_VERSION current_version = spec.config.EIP7002_FORK_VERSION + elif spec.fork == WHISK: + previous_version = spec.config.CAPELLA_FORK_VERSION + current_version = spec.config.WHISK_FORK_VERSION state = spec.BeaconState( genesis_time=0, @@ -145,4 +149,16 @@ def create_genesis_state(spec, validator_balances, activation_threshold): if is_post_eip6110(spec): state.deposit_receipts_start_index = spec.UNSET_DEPOSIT_RECEIPTS_START_INDEX + if is_post_whisk(spec): + vc = len(state.validators) + for i in range(vc): + state.whisk_k_commitments.append(compute_whisk_initial_k_commitment_cached(i)) + state.whisk_trackers.append(compute_whisk_initial_tracker_cached(i)) + + for i in range(spec.WHISK_CANDIDATE_TRACKERS_COUNT): + state.whisk_candidate_trackers[i] = compute_whisk_initial_tracker_cached(i % vc) + + for i in range(spec.WHISK_PROPOSER_TRACKERS_COUNT): + state.whisk_proposer_trackers[i] = compute_whisk_initial_tracker_cached(i % vc) + return state diff --git a/tests/core/pyspec/eth2spec/test/helpers/keys.py b/tests/core/pyspec/eth2spec/test/helpers/keys.py index 5e36e90df6..a849f11320 100644 --- a/tests/core/pyspec/eth2spec/test/helpers/keys.py +++ b/tests/core/pyspec/eth2spec/test/helpers/keys.py @@ -4,3 +4,18 @@ privkeys = [i + 1 for i in range(32 * 256)] pubkeys = [bls.SkToPk(privkey) for privkey in privkeys] pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)} + +known_whisk_trackers = {} + + +def register_known_whisk_tracker(k_r_G: bytes, index: int): + known_whisk_trackers[k_r_G] = index + + +def whisk_ks_initial(i: int): + return i + + +# Must be unique among the set `whisk_ks_initial + whisk_ks_final` +def whisk_ks_final(i: int): + return i + 10000000 diff --git a/tests/core/pyspec/eth2spec/test/helpers/whisk.py b/tests/core/pyspec/eth2spec/test/helpers/whisk.py new file mode 100644 index 0000000000..a92dd267ba --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/helpers/whisk.py @@ -0,0 +1,99 @@ +from typing import Tuple, Optional +from eth_typing import BLSPubkey +from curdleproofs import GenerateWhiskTrackerProof, WhiskTracker +from eth2spec.test.helpers.keys import whisk_ks_initial +from py_arkworks_bls12381 import G1Point, Scalar + + +# Map of validator index to initial WhiskTracker (r = 1, k = index) +whisk_initial_tracker_cache_by_index = {} +# Map of validator index to k commitment (k = index) +whisk_initial_k_commitment_cache_by_index = {} +# Map of k_r_G to validator index +whisk_initial_tracker_cache_by_k_r_G = {} +INITIAL_R = 1 + +# Generator +G1 = G1Point() + + +def compute_whisk_initial_tracker_cached(i: int) -> WhiskTracker: + if i in whisk_initial_tracker_cache_by_index: + return whisk_initial_tracker_cache_by_index[i] + + tracker = compute_whisk_tracker(whisk_ks_initial(i), INITIAL_R) + whisk_initial_tracker_cache_by_index[i] = tracker + whisk_initial_tracker_cache_by_k_r_G[tracker.k_r_G] = i + return tracker + + +def compute_whisk_initial_k_commitment_cached(i: int) -> BLSPubkey: + if i in whisk_initial_k_commitment_cache_by_index: + return whisk_initial_k_commitment_cache_by_index[i] + + commitment = compute_whisk_k_commitment(whisk_ks_initial(i)) + whisk_initial_k_commitment_cache_by_index[i] = commitment + return commitment + + +def resolve_known_tracker(tracker: WhiskTracker) -> Optional[int]: + if tracker.k_r_G in whisk_initial_tracker_cache_by_k_r_G: + return whisk_initial_tracker_cache_by_k_r_G[tracker.k_r_G] + else: + return None + + +def g1point_to_bytes(point: G1Point) -> bytes: + return bytes(point.to_compressed_bytes()) + + +def compute_whisk_k_commitment(k: int) -> BLSPubkey: + return g1point_to_bytes(G1 * Scalar(k)) + + +def compute_whisk_tracker(k: int, r: int) -> WhiskTracker: + r_G = G1 * Scalar(r) + k_r_G = r_G * Scalar(k) + return WhiskTracker(g1point_to_bytes(r_G), g1point_to_bytes(k_r_G)) + + +def compute_whisk_tracker_and_commitment(k: int, r: int) -> Tuple[WhiskTracker, BLSPubkey]: + k_G = G1 * Scalar(k) + r_G = G1 * Scalar(r) + k_r_G = r_G * Scalar(k) + tracker = WhiskTracker(g1point_to_bytes(r_G), g1point_to_bytes(k_r_G)) + commitment = g1point_to_bytes(k_G) + return tracker, commitment + + +# Trigger condition for first proposal +def set_as_first_proposal(spec, state, proposer_index: int): + if state.whisk_trackers[proposer_index].r_G != spec.BLS_G1_GENERATOR: + # Ensure tracker is empty to prevent breaking it + assert state.whisk_trackers[proposer_index].r_G == spec.BLSG1Point() + state.whisk_trackers[proposer_index].r_G = spec.BLS_G1_GENERATOR + + +def is_first_proposal(spec, state, proposer_index: int) -> bool: + return state.whisk_trackers[proposer_index].r_G == spec.BLS_G1_GENERATOR + + +def register_tracker(state, proposer_index: int, k: int, r: int): + tracker, k_commitment = compute_whisk_tracker_and_commitment(k, r) + state.whisk_trackers[proposer_index] = tracker + state.whisk_k_commitments[proposer_index] = k_commitment + + +def set_registration(body, k: int, r: int): + tracker, k_commitment = compute_whisk_tracker_and_commitment(k, r) + body.whisk_registration_proof = GenerateWhiskTrackerProof(tracker, Scalar(k)) + body.whisk_tracker = tracker + body.whisk_k_commitment = k_commitment + + +def set_opening_proof(spec, state, block, proposer_index: int, k: int, r: int): + tracker, k_commitment = compute_whisk_tracker_and_commitment(k, r) + state.whisk_proposer_trackers[state.slot % spec.WHISK_PROPOSER_TRACKERS_COUNT] = tracker + state.whisk_k_commitments[proposer_index] = k_commitment + block.proposer_index = proposer_index + block.body.whisk_opening_proof = GenerateWhiskTrackerProof(tracker, Scalar(k)) diff --git a/tests/core/pyspec/eth2spec/test/whisk/__init__.py b/tests/core/pyspec/eth2spec/test/whisk/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/whisk/block_processing/__init__.py b/tests/core/pyspec/eth2spec/test/whisk/block_processing/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_shuffled_trackers.py b/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_shuffled_trackers.py new file mode 100644 index 0000000000..31665dc228 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_shuffled_trackers.py @@ -0,0 +1,134 @@ +from eth2spec.test.context import spec_state_test, with_whisk_and_later, expect_assertion_error +from eth2spec.test.helpers.keys import whisk_ks_initial +from eth2spec.test.helpers.whisk import compute_whisk_tracker +from curdleproofs import GenerateWhiskShuffleProof + + +def set_correct_shuffle_proofs(spec, state, body): + pre_shuffle_trackers = get_and_populate_pre_shuffle_trackers(spec, state, body) + + post_trackers, shuffle_proof = GenerateWhiskShuffleProof(spec.CURDLEPROOFS_CRS, pre_shuffle_trackers) + body.whisk_post_shuffle_trackers = post_trackers + body.whisk_shuffle_proof = shuffle_proof + + +def get_and_populate_pre_shuffle_trackers(spec, state, body): + shuffle_indices = spec.get_shuffle_indices(body.randao_reveal) + pre_shuffle_trackers = [] + for i in shuffle_indices: + # Set r to some value > 1 ( = 2+i) + tracker = compute_whisk_tracker(whisk_ks_initial(i), 2 + i) + state.whisk_candidate_trackers[i] = tracker + pre_shuffle_trackers.append(tracker) + return pre_shuffle_trackers + + +def get_pre_shuffle_trackers(spec, state, body): + return [state.whisk_candidate_trackers[i] for i in spec.get_shuffle_indices(body.randao_reveal)] + + +def set_state_epoch(spec, state, epoch): + state.slot = epoch * spec.SLOTS_PER_EPOCH + + +def set_state_epoch_selection_gap(spec, state): + set_state_epoch(spec, state, spec.config.WHISK_EPOCHS_PER_SHUFFLING_PHASE - 1) + + +def empty_block_body(spec): + return spec.BeaconBlockBody() + + +def run_process_shuffled_trackers(spec, state, body, valid=True): + yield 'pre', state + yield 'body', body + + if not valid: + expect_assertion_error(lambda: spec.process_shuffled_trackers(state, body)) + yield 'post', None + return + + spec.process_shuffled_trackers(state, body) + + yield 'post', state + + +@with_whisk_and_later +@spec_state_test +def test_shuffle_trackers(spec, state): + body = empty_block_body(spec) + set_correct_shuffle_proofs(spec, state, body) + yield from run_process_shuffled_trackers(spec, state, body) + + +@with_whisk_and_later +@spec_state_test +def test_no_shuffle_minus_selection_gap(spec, state): + body = empty_block_body(spec) + set_state_epoch_selection_gap(spec, state) + yield from run_process_shuffled_trackers(spec, state, body) + + +@with_whisk_and_later +@spec_state_test +def test_no_shuffle_minus_one_and_selection_gap(spec, state): + body = empty_block_body(spec) + set_state_epoch( + spec, + state, + spec.config.WHISK_EPOCHS_PER_SHUFFLING_PHASE - spec.config.WHISK_PROPOSER_SELECTION_GAP - 1 + ) + yield from run_process_shuffled_trackers(spec, state, body) + + +@with_whisk_and_later +@spec_state_test +def test_shuffle_during_selection_gap(spec, state): + body = empty_block_body(spec) + set_correct_shuffle_proofs(spec, state, body) + set_state_epoch_selection_gap(spec, state) + yield from run_process_shuffled_trackers(spec, state, body, valid=False) + +# Invalid cases on shuffle +# - wrong proof +# - wrong post shuffle + + +@with_whisk_and_later +@spec_state_test +def test_invalid_shuffle_bad_proof(spec, state): + body = empty_block_body(spec) + set_correct_shuffle_proofs(spec, state, body) + body.whisk_shuffle_proof = spec.WhiskShuffleProof() + yield from run_process_shuffled_trackers(spec, state, body, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_invalid_shuffle_bad_trackers_zero(spec, state): + body = empty_block_body(spec) + set_correct_shuffle_proofs(spec, state, body) + body.whisk_post_shuffle_trackers[0] = spec.WhiskTracker() + yield from run_process_shuffled_trackers(spec, state, body, valid=False) + +# Invalid cases on gap +# - not empty shuffle trackers +# - not empty proof + + +@with_whisk_and_later +@spec_state_test +def test_invalid_gap_non_zero_proof(spec, state): + body = empty_block_body(spec) + body.whisk_shuffle_proof = spec.WhiskShuffleProof('0xff') + set_state_epoch_selection_gap(spec, state) + yield from run_process_shuffled_trackers(spec, state, body, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_invalid_gap_non_zero_trackers(spec, state): + body = empty_block_body(spec) + body.whisk_post_shuffle_trackers = get_and_populate_pre_shuffle_trackers(spec, state, body) + set_state_epoch_selection_gap(spec, state) + yield from run_process_shuffled_trackers(spec, state, body, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_whisk_opening_proof.py b/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_whisk_opening_proof.py new file mode 100644 index 0000000000..b923a927be --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_whisk_opening_proof.py @@ -0,0 +1,67 @@ +from eth2spec.test.context import spec_state_test, with_whisk_and_later, expect_assertion_error +from eth2spec.test.helpers.whisk import ( + compute_whisk_k_commitment, + compute_whisk_tracker, + set_opening_proof +) + + +def empty_block(spec): + return spec.BeaconBlock() + + +def run_process_whisk_opening_proof(spec, state, block, valid=True): + yield 'pre', state + yield 'block', block + + if not valid: + expect_assertion_error(lambda: spec.process_whisk_opening_proof(state, block)) + yield 'post', None + return + + spec.process_whisk_opening_proof(state, block) + + yield 'post', state + + +PROPOSER_INDEX = 0 +K_OK = 2 +K_WRONG = 3 +R_OK = 2 +R_WRONG = 3 + + +@with_whisk_and_later +@spec_state_test +def test_valid_proof(spec, state): + block = empty_block(spec) + set_opening_proof(spec, state, block, PROPOSER_INDEX, K_OK, R_OK) + run_process_whisk_opening_proof(spec, state, block) + + +@with_whisk_and_later +@spec_state_test +def test_wrong_commitment(spec, state): + block = empty_block(spec) + set_opening_proof(spec, state, block, PROPOSER_INDEX, K_OK, R_OK) + state.whisk_k_commitments[PROPOSER_INDEX] = compute_whisk_k_commitment(K_WRONG) + run_process_whisk_opening_proof(spec, state, block, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_wrong_tracker_r(spec, state): + block = empty_block(spec) + set_opening_proof(spec, state, block, PROPOSER_INDEX, K_OK, R_OK) + wrong_tracker = compute_whisk_tracker(K_OK, R_WRONG) + state.whisk_proposer_trackers[state.slot % spec.WHISK_PROPOSER_TRACKERS_COUNT] = wrong_tracker + run_process_whisk_opening_proof(spec, state, block, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_wrong_proof(spec, state): + block = empty_block(spec) + set_opening_proof(spec, state, block, PROPOSER_INDEX, K_OK, R_OK) + block.body.whisk_opening_proof = spec.WhiskTrackerProof() + run_process_whisk_opening_proof(spec, state, block, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_whisk_registration.py b/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_whisk_registration.py new file mode 100644 index 0000000000..e7aa6c6cb6 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/whisk/block_processing/test_process_whisk_registration.py @@ -0,0 +1,108 @@ +from eth2spec.test.context import spec_state_test, with_whisk_and_later, expect_assertion_error +from eth2spec.test.helpers.whisk import ( + set_as_first_proposal, + compute_whisk_k_commitment, + set_registration, + register_tracker +) + + +def empty_block_body(spec): + return spec.BeaconBlockBody() + + +def set_as_first_proposal_and_proposer(spec, state, proposer_index): + state.latest_block_header.proposer_index = proposer_index + set_as_first_proposal(spec, state, proposer_index) + + +def run_process_whisk_registration(spec, state, body, valid=True): + yield 'pre', state + yield 'body', body + + if not valid: + expect_assertion_error(lambda: spec.process_whisk_registration(state, body)) + yield 'post', None + return + + spec.process_whisk_registration(state, body) + + yield 'post', state + + +IDENTITY_R = 1 +OTHER_R = 100_000_2 # Large enough values to not collide with initial k values +OTHER_K = 100_000_2 +PROPOSER_INDEX = 0 +OTHER_INDEX = 1 + +# First proposal + + +@with_whisk_and_later +@spec_state_test +def test_first_proposal_ok(spec, state): + body = empty_block_body(spec) + set_as_first_proposal_and_proposer(spec, state, PROPOSER_INDEX) + set_registration(body, OTHER_K, OTHER_R) + yield from run_process_whisk_registration(spec, state, body) + + +@with_whisk_and_later +@spec_state_test +def test_first_proposal_indentity_tracker(spec, state): + body = empty_block_body(spec) + set_as_first_proposal_and_proposer(spec, state, PROPOSER_INDEX) + set_registration(body, OTHER_K, IDENTITY_R) + yield from run_process_whisk_registration(spec, state, body, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_first_proposal_non_unique_k_other(spec, state): + body = empty_block_body(spec) + set_as_first_proposal_and_proposer(spec, state, PROPOSER_INDEX) + state.whisk_k_commitments[OTHER_INDEX] = compute_whisk_k_commitment(OTHER_K) + set_registration(body, OTHER_K, OTHER_R) + yield from run_process_whisk_registration(spec, state, body, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_first_proposal_non_unique_k_self(spec, state): + body = empty_block_body(spec) + set_as_first_proposal_and_proposer(spec, state, PROPOSER_INDEX) + state.whisk_k_commitments[PROPOSER_INDEX] = compute_whisk_k_commitment(OTHER_K) + set_registration(body, OTHER_K, OTHER_R) + yield from run_process_whisk_registration(spec, state, body, valid=False) + + +@with_whisk_and_later +@spec_state_test +def test_first_proposal_invalid_proof(spec, state): + body = empty_block_body(spec) + set_as_first_proposal_and_proposer(spec, state, PROPOSER_INDEX) + set_registration(body, OTHER_K, OTHER_R) + body.whisk_tracker.k_r_G = spec.BLSG1Point() + yield from run_process_whisk_registration(spec, state, body, valid=False) + +# Second proposal + + +@with_whisk_and_later +@spec_state_test +def test_second_proposal_ok(spec, state): + body = empty_block_body(spec) + # An empty body has the correct values for a second proposal + # Set tracker to != G1 generator for second proposal condition + register_tracker(state, PROPOSER_INDEX, OTHER_K, OTHER_R) + yield from run_process_whisk_registration(spec, state, body) + + +@with_whisk_and_later +@spec_state_test +def test_second_proposal_not_zero(spec, state): + body = empty_block_body(spec) + set_registration(body, OTHER_K, OTHER_R) + register_tracker(state, PROPOSER_INDEX, OTHER_K, OTHER_R) + yield from run_process_whisk_registration(spec, state, body, valid=False) diff --git a/tests/core/pyspec/eth2spec/test/whisk/sanity/__init__.py b/tests/core/pyspec/eth2spec/test/whisk/sanity/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/pyspec/eth2spec/test/whisk/sanity/blocks/__init__.py b/tests/core/pyspec/eth2spec/test/whisk/sanity/blocks/__init__.py new file mode 100644 index 0000000000..818aa2cf91 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/whisk/sanity/blocks/__init__.py @@ -0,0 +1 @@ +from .test_whisk import * # noqa: F401 F403 diff --git a/tests/core/pyspec/eth2spec/test/whisk/sanity/blocks/test_whisk.py b/tests/core/pyspec/eth2spec/test/whisk/sanity/blocks/test_whisk.py new file mode 100644 index 0000000000..152eccbf34 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/whisk/sanity/blocks/test_whisk.py @@ -0,0 +1,51 @@ +from eth2spec.test.helpers.block import build_empty_block +from eth2spec.test.context import spec_state_test, with_whisk_and_later +from eth2spec.test.helpers.keys import whisk_ks_initial +from eth2spec.test.helpers.state import state_transition_and_sign_block +from eth2spec.test.helpers.whisk import compute_whisk_tracker_and_commitment +from curdleproofs import WhiskTracker + +known_whisk_trackers = {} + + +def assign_proposer_at_slot(state, slot: int): + state + + +def initialize_whisk_full(spec, state): + # TODO: De-duplicate code from whisk/fork.md + for index in range(len(state.validators)): + whisk_k_commitment, whisk_tracker = spec.get_initial_commitments(whisk_ks_initial(index)) + state.whisk_k_commitments[index] = whisk_k_commitment + state.whisk_trackers[index] = whisk_tracker + + # Do a candidate selection followed by a proposer selection so that we have proposers for the upcoming day + # Use an old epoch when selecting candidates so that we don't get the same seed as in the next candidate selection + spec.select_whisk_candidate_trackers(state, spec.Epoch(0)) + spec.select_whisk_proposer_trackers(state, spec.Epoch(0)) + + +# Fill candidate trackers with the same tracker so shuffling does not break +def fill_candidate_trackers(spec, state, tracker: WhiskTracker): + for i in range(spec.WHISK_CANDIDATE_TRACKERS_COUNT): + state.whisk_candidate_trackers[i] = tracker + + +@with_whisk_and_later +@spec_state_test +def test_whisk__process_block_single_initial(spec, state): + assert state.slot == 0 + proposer_slot_1 = 0 + tracker_slot_1, k_commitment = compute_whisk_tracker_and_commitment(whisk_ks_initial(proposer_slot_1), 1) + state.whisk_k_commitments[proposer_slot_1] = k_commitment + state.whisk_proposer_trackers[1] = tracker_slot_1 + fill_candidate_trackers(spec, state, tracker_slot_1) + + # Produce and process a whisk block + yield 'pre', state + + block = build_empty_block(spec, state, 1, proposer_slot_1) + signed_block = state_transition_and_sign_block(spec, state, block) + + yield 'blocks', [signed_block] + yield 'post', state diff --git a/tests/core/pyspec/eth2spec/test/whisk/unittests/test_config_invariants.py b/tests/core/pyspec/eth2spec/test/whisk/unittests/test_config_invariants.py new file mode 100644 index 0000000000..f48b7099c7 --- /dev/null +++ b/tests/core/pyspec/eth2spec/test/whisk/unittests/test_config_invariants.py @@ -0,0 +1,17 @@ +from eth2spec.test.context import spec_test, with_whisk_and_later +from eth2spec.test.context import single_phase + + +# Note: remove once whisk is rebased on top of deneb +def is_power_of_two(value: int) -> bool: + """ + Check if ``value`` is a power of two integer. + """ + return (value > 0) and (value & (value - 1) == 0) + + +@with_whisk_and_later +@spec_test +@single_phase +def test_curdleproof(spec): + assert is_power_of_two(spec.CURDLEPROOFS_N_BLINDERS + spec.WHISK_VALIDATORS_PER_SHUFFLE)